Callback and Controls Rendering (Manual Partial Page Rendering)

Callback and Controls Rendering (Manual Partial Page Rendering)

In my previous article, I wrote about Callback and JSON-based JavaScript serialization.

Why Should I Read this Article?

Callback doesn't cause postback and page rendering, either full nor even partial. You can communicate with the server (IIS) and your server side code runs there successfully. You could rebind your controls, such as Dropdownlist, Gridview, Listview, Datalist, Repeater, or any server-side control to which you assign data. However, the problem is when the page won't render, its controls won't render; if controls won't render, changes won't reflect. When changes won't reflect, there won't be anything at the front end to show on the web page.

This article is mainly about the Callback and Rendering controls, but through this tutorial you also can learn many other things, such as a brief introduction of Postback, Rendering, creating server-side controls dynamically, and creating a Datatable dynamically in memory. Binding with server-side controls means getting server-side control at the client side and setting their properties and registering a client-side event of a server-side control from/through server-side code.

First of all, I would like to brief you on some terms that I believe every web developer should be aware of.

Postback

Postback is a mechanism of communication between the client side (browser) and the server side (IIS). Through postback, all contents of the page/form(s) are sent to the server from the client for processing. After following the page life cycle, all server-side contents get rendered into client-side code and the client (browser) displays those contents. Callback is another way of communication between the server and client. Callback doesn't follow the page life cycle that followed standard postback and doesn't even cause Rendering.

Rendering

Rendering is the process of converting server-side code/contents into client-side code/content so the client (browser) can understand that code and display the output. The browser can understand or, you may say, decode the code of client-side languages and scripts such as HTML, DHTML, XHTML, JavaScript, Vbscript, and others.

If rendering won't happen, the changes won't reflect; this happens on the server at the client side. Ajax leverages partial postback automatically, whereas callback doesn't cause it, so a programmer needs to perform that task manually.

The ASP.NET team has created a RenderControl method with each control. By using that control, you can render your control very easily.

CALLBACK

CALLBACK is a lightweight process. It uses the well-known xmlhttp object internally to call a server-side method. It doesn't cause page postback, so it doesn't cause page rendering. To show output at the client side, you need to make the output HTML yourself and render the controls manually.

ICALLBACKEVENTHANDLER

ICALLBACK is implemented in ASP.NET by using the ICALLBACKEVENTHANDLER interface. This interface has two methods; one of them is used to call from JavaScript (client-side code), and the other one returns results asynchronously back to the JavaScript function.

You just need to perform some action through server-side code at the server side; it needs to return results but the results could be an instance or object of any class that could be not easy for JavaScript code to handle easily. Here, I prefer JSON, which stands for JavaScript Object Notation.

Callback and Controls Rendering (Manual Partial Page Rendering)

Real-Time Scenario with Implementation

Suppose you have categories, subcategories, and products data; you need to populate these categories and subcategories that depend upon categories data to be populated in two different drop-down lists. For the products data, you want to use a multicolumn format and you need to show that data in tabular format. I would prefer using the Gridview control.

The situation would be to load/populate categories on Page_Load and load/populate subcategories on the basis of the selected category using callback. Finally, you would load products into Gridview on the basis of the selected subcategory.

Before starting coding, I would like to write pseudo code for better understanding.

Pseudo Code

  1. Create Server side controls; for example, Dropdownlists and Gridview.
  2. Load Categories on Page load.
  3. Implement the ICallbackEventHandler interface.
  4. Create subcategories data in server memory to bind to the Subcategory drop-down list.
  5. Render control (subcategory dropdownlist) and show output.
  6. Create products data in server memory to bind to the Products gridview.
  7. Render Control (products gridview) and return rendered contents to the client side to show.
  8. Set innerHTML of each control by rendered contents.

CREATE CONTROLS (DROP-DOWN LISTS, GRIDVIEW)

Categories:

<asp:DropDownList ID="ddlCategories" runat="server" Width="100"
                  onchange="CallSrv(this);">
   </asp:DropDownList>

Subcategories:

<div id="ddlSubcategories">
</div>

Products:

<div id="grvProducts">
</div>

Callback and Controls Rendering (Manual Partial Page Rendering)

CALLBACK SERVER-SIDE CODE

Implement ICALLBACKEVENTHANDLER to call a server-side method asynchronously step by step.

Implement Server Side (C#) Page/Control class by
   System.Web.UI.ICallbackEventHandler

Following are the definitions of two methods that need to be implemented:

RaiseCallbackEvent method invoke by javascript function
public void RaiseCallbackEvent(string eventArgument)
{

   //split eventArgument parameter to get command name and then
   //value to perform operation
   //like if command is by Category then we need to load sub
   //categories and if command is by subcateogry
   //then we need to load products
   string[] commands = eventArgument.Split(",".ToCharArray());

   //check command
   if (commands[0].Equals("LoadSubCategory"))
   {
      //create sub category control dynamically
      DropDownList ddlSubcategories = new DropDownList();
      switch (commands[1])
      {
         //populate sub category data on the basis of
         //category
         case "Autos":
            ddlSubcategories.Items.Add("Cars");
            ddlSubcategories.Items.Add("Bikes");
            break;
         case "Electronics":
            ddlSubcategories.Items.Add("Computers");
            ddlSubcategories.Items.Add("TV");
            break;
      }

      //set client side event
      ddlSubcategories.Attributes.Add("onchange",
                                      "CallSrv(this);");

      //primarily rendered output would come in string
      //builder (sb) object
      //through stringwriter which would get data from
      //htmltextwriter which would get data from RenderControl method
      System.Text.StringBuilder sb = new System.Text.StringBuilder();
      System.IO.StringWriter sw = new System.IO.StringWriter(sb);
      HtmlTextWriter htw = new HtmlTextWriter(sw);

      //render sub categories dropdownlist
      ddlSubcategories.RenderControl(htw);

      //set prefix command name so at client side we could know
      //which control to load actually and
      //set rendered string
      this.RenderedOutput = "LoadSubCategory," + sb.ToString();
   }
   //check command
   else if (commands[0].Equals("LoadProducts"))
   {
      //create data table in memory and populate that wid
      //sample/example data to show on webpage
      DataTable dtProducts = new DataTable();
      //create columns of data table
      dtProducts.Columns.Add("ProductName");
      dtProducts.Columns.Add("ProductDescription");
      dtProducts.Columns.Add("ProductPrice");
      //declare row to fill up with data
      DataRow drProduct;
      switch (commands[1])
      {
         //create data in memory (datatable) to populate in gridview
         case "Cars":
            drProduct = dtProducts.NewRow();
            drProduct["ProductName"] = "Honda";
            drProduct["ProductDescription"] = "2000 CC";
            drProduct["ProductPrice"] = "$1000";
            dtProducts.Rows.Add(drProduct);
            drProduct = dtProducts.NewRow();
            drProduct["ProductName"] = "Toyota";
            drProduct["ProductDescription"] = "1800 CC";
            drProduct["ProductPrice"] = "$800";
            dtProducts.Rows.Add(drProduct);
            break;
         case "Bikes":
            drProduct = dtProducts.NewRow();
            drProduct["ProductName"] = "Pak Hero";
            drProduct["ProductDescription"] = "125 CC";
            drProduct["ProductPrice"] = "$100";
            dtProducts.Rows.Add(drProduct);
            drProduct = dtProducts.NewRow();
            drProduct["ProductName"] = "Honda";
            drProduct["ProductDescription"] = "250 CC";
            drProduct["ProductPrice"] = "$150";
            dtProducts.Rows.Add(drProduct);
            break;
         case "Computers":
            drProduct = dtProducts.NewRow();
            drProduct["ProductName"] = "Dell";
            drProduct["ProductDescription"] = "P4 Centrino";
            drProduct["ProductPrice"] = "$400";
            dtProducts.Rows.Add(drProduct);
            drProduct = dtProducts.NewRow();
            drProduct["ProductName"] = "IBM";
            drProduct["ProductDescription"] = "P4 Think PAD";
            drProduct["ProductPrice"] = "$350";
            dtProducts.Rows.Add(drProduct);
            break;
         case "TV":
            drProduct = dtProducts.NewRow();
            drProduct["ProductName"] = "Sony";
            drProduct["ProductDescription"] = "Plasma";
            drProduct["ProductPrice"] = "$600";
            dtProducts.Rows.Add(drProduct);
            drProduct = dtProducts.NewRow();
            drProduct["ProductName"] = "Philips";
            drProduct["ProductDescription"] = "Projection";
            drProduct["ProductPrice"] = "$550";
            dtProducts.Rows.Add(drProduct);
            break;
      }
      //create gridview to bind with created datable to show output
      GridView grvProducts = new GridView();
      grvProducts.DataSource = dtProducts;
      grvProducts.DataBind();

      //primarily rendered output would come in string builder
      //(sb) object
      //through stringwriter which would get data from htmltextwriter
      //which would get data from RenderControl method
      System.Text.StringBuilder sb = new System.Text.StringBuilder();
      System.IO.StringWriter sw = new System.IO.StringWriter(sb);
      HtmlTextWriter htw = new HtmlTextWriter(sw);

      //render sub categories dropdownlist
      grvProducts.RenderControl(htw);

      //set prefix command name so at client side we could know
      //which control to load actually and
      //set rendered string
      this.RenderedOutput = "LoadProducts," + sb.ToString();
   }
   }
   /// <summary>
   /// Execute/Fires when RaiseCallbackEvent code runs completely
   /// </summary>
   /// <returns></returns>
   public string GetCallbackResult() 
   {
      //return rendered string with command name
      return RenderedOutput;
   }

In Page_Load or Page_Init event

The following statements are used to register client-side methods. CallServer(arg, context), as the name implies, would use the call/raise server-side method that was the RaiseCallbackEvent string eventArgument. ReceiveServerData(arg, context) would use the get result through the arg parameter by GetCallbackResult().

//Register Client Script for Callback and populate categories
protected void Page_Load(object sender, EventArgs e)
{
ClientScriptManager scriptMgr = Page.ClientScript;
String cbReference = scriptMgr.GetCallbackEventReference(this,
   "arg", "ReceiveServerData", "");
String callbackScript = "function CallServer(arg, context)
   {" + cbReference + "; }";
cm.RegisterClientScriptBlock(this.GetType(),"CallServer",
   callbackScript, true);

if (!Page.IsPostBack)
   {
      //Load Products Data
      this.ddlCategories.Items.Add("Select");
      this.ddlCategories.Items.Add("Autos");
      this.ddlCategories.Items.Add("Electronics");
   }
}

Callback and Controls Rendering (Manual Partial Page Rendering)

<script language="javascript" type="text/javascript">
//Runs when GetCallbackResult() executes and return result through
//arg param
function ReceiveServerData(arg, context)
{
//split command and contents (rendered data)
   var cmd_content = arg.split(',');
   //check command
   if (cmd_content[0] == 'LoadSubCategory')
   {
      //set rendered contents to sub category div to show
      //subcategories according to categories
      document.getElementById('ddlSubcategories').innerHTML =
        cmd_content[1];
   }
   else
   {
   //set rendered contents to products div to show products
   //according to categories and sub categories
    document.getElementById('grvProducts').innerHTML =
      cmd_content[1];
   }

}

//invoke by categories/subcategories dropdownlist to communicate
//with server for processing
function CallSrv(ddl)
{
   //check command and determine either this method invoked by
   //Categories Dropdownlist or by Subcategories Dropdownlist
   if (ddl.id == 'ddlCategories')
   {
      if(ddl.value != 'Select')
      {
         //Set command and value to load data accordingly and call
         //server side method RaiseCallbackEvent
          CallServer('LoadSubCategory' + ',' + ddl.value, '');
      }
   }
   else
   
      //Set command and value to load data accordingly and call
      //server side method RaiseCallbackEvent

          CallServer('LoadProducts' + ',' + ddl.value, '');
   }

}
</script>

That's it. These are the steps you need to use to call and get results from server-side code by using ICALLBACK. Asynchronous output would occur within a millisecond and without Postback.

Conclusion

Callback is a lightweight technique used to call server-side methods asynchronously from JavaScript without any postback and reloading/rendering of unnecessary parts of the page or unnecessary code. So, you can use that when you need to perform any operation at the back end—such as update records in a database. You don't need to send all the content of pages in a request and make that object heavyweight, which could cause slow performance.



About the Author

Muhammad Adnan Amanullah

.Net Evangelist http://weblogs.asp.net/MuhammadAdnan http://realfantasy.wordpress.com http://interviewquestion.wordpress.com

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

  • On-Demand Webcast APIs can be a great source of competitive advantage. The practice of exposing backend services as APIs has become pervasive, however their use varies widely across companies and industries. Some companies leverage APIs to create internal, operational and development efficiencies, while others use them to drive ancillary revenue channels. Many companies successfully support both public and private programs from the same API by varying levels of access to different constituents. Nearly all …

Most Popular Programming Stories

More for Developers

RSS Feeds