Our Code
  • Per Lundberg (gravatar)

    In this posting, I’ll give an introduction to how you can use the new features provided by ASP.NET AJAX to call methods in web services from your own JavaScript code with very little fuss. (Well, at least that’s the idea…)

    First, I want to take some steps backward and describe the history, the steps that led to the advent of ASP.NET AJAX. JavaScript has historically been a client-only language, providing some client-side events that can be used to e.g. perform certain events every time the user hovers the mouse over a certain part of the web page, or every time an HTML <button> is clicked. All of this is taking place on the client computer only, in the web browser. There is no interaction between the JavaScript code and the server providing the web page on which the JavaScript code is hosted.

    As the web applications started to be more and more advanced, the need for more interaction arose. The gap between the client and the server needed to be eradicated, somehow. The solution - or bridge, if you like - is named XMLHttpRequest. This is the very foundation that all of AJAX (including ASP.NET AJAX) relies upon.

    XMLHttpRequest is a mechanism through which a web browser (Firefox, Internet Explorer, Safari, etc.) can make a request to the server without refreshing the whole page. The request is made by client-side script, in other words, JavaScript (as much as we love it or hate it…). The initial implementation of the XMLHttpRequest was made by Microsoft as a wrapper on top of the MSXML, using ActiveX (so it was not a “pure” JavaScript functionality at that time; rather JScript). Later on, other browser vendors followed along, modeling their implementation after the Microsoft one, and eventually the XMLHttpRequest was standardized by the W3C. [1]

    So, what good does this XMLHttpRequest API do? Well, as previously mentioned, it enables client-side code (JavaScript) running in the web browser to make server-side requests for certain information, without the need for a full page reload. This makes all forms of interesting interactive web sites (or rather, web applications is a more descriptive term) possible. For example, you could have a page fetch live news from a newsfeed server, and display it on a web server, without the need for any refreshing of the page. You could have a form where the user enters a monetary value and chooses the source/target currencies, and presses a “Convert” button. The value is then converted between the given currencies, with no need for any 1990’s-style page refreshing. :-)

    In the Microsoft ASP.NET world, ASP.NET AJAX was introduced between the release of ASP.NET 3.0 and 3.5 (a pre-release named Atlas was available slightly earlier). ASP.NET 3.5 (Visual Studio 2008) has ASP.NET AJAX support out-of-the-box.

    (In the ASP.NET AJAX nomenclature, Microsoft talks about this “avoiding full page refresh” thing as partial page updates. I’ll use this phrase for the rest of this article.)

    ASP.NET AJAX can be used in two modes: “ASP.NET mode” and “JavaScript mode”. In ASP.NET mode, what you do is basically more or less embed the controls that you want to use partial-page updates for in an <asp:UpdatePanel/> control. That way, ASP.NET AJAX will “seamlessly” handle the page updates, and tunnel them through the AJAX (XMLHttpRequest) pipe. Very convenient and easy to use for the developer, but not always optimal from a performance and technical point of view. I did a simple test when writing this blog article. The source code to my test page looks like this:

    <%@ Page Language="C#" AutoEventWireup="true" %>
    
    <script type="text/C#" runat="server">
    
        protected void Button_Click(object sender, EventArgs e)
        {
            Label.Text = "Moo!";
        }
        
    </script>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <asp:ScriptManager EnablePartialRendering="true" runat="server" />
        <asp:UpdatePanel ID="UpdatePanel" runat="server">
            <ContentTemplate>
                <asp:Button ID="Button" runat="server"
                            Text="Click Me!"
                            OnClick="Button_Click" />
                <asp:Label ID="Label" runat="server" />
            </ContentTemplate>
        </asp:UpdatePanel>
        </form>
    </body>
    </html>

    In other words, quite a simple page. The idea is that you click a button, and the button makes the text for a certain control be changed to “Moo!”. Since this is embedded in an UpdatePanel, this is supposed to take place using partial-page rendering techniques. The page looks like this when rendered:

     "Click Me" web page

    Now, let’s inspect what it looks like in Fiddler when the “Click Me!” button is clicked. This is what we get:

    Fiddler output of the UpdatePanel request

    The amount of overhead is immense; not speaking byte-wise, but percentage-wise. What we wanted to do is to fetch the “Moo!” text and place it in a control. This is a four byte string (if we’re talking ASCII and not UCS-2…) + maybe a trailing CR+LF or something like that. Let’s be nice and say that 10 bytes for this update would be reasonable.

    Instead, we got 571 characters being sent over the wire. That’s an incredible 5700% of the “reasonable size” being used for the request!

    Now, in reality, this is much less of a problem than I’m making it appear to be… Computers are fast nowadays, and broadband connections are common. Still, that old 640 KiB geek in me screams when I see something like this… :-) And of course, in this example, it might not be a problem, but who’re saying it wouldn’t be in a more complicated use case? What if you have more controls on the page, more viewstate to persist (which could be disabled altogether, btw.) and so forth? This can actually turn out to be a performance killer.

    The reason for this extraneous information being transferred is this: The UpdatePanel control is built in a generic way. If you look closely at my screenshot (click on it to see the full picture), you see that what is transferred is the full HTML for the content of the UpdatePanel control. This makes it simple to implement (in the UpdatePanel control itself), and also has some other advantages, but is sometimes very much less than optimal, and can also make the page give a more sluggish feeling than necessary.

    In our specific example, what we could have done instead is to just get the updated Text field and set the innerHTML property of the Label to this value. This should provide a much more optimized experience. :-) By using the client-side ASP.NET AJAX functionality, this is actually quite simple! I’ll go ahead and add a webservice to my web project, called “LabelWebService.asmx”. The .asmx file is left unmodified, and the code-behind file is modified to look like this:

    using System.Web.Script.Services;
    using System.Web.Services;
    
    namespace eCraft.AjaxWithUpdatePanel
    {
        /// <summary>
        /// Simple webservice for fetching the text for a label on a web page.
        /// </summary>
        [WebService(Namespace = "http://labs.ecraft.com/Samples/CallingWebServicesFromJavascript/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [ScriptService]
        public class LabelWebService : WebService
        {
            [WebMethod]
            public string GetText()
            {
                return "Moo!";
            }
        }
    }

    In other words, a very simple proof-of-concept web service that just returns a dummy value. Note the special attribute ScriptService on this class (from the System.Web.Script.Services namespace). What this attribute does is enable JavaScript proxy generation for your web service, enabling the service to be called from JavaScript embedded in an ASP.NET page. We might go through how this works behind the scenes some other time; for now, just accept the fact that it somehow magically creates a JavaScript wrapper class that lets you call your web service from JavaScript.

    So, let’s skip the talk and go straight on to the code, shall we? This is the modified test page, now with some embedded code for calling the web service through JavaScript:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="eCraft.AjaxWithUpdatePanel.Default" %>
    
    <script type="text/javascript">
           
        function Button_Click()
        {
            var ws = new eCraft.AjaxWithUpdatePanel.LabelWebService;
            ws.GetText(GetText_Succeeded);        
        }
    
        function GetText_Succeeded(result)
        {
            var label = $get('<%= Label.ClientID %>');
            label.innerHTML = result;
        }
        
    </script>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title></title>
    </head>
    <body>
        <form id="form2" runat="server">
        <asp:ScriptManager ID="ScriptManager1"
            EnablePartialRendering="true" runat="server">
        <Services>
            <asp:ServiceReference Path="~/LabelWebService.asmx" />
        </Services>
        </asp:ScriptManager>
            
        <asp:Button ID="Button" runat="server" Text="Click Me!"
            OnClientClick="Button_Click(); return false;" />
        <asp:Label ID="Label" runat="server" />
        </form>
    </body>
    </html>

    As you see, the page has been slightly changed from before. Maybe one of the most important changes that has taken place is that we skipped the <asp:UpdatePanel/> control altogether, but kept the <asp:ScriptManager/> one. We also added an <asp:ServiceReference/> control. This is what makes the page aware of the web service that we are about to call, and it helps the JavaScript intellisense to recognize the proxy class representing our web service.

    We have also introduced two new JavaScript functions: Button_Click() and GetText_Succeeded(). The <asp:Button/> control have also been modified to perform an OnClientClick rather than an OnClick event. (The “return false” part is important, since we would otherwise get a full page postback – that’s the default behavior of the <input type=”button”> element, which is what the Button control gets rendered as.)

    In the Button_Click() function, we create an instance of our web service wrapper class. The cool thing about this is that if you remove the code inside that function, and start typing “var ws = new e“, you should get something like this:

    Calling web services from JavaScript - intellisense screenshot

    The eCraft.AjaxWithUpdatePanel.LabelWebService class is apparently known to Visual Studio, helping us a lot. You can now use code-completion to write the full class name, just like you could for C# code. This is a good enhancement that Microsoft has done to the JavaScript language, making it more convenient to work with (even though I’m really looking forward to a possible successor to the JavaScript language altogether… The language is too “weak” and dynamic in my taste.)

    If you look at my Button_Click code again, something noteworthy is that the web service call is done slightly different than it would be done in C#. Instead of just calling the web service and getting back the result as a return value from the method, we are setting up a callback that will get called once the web service method is finished. This is a clear difference from traditional web service client code. This shows the asynchronous nature of the AJAX technology (after all, that’s what the A in AJAX stands for…). All web service calls are asynchronous when being used from JavaScript like this, and asynchronous service calls usually use callbacks to call a user-supplied method/function when the call has finished.

    The disadvantage of this is that your code can become harder to read; it is less obvious what the flow looks like. The advantage is that you can make multiple server requests at once, and in a load-balancing scenario, there could even be multiple physical servers to serve your different requests, increasing performance. It is also a good preparation for starting to work with service calls in Silverlight, which always uses asynchronous calls (at least when calling WCF services, but I guess the same goes for traditional web services as well).

    Finally, let’s look at the Fiddler output for my modified version of the program. You’ll be amazed (we hope :-). This is what it looks like:

    Fiddler output of the JavaScript web service request

    Whoha! What’s that? It clearly looks very different to before, and also extremely optimized.

    The reason why the content here looks very differently is that we’re now making a web service call rather than getting HTML data for updating the UpdatePanel. But also, it doesn’t look like the SOAP stuff that you could expect to get back from a normal web service call. This is because it uses the JSON format for serializing the data. JSON is a highly optimized format for serializing data over e.g. HTTP connections, and it is the default when using the ScriptService attribute like we’re doing here. (It usually works well, but it might not be suitable for all web service calls, perhaps especially if the data you are returning is of XML format. If necessary, you can always change to “raw XML”  as the response format. See this external blog posting for more details on that.)

    Regarding the performance, we can see that the 571 bytes from the UpdatePanel sample has now shrank to a whopping 12 bytes. Quite an improvement (97,9% actually…). With the risk of being repetitive; in this case, it might not have mattered that much, but you should be able to clearly see the potential that this method has over standard <asp:UpdatePanel/> usage. The performance is simply outstanding. The cost you have to take is that you have to write client code to update the contents of the HTML controls. Sometimes, this can be a bit of work, but it can be simplified a bit. (instead of e.g. creating an HTML table with rows and cells, you could create it from beforehand and just use style=”display: none” to hide the cells. This makes it easy to un-hide them through JavaScript; hopefully simpler or better than inserting a bunch of new nodes in the DOM tree…)

    Alright, time to close up this blog posting. In this posting, we have gone through the basics behind how AJAX works. We have also done some field testing of ASP.NET AJAX performance, first using UpdatePanel and later on using direct web service calls from JavaScript. We saw the clear performance advantage with JavaScript calling a web service vis-a-vis using the UpdatePanel, but can also understand that the UpdatePanel is often a better (or at least “simpler to implement”) choice, especially if you have a lot of code and controls in the existing implementation that you simply want to AJAXify. The UpdatePanel also makes the code slightly simpler to read and understand, since it “looks” more like traditional ASP.NET code (but this might actually be a disadvantage, since it works differently under the hood – abstraction can be good, but it can also fool you at times).

    Anyway, we now know the alternatives, so we can wisely consider them both in real-world scenarios, and use whichever one is more suitable in each specific case. Remember that system architecture is no “one size fits all” business.

    See you in my future posts; until then, take care.

    • Robin Lauren (15.1.10 15:17)

      Your intentions are good but your reasoning is flaky. As long as a return packet is under 1.5 kB, it doesn't really matter how small it is since it's still going to fit inside one TCP/IP pcket.

      I'm not a C# coder so i can't comment on the code purity issues, but i much appreciate the cleaner return value of "just the facts, mam".

    • per.lundberg@ecraft.com (22.1.10 10:40)

      Thanks for the comment, Robin. You're right (even though you're expressing yourself slightly incorrectly - it's the ethernet frame size, not the TCP/IP packet, that is normally limited to 1,5 kbytes - 1514 bytes including 14 bytes or so worth of header). But then again, TCP/IP packets are normally delivered in ethernet frames, so my 20 KiB TCP/IP packet is likely to be split by the TCP/IP layer in my Windows Vista into suitable ethernet frames anyway, so in practice what you say is true, even it's theoretically incorrect. ;-)

      Anyway, in my example both messages will be delivered in 1 ethernet frame, so the difference is 0% in terms of packets being sent over the wire. Still, the overhead has to be processed by the target TCP/IP layer and so forth.

      In real-world scenarios though, my reasoning might be more correct (even though the 97,9% performance increase is unlikely to remain :-) ). It would be interesting to see some figures of more complex scenarios of UpdatePanel vs "raw" Javascript. I think usually people who make more complex stuff usually prefer the UpdatePanel approach though, since it makes the solution more homogeneous (all the code in simple C# code-behind files rather than some parts in Javascript files hidden away somewhere...).

    • Tim Viney (26.3.10 00:24)

      I love this, great blog, thanks.

      I'm developing an on going asp.net app that is growing arms and legs. One major page has about 10 user controls each in it's own update panel. There is a heck of alot of text in gridviews and datalists all over the page, so as you can imagine it can be a tad slugish. I'm working on a part where I need to check that a corisponding file exists on the server when a user clicks a checkbox in a large datalist. To do this check in an update panel and wate for the big roundtrip would be unexceptable I think, but could be just the ticket for my scenario I think :)

      Thanks, very usefull.

    Leave a reply

    Name (required)
    Website