ASP.NET: Remote Scripting, Yes! AJAX, "NOT!"
by Peter A. Bromberg, Ph.D.

Peter Bromberg

"Everything that is really great and inspiring is created by the individual who can labor in freedom." -- Albert Einstein

Remote Scripting has been used by classic ASP developers since the earliest days of Internet Explorer 3.0 when Microsoft put out their Remote Scripting applet and sample source code. In fact, the first major commercial implementation of Remote Scripting that I know of was Outlook Web Access, really at the time a quite remarkable and full-featured offering created by the MS Exchange programming team.

In a nutshell, Remote Scripting is an infrastructure that allows a remote request to be made from a page based on client-side events, a remote method invoked, and the results returned to the page and usually populated into the DOM with client-side script, and there is no page reload or postback. Google's "Suggest" uses this, as does Gmail and a number of other commercial offerings.

Recently there has been a marketing bonanza opened up primarily by Garrett of Adaptive Path and others, claiming this to be some fantastic new technology that will revolutionize the web (or something along those lines). Don't be fooled. It's just Remote Scripting with no particularly noteworthy improvements, and somebody (as usual) has simply hijacked it and given it a new "buzzword acronym" in order to sell more seminars, books and whatever other rubbish they think they can make money from.



What really has happened to fire this AJAX "repackaged evangelism" is that the Mozilla / Firefox people finally got religion and realized they needed to put in the equivalent of the XMLHTTP request object that has been in Microsoft's browsers since ancient history. Only, theirs is stunted- MSXML XMLHTTP can make a request to a resource on a different domain, and the Firefox implementation can not. (Sounds kinda like Natasha saying "Boris, you got PLAN?" -- while shooting him in the foot!).

In ASP.NET 2.0, we don't even need to bother with this infrastructure because Script Callbacks are built in! However, with a little effort, it's trivial to implement this in ASP.NET 1.1.

There are a number of ".NET-ified" implementations of remote scripting that tie together the JSRS tecnique popularized by Brent Ashley some years back, with the server-side compiled architecture of the .NET platform. My favorite, both for its simplicity and elegance, is Jonathan Cogley's "Thycotic Remote Scripting".

What I have done here is to use Jonathan's classes combined with the SQLite database engine and SQLite.NET provider to show an example of how you could have a Remote Scripting page where a user enters their Zip Code and when they tab out of the zip code textbox to continue filling out the web page form, their City and State are automatically entered for them in the following textbox, without any page reload. I also provide the complete US ZipCode database in SQLite 3.0 format, which has zip, city, state, longitude, latitude and county for every zipcode in the United States, and takes up only 2627 KB on the disk, as opposed to the identical content in SQL Server taking up well in excess of 12 MB for the MDF file alone. I use the Finisar SQLite.NET ADO provider. Throughput on lookups is fast and reliable.

I was reminded by my expert reviewer to mention that JSRS-based remote scripting is indeed "Cross Browser", since it uses only Javascript. Yes, Horace! Remote Scripting is cross browser, and there is a Santa Claus.

Try out the sample page which provides examples with both GET and POST here.

Once you get an understanding of the Remote Scripting architecture, which you can get from Brent Ashley's page, it becomes relatively easy to start coming up with even more ambitious implementations of this concept. If you look at Brent's Links page, you will see a link to an article I wrote here, back in 2001, about using cookies with Remote Scripting. JSRS does not rely on XMLHTTP, instead using a hidden IFRAME or similar construct as a container for the returned data. I should hasten to add, for example, that there is nothing to stop you from having your Remote Scripting call return an entire DataSet in its native XML format, installing this as an XML Data Island in your client-side web page, and going to town with it. Also, I should mention based on some comments below, that Cogley's msrs.js latest file (not used here) does include the use of the cross-browser XMLHTTPRequest object, not "just IFRAMES".

Regarding ASP.NET 2.0, there is already adequate documentation on how to use the built-in script callback interface, so that is not what this is about. Suffice to say that it works pretty much the same.

Here's how we make a remote script call from the client and handle it on the server:

<SCRIPT LANGUAGE="JAVASCRIPT" SRC="msrsclient.js"></SCRIPT>
  <SCRIPT language="javascript">
   var aspObject;
      var serverURL = "../MyServerSidePage.aspx";
      
   function GetCityState() {
  RSExecute(serverURL,"CityStateLookup",document.myForm.stringInput.value,cb,
cbError,"Getting City and State."); } function cb(co) { //alert("Callback fired."); if (co.return_value) { document.myForm.stringOutput.value = co.return_value; } } function cbError(co) { //alert("Error callback fired."); if (co.message) { alert("Context:" + co.context + "\nError: " + co.message); } } </SCRIPT> </HEAD> <body MS_POSITIONING="FlowLayout"> <form id="myForm" name="myForm"> <P> <br> <b>Return City, state from zipcode</b></P> <P> zipcode&nbsp; <input type="text" name="stringInput" id="stringInput" value="94901"
onblur="GetCityState();"><br> Result: <input type="text" name="stringOutput" id="stringOutput" style="WIDTH: 248px; HEIGHT: 22px" size="36"> </P> <P>Enter a Zip code and TAB out of the zipcode texbox to see results. <br> <br> <br> </P> </form> </body>

And, on the server:

[RemoteScriptingMethod(Description="Gets city and state from zip code.")]
  public string[] CityStateLookup(string zipcode)
  {
   string city=String.Empty;
   string state = String.Empty;
   string dbloc=Server.MapPath("zipcodes.db");
   
SQLiteConnection cn = new SQLiteConnection(@"Data Source="+dbloc +";UTF8Encoding=True;Version=3");

   SQLiteCommand cmd = 
new SQLiteCommand("Select CITY, STATE FROM ZIPCODES WHERE ZIP='"+zipcode+"'",cn); cn.Open(); SQLiteDataReader rdr= cmd.ExecuteReader(); rdr.Read(); try { city=rdr["city"].ToString(); state =rdr["state"].ToString(); } catch(Exception ex) { } rdr.Close(); cn.Close(); cmd.Dispose(); string[] result ={city, state}; return result; }

But wait, there's more! A couple of days after posting the original of this article, we got a forum post asking how to create a system that would pop up a "notification window" telling a user that they have some sort of message. With Remote Scripting, this is a piece of cake. We simply add a "Notifications" table to our database, containing ID (primary key), Notification (the message to deliver to the user), NotificationDate, UserId, and a bit column called "Active".

Our script call from any page would then need to look like this:

<SCRIPT language="JAVASCRIPT" src="msrsclient.js"></SCRIPT>
  <SCRIPT language="javascript">
  
    var userid='<%=Session["userid"].ToString() %>';   
  window.setTimeout("CheckNotification()",5000);  
   var aspObject;
      var serverURL = "../MyServerSidePage.aspx";    
        msrsPOST = true; // use POST instead of GET
   function CheckNotification() {  
  RSExecute(serverURL,"GetNotification",userid,cb,cbError,"Getting Notification.");
   window.setTimeout("CheckNotification()",5000);
   }   
   function cb(co) {  
  if (co.return_value) {
   //document.myForm.stringOutput.value = co.return_value;
   if(co.return_value!="")  
    openWindowAndWrite(co.return_value);
  }
   }
   
   function cbError(co) {  
  if (co.message) {
   alert("Context:" + co.context + "\nError: " + co.message);
  }
   }
   
function openWindowAndWrite(strText) {
winBS='toolbar=no,location=no,directories=no,menubar=no,';
winBS+='scrollbars=yes,width=300,height=300';
winBS+=',left=10,top=25';
holyCow=window.open("","",winBS); 
holyCow.document.open(); 

holyCow.document.write (strText);
var updatemsg="<BR/><a href='ClearNotification.aspx?userid=
<%= Session["userid"].ToString() %>'
>Clear Notification</a>"; holyCow.document.write(updatemsg); holyCow.document.close(); holyCow.focus() ; } </SCRIPT>"

Note that the checkNotification callback looks to see if it has a message from the JSRS call to the GetNotification method on the server page. If it does, it pops up a window that has a link to another server page that simply updates the table setting the "Active" bit column to zero, so it doesn't come up again. The getNotification method just does a SQL Select FROM Notifications where USERID=<whatever id>, and returns an empty string if there is no result. Easy! When my sample page comes up, it also has a link to another page that comes up in a separate browser window and allows you to add a new notification record to the table to "activate" the test.

There's complete code for all of this as well as the Notifications table inside the Zipcodes database in the download. Just make a folder "C:\Inetpub\wwwroot\SampleRemoteScriptingWeb" and make it an IIS Application, unzip the download below right into it, and you should be able to load the VS.NET 2003 solution and run it right "out of the box". Note that my online sample in the orange link above does NOT include this Notification Popup demo, that's only available in the downloadable solution below.

I bet you can come up with a whole bunch of cool things to do with this concept. Not to "grind my axe" too hard, since I've already made my point above, but you'll notice that at no time have I referred to any of this by any other name but "Remote Scripting". You can call it AJAX; you can call it HAMBURGER if that really turns you on and you think it will elevate your stature in the seminar circuit and make you more money. Whatever you call it, however, it shall remain "Remote Scripting", because that is what it is. If you are interested in working with Script Callbacks in ASP.NET 2.0 in a strongly - typed manner the "right way" instead of what I call the "BS AJAX clone" way, see Bertrand Leroy's blog and his gotdotnet workspace for the RefreshPanel infrastructure.

Download the Visual Studio.NET Solution (including SQLite Zipcode Database) that accompanies this article

 

 


Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.
Article Discussion: