Click here to Skip to main content
15,867,308 members
Articles / Web Development / HTML

Remote Scripting in ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.22/5 (10 votes)
28 Aug 2013CPOL9 min read 60.8K   733   37   7
A remote scripting system performs remote server function calls from the browser level. This allows to save the time necessary to completely resend and build a page due to a query working somewhere in the background and supplying small amounts of data at a time.

This article is written by Marcin Kawalerowicz and was originally published in the September 2005 issue of the Software Developer's Journal. You can find more articles at the SDJ website.

Introduction

Imagine a sophisticated website: a fancy navigation system, menu, footer, language selection, logo, tabs... The page weighs a whole lot as it is and, on top of that, we have to reload the contents of the one and only drop-down list from our database. What does that mean to our ASP.NET application? First, a query sent to the server, then the processing and sending of the response to the browser, where the time-consuming page rendering process will take place. Up to several tens of seconds (!) to only to reload the values of a single drop-down list? It does not have to be that way because this is where Remote Scripting, which is basically a way of remote procedure calling on a server, comes in.

Remote Scripting is not the first idea that came up to minimize the undesired effects of time consuming page reloading. Apart from techniques which encapsulate parts of a site in autonomic frames, it is a common practice to buffer information necessary for future updates of various DHTML elements. The data is being sent to the browser right in the source code of the page. Necessary information can be saved in invisible form elements or simply in the dynamically generated JavaScript code. After such an operation, the data can undergo any manipulation by means of the DOM technique. However, this approach works only for a relatively small amount of data. What can one do in order to synchronies the actions of several drop-down lists? The amount of data necessary to be kept in such a cache rises exponentially with each additional drop-down list, and will soon overcome all acceptable thresholds. Let us, for instance, imagine a system of three drop-down lists containing, respectively, the make of the car, its type, and model. Let us assume that we have five makes, each has about thirty types, and each type has been assigned the same number of models. It can be easily calculated that there will be a hundred and fifty types and about a thousand models. Sending this data could still be considered acceptable but let us imagine that our database contains one hundred and fifty makes instead of just five.

Different kinds of Remote Scripting systems can be used in an attempt to solve this difficult situation. They can perform remote server function calls from the browser level. This allows to save the time necessary to completely resend and build a page due to a query working somewhere in the background and supplying small amounts of data at a time. Microsoft has presented the first technology of this kind by releasing the free Remote Scripting system – MSRS.

Although the system was capable of synchronous and asynchronous operation, it never gained much popularity among non-corporate users. This is due to the fact that it forces users to use a Java applet, is compatible only with the Windows platform, and is incompatible with most browsers. Naturally, MSRS also requires IIS to be running on the server side.

The interesting fact is that Brent Ashley came to the programmer's to rescue by publishing a fairly decent JSRS library system, which is compatible with many browsers. On the client side, it uses JavaScript, and works only in asynchronous mode. Through the years, several server side library implementations have been created, including those for CGI, ASP, servlets, PHP, etc. A JSRS version, together with a library working in ASP.NET, has been presented by Alvaro Mendez. The library cooperates with both JSRS and MSRS (this one as well – it halts all browser actions until a response from the server is obtained). First, we will try it out by writing a simple calculator, and then by solving the aforementioned automobile problem.

Installation

Equipping your ASP.NET site with the functionality allowing it to remotely invoke methods on the server from the browser's JavaScript level is very simple. Let us copy the AMS.Web.RemoteScripting.dll library to the bin folder of our Internet application (or set the proper file reference in Visual Studio). In the Page_Load method of the site, which contains the definition of the method that we are going to remotely call, type:

C#
if (AMS.Web.RemoteScripting.InvokeMethod(Page))
  return;

The server is ready to accept queries. Let us prepare the client by declaring the usage of the rs.js file as follows:

HTML
<script language="'JavaScript'" src='rs.js'></script>

This is all that needs to be done from the “administrative” point of view. Now we have to program the methods.

Simple training

Our goal is to create a simple calculator on a web site. It will be able to perform one of four basic arithmetical operations on two given numbers. The calculations will be carried out on the server side. Let us prepare a page, such as the one in the example in Listing 1.

Listing 1. Page code for a simple calculator

HTML
<FORM ID="Form1" METHOD="post" RUNAT="server">
   <INPUT id="p1" type="text" size="10">
     <SELECT id="operation">
        <OPTION selected value="add">+</OPTION>
        <OPTION value="sub">-</OPTION>
        <OPTION value="mul">*</OPTION>
        <OPTION value="div">/</OPTION>
     </SELECT>
     <INPUT id="p2" type="text" size="10">
     <INPUT id="b" type="button" value="=" onclick="MakeOperation()">
     <DIV id="result"></DIV>
</FORM>

Clicking the [=] button calls the MakeOperation() JavaScript function. Let us program it in accordance to Listing 2. The function calls the Execute method of the RS class (the definition of this class can be found in the rs.js file). The parameters are the address of the ASP.NET page containing the method prepared to be remotely called, the method's name, any number of parameters in the form of a character string (in this case these will be three parameters signifying the type of the arithmetical operation, the first and the second variable). The next parameter is the name of the JavaScript function meant to process the results (in this case, this function will save the result of the math operation in a DIV layer named result). The last parameter is the name of a JavaScript function, which should be called in the event of an error (it overloads a standard library function, therefore defining it is optional).

Listing 2. The calculator's JavaScript function

JavaScript
function MakeOperation()
{
   RS.Execute(
      "Calculator.aspx",
      "MakeOperation",
      document.Form1.operation.options[
           document.Form1.operation.selectedIndex
      ].value,
      document.Form1.p1.value,
      document.Form1.p2.value,
      SetResult,
      ErrorCallback);
}
 
function SetResult(res)
{
   result.innerHTML = res;
}
 
function ErrorCallback(res)
{
   alert("Error: "+res);
}

Programming the method on the server comes down to defining the MakeOperation() method in the Calculator.aspx.cs file in accordance with Listing 3 (if you do not use code-behind then naturally, you will define this method right in your page code). It should be remembered that, even though MakeOperation() formally returns a double precision floating point number, the result will be converted to a character string before it will be sent back to the client. This rule is true for all methods prepared to be remotely called. In addition, it is also worth remembering that the returned result must be scalar and it is impossible to use reference variables as parameters.

Listing 3. The calculator

C#
public double MakeOperation(
   string operation,
   string p1,
   string p2) 
{
   double d1 = Convert.ToDouble(p1);
   double d2 = Convert.ToDouble(p2);
   double output = 0;
   switch(operation) 
   {
      case "add":
         output = d1 + d2;
         break;
      case "sub":
         output = d1 - d2;
         break;
      case "div":
         output = d1 / d2;
         break;
      case "mul":
         output = d1 * d2;
         break;
   }
   return output;
}

The automobile riddle

Let us now attempt to solve the problem of the three drop-down lists presented at the beginning of the article. We want to create the dream car for ourselves. First, we will choose the make, then the type of the car, and finally decide on the model. In the classical solution, each decision requires the entire page to be reloaded. We will use Remote Scripting to download only the data that we really need. Let us prepare the aspx page as shown in Listing 4.

Listing 4. Dream Car Configuration

HTML
<%@ Page language="c#" Codebehind="Cars.aspx.cs" 
       AutoEventWireup="false" Inherits="JSRS.Cars" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
   <head>
      <title>RS Cars</title>
      <script language="javascript" src="scripts/rs.js"></script>
      <script language="JavaScript">
function LoadModel()
{
   RS.Execute("Cars.aspx",
      "GetModel",
      document.Form1.ddlMake.value,
      RS.ReplaceOptions2,
      document.Form1.ddlModel);
      dcument.Form1.ddlType.options.length = 0;
   }
 
function LoadType()
{
   RS.Execute("Cars.aspx",
      "GetType",
      document.Form1.ddlModel.value,
      RS.ReplaceOptions2,
      document.Form1.ddlType);
}
      </script>
   </head>
   <body>
   <form id="Form1" method="post" runat="server">
      <asp:dropdownlist id="ddlMake" runat="server">
         </asp:dropdownlist><br>
      <asp:dropdownlist id="ddlModel" runat="server">
         </asp:dropdownlist><br>
      <asp:DropDownList id="ddlType" runat="server">
            </asp:DropDownList><br>
      <asp:Button id="btnCheck" runat="server" 
            Text="Check" Width="96px"></asp:Button><br>
      <asp:Label id="lblMake" runat="server">
         Make ID:</asp:Label><br>
      <asp:Label id="lblModel" runat="server">
         Model ID:</asp:Label><br>
      <asp:Label id="lblType" runat="server">
         Type ID:</asp:Label>
   </form>
   </body>
</html>

We will use a simple XML file as our database. We can load it into the DataSet container by means of the ReadXml() method, and place everything within our session as shown in Listing 5.

Listing 5. Loading data from an XML file into our session

C#
private DataSet ds
{
   get
   {
      if (Session["ds"] != null)
         return (DataSet)Session["ds"];
      else
      {
         ds = new DataSet();
         ds.ReadXml(MapPath("Cars.xml"));
         Session["ds"] = ds;
         return ds;
      }
   }
   set { Session["ds"] = value; }
}

We will declare the usage of Remote Scripting in the Page_Load of our page according to the description presented in the Installation frame. Since we are using server controls this time, we are required to declare additional OnChange attributes for JavaScript functions.

C#
ddlMake.Attributes.Add("onchange","LoadModel()");
ddlModel.Attributes.Add("onchange","LoadType()");

When the page is first loaded, we tie the Make table, which represents the make of the car, to the first drop-down list.

C#
ddlMake.DataSource = ds.Tables["Make"];
ddlMake.DataTextField = "MakeName";
ddlMake.DataValueField = "MakeID";
ddlMake.DataBind();

The library contains a useful function for processing results: RS.ReplaceOptions2. This method can automatically fill a drop-down list under the condition that the result obtained from the server is a character string having the form:

HTML
<option value='x'>y</option>
<option value='x'>y</option>
<option value='x'>y</option>
...

Let us, therefore, prepare such methods for the Type and Model tables. They will return a list of car types for a given make and a list of models for a given type (Listing 6).

Listing 6. Remote server-side methods

C#
public string GetModel(string MakeID)
{
   string output = "<option value='-1'></option>";
   foreach (DataRow row in
      ds.Tables["Model"].Select("MakeID='" + MakeID + "'"))
      output += "<option value='" + row[0] + "'>" + 
                row[2] + "</option>";
   return output;
}
 
public string GetType(string ModelID) 
{
   string output = "<option value='-1'></option>";
   foreach (DataRow row in
      ds.Tables["Type"].Select("ModelID='" + ModelID + "'"))
      output += "<option value='" + row[0] + 
                "'>" + row[2] + "</option>";
   return output;
}

Unfortunately, drop-down lists populated at the client side lose all their contents as soon as the page is reloaded (that is why one should not place them in the page's ViewState). Therefore, we must set them again each time. To do this, we can use the Request query parameters. The identifier of the chosen model can be found at Request["ddlModel"], whereas Request["ddlType"] contains the chosen type. Listing 7 shows how this can be done.

Listing 7. Repeated loading of list contents

C#
ddlModel.DataSource = new DataView(ds.Tables["Model"], 
                      "MakeID='" + ddlMake.SelectedValue + 
                      "'", null, DataViewRowState.CurrentRows);
ddlModel.DataTextField = "ModelName";
ddlModel.DataValueField = "ModelID";
ddlModel.DataBind();
ddlModel.Items.Insert(0, new ListItem("","-1"));
ddlModel.SelectedValue = Request["ddlModel"];
 
ddlType.DataSource = new DataView(ds.Tables["Type"], 
                     "ModelID='" + ddlModel.SelectedValue + 
                     "'", null, DataViewRowState.CurrentRows);
ddlType.DataTextField = "TypeName";
ddlType.DataValueField = "TypeID";
ddlType.DataBind();
ddlType.Items.Insert(0, new ListItem("","-1"));
ddlType.SelectedValue = Request["ddlType"];

How does this work?

While preparing remote method calls, the client side script opens an invisible container. Most often, it is a floating IFRAME frame or a layer, as in the case of older Netscape versions which do not support it. The contents of this frame can be viewed by setting the this.debug option in the rs.js file to true. Within the container, a form containing necessary data, which is automatically sent to the server by means of the GET or POST methods (dependent on the RS.usePOST parameter), is dynamically created. The RS.maxPoolSize parameter defines the maximum number of containers which can be open at any given time (an error is generated if this number is exceeded). A sample query for our calculator looks as follows:

GET /RSASP/Calculator.aspx?RC=C1&M=MakeOperation&P0=[mul]
                 &P1=[2]&P2=[3]&U=1119008434742 HTTP/1.1

Subsequent parameters signify the protocol (RC), the method to be called on the server (M), and additional parameters (P0 signifies multiplication, P1 and P2 are the variables). The last query parameter (U) is a time stamp used to manage the query pool.

On the server side

By means of reflection, the library finds the required (RemoteScripting.InvokeMethod(Page)) method and calls it with the given parameters. Once the method finishes work, the result is encapsulated in HTML/JS code and sent to the client. A response to the previous query may look as follows:

HTML
<html>
<body onload="p=document.layers?parentLayer:window.parent;
                 p.RS.pool['C1'].setResult(true);">Payload:<br>
<form name="rsForm"><textarea rows="4" cols="80" 
  name="rsPayload">2</textarea></form>
</body>
</html>

This code calls the setResult function we have previously programmed, by means of OnLoad. After this operation, the invisible container is closed.

Summary

Remote Scripting is one of the ways the World Wide Web might follow. This tendency is clearly shown by the Script Callback technology, which will be part of the second version of the .NET Framework. One can only hope that, as this technology becomes more popular, the way people look at web site programming will change. Time will show. In the mean time, the library created by Alvaro Mendez can be used today to speed up the WWW.

Info on the 'Net

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Publisher
Poland Poland
Software Developer's Journal (formerly Software 2.0) is a magazine for professional programmers and developers publishing news from the software world and practical articles presenting very interesting ready programming solutions. To read more

Comments and Discussions

 
GeneralTry AJAX with JSON Pin
Dewey19-Nov-07 20:58
Dewey19-Nov-07 20:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.