ASP.NET Posts

  • 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.

  • Per&#32;Lundberg (gravatar)

    Yesterday, when I was debugging a problem on an application of ours, the behavior of the application was very illogical – at least, that’s how it seemed. This is what I was doing: If a local variable (in the code-behind class for the page) was non-null, some logic where to be triggered. And this logic did not work correctly. Eventually, I simplified the program (by hardwiring stuff) to the point where it should really work. But, as you probably have figured out, it didn’t…

    Then, the answer was revealed to me; a new thought popped into my mind. The ViewState! Yes, most assuredly, this was the cause of the problem. When I set the EnableViewState=false on my control, it started working correctly again. Hallelujah! :-)

    So, what is this whole ViewState thing and why was it causing problems in my specific case?

    ViewState: The end-user experience

    You can say, without exaggerating too much, that ViewState is one of the core elements of ASP.NET. The key idea is this: imagine an .aspx file that looks like this:

    <%@ Page Language="C#" AutoEventWireup="true" %>
    
    <script runat="server">
        
        /// <summary>
        /// Gets called when the Button1 is clicked.
        /// </summary>
        /// <param name="sender">the sender of the event</param>
        /// <param name="e">the event arguments</param>
        protected void Button1_Click(object sender, EventArgs e)
        {
            Label1.Text = "Button1 has been clicked!";
        }
    
        /// <summary>
        /// Gets called when the Button2 is clicked.
        /// </summary>
        /// <param name="sender">the sender of the event</param>
        /// <param name="e">the event arguments</param>
        protected void Button2_Click(object sender, EventArgs e)
        {
            Label1.Text += " Button2 has been clicked!";
        }
        
    </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">
        <div>
            <p>
                <asp:Label runat="server" ID="Label1" />
            </p>
            <asp:Button runat="server" ID="Button1" 
                        OnClick="Button1_Click"
                        Text="Button1" />
            <asp:Button runat="server" ID="Button2"
                        OnClick="Button2_Click"
                        Text="Button2" />
        </div>
        </form>
    </body>
    </html>

    (Of course, this example is fictionary; I do not recommend that you place your event handlers in the .aspx file but rather in the code-behind. :-)

    This page contains two buttons: Button1 and Button2. When rendered, it looks like this:

    Screenshot #1

    Now, if we click on the Button1, it looks like this:

     Screenshot #1

    No rocket-science yet. :-) The logic for this page can clearly be understood, without knowing how ASP.NET works “under the hood”. The button was clicked, the event was fired, and the event handler set the text of the Label1 control to “Button1 has been clicked!”. All of this happened before the page was actually rendered to the web browser.

    But now, let’s click on Button2 and see what we get:

    Screenshot #2

    Hey, that’s weird, isn’t it? In the Button2_Click() event handler, we only added the “Button2 has been clicked” text, but the “Button1 has been clicked” text still remains anyway…?

    This is where ASP.NET deviates from “regular” web programming (think: PHP, CGI, JSP…). Now, if you have only ever used ASP.NET (and never any other web-based programming environment), you might feel like this is the most natural thing in the world. It has to work like this, doesn’t it?

    Well… no. Not at all, in fact.

    ViewState: The background

    Traditionally, before the advent of ASP.NET, if you would want the state of an object (such as the content of a <span> tag) to persist across page requests, you would have to invent this yourself (There might be frameworks that can help in doing this). The default would be that all object state would “fall off” the page if the user would e.g. press F5 in the web browser.

    Now, what our friends at Microsoft has been doing is trying to bridge the gap between normal applications (i.e. Windows Forms or similar) and web applications a little. The request/response model traditionally used on the web can be a bit unfriendly to a newcomer. The ASP.NET solution to this challenge is called ViewState.

    ViewState: What is is

    So, what is this ViewState thing now that I’ve been writing about for a while? Simply put, ViewState is a functionality that lets the state of objects persist between different page requests. What you saw above, with the “Button1/2 has been clicked” texts, is a simple example of this persistence. Another simple visual example of the ViewState functionality would be to let the Button1 handler modify the background color of the page. When clicking the Button2, the modified color would still remain.

    A couple of simple rules regarding ViewState:

    • All object state gets persisted in the ViewState, for public properties (This can be seen as the general rule; there might be exceptions to it).
    • ViewState is only preserved for “server controls”; that is, any tags with the runat=”server” attribute set.
    • ViewState is enabled by default in ASP.NET. It can be disabled:
      • on control-level, by setting EnableViewState=”false”. On HTML-controls, like a regular div with runat=”server”, the attribute is called enableviewstate instead.
      • on page-level, by setting the EnableViewState=”false” attribute on the <%@ Page %> tag.
      • on application level, like this (in the Web.config):
        <system.web>
          <pages enableViewState="false"/>
        </system.web>

    Technically, the ViewState is sent in a hidden form field called __VIEWSTATE, as a string of base64-encoded text. If you like, try viewing the source of the previously listed sample page, after having clicked the Button1, and you’ll see that it contains some human-unreadable data. This data contains the “Button1 has been clicked!" text.

    Now when we have seen some of the “whys” and the “hows” for the ViewState persistence, let’s get into the even more interesting question about the problems that ViewState can cause you. I promised you at the beginning of this blog posting that it can mess up your life; you will soon see how. :-)

    ViewState: When it can cause you headaches

    As seen above, I have listed some of the advantages of preserving ViewState; it bridges the gap (slightly) between regular (Windows Forms/WPF) applications and the web. It makes the programming models more homogeneous, making it simpler for people who work with them both.

    Still, there are also some disadvantages of this technique. One of the disadvantages is that for a large page, the view state can be pretty big, meaning that quite a lot of data will be transferred over the wire on every page hit. Even though this might not be too big a problem, it can still feel meaningless to have this data being transferred when it’s not really needed (for some applications).

    Another disadvantage which was the driving reason for writing this blog entry in the first place is that the view state persistence can cause really difficult, hard-to-track bugs. The code sample below illustrates one such scenario:

    <%@ Page Language="C#" AutoEventWireup="true" %>
    
    <script runat="server">
        
        // Dummy child class. In my real-world example, the class
        // has some custom behavior that justifies its existence.
        public class DropDownListCustom: DropDownList
        {
        }
        
        /// <summary>
        /// Gets called right before the page is rendered.
        /// </summary>
        /// <param name="sender">the sender of the event</param>
        /// <param name="eventArgs">the event arguments</param>
        protected void Page_PreRender(object sender, EventArgs eventArgs)
        {
            // Creates a new DropDownListCustom object with some
            // items.
            DropDownList dropDownList1 = new DropDownListCustom();
            dropDownList1.ID = "DropDownList1";
            dropDownList1.Items.Add("Item 1");
            dropDownList1.Items.Add("Item 2");
            dropDownList1.Items.Add("Item 3");
    
            if (IsPostBack)
            {
                string formValue = Request.Form["DropDownList1"];
    
                // Display the previously selected value + form
                // value so we can clearly see if the assignment
                // to the SelectedValue has any effect.
                Label1.Text = "Was selected: " + dropDownList1.SelectedValue;
                Label2.Text = "Will be selected: " + formValue;
                dropDownList1.SelectedValue = formValue;
            }
            
            div1.Controls.Add(dropDownList1);
        }
        
    </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">    
        <div><asp:Label ID="Label1" runat="server" /></div>
        <div><asp:Label ID="Label2" runat="server" /></div>
        <div runat="server" id="div1"/>      
        <asp:Button runat="server" ID="Button1" Text="Button1" />
        </form>
    </body>
    </html>

    When viewing this page, it looks like this:

    Screenshot #3

    When selecting a different item and clicking Button1, this is what you get:

    image

    As you see, the page is not working correctly. We selected Item 2, and it was correctly passed to the page in the Form variables, but somehow, the assignment to the SelectedValue (the highlighted line in the sample code) had no effect whatsoever.

    This sample page has some important characteristics that should be pointed out:

    1. It uses a custom DropDownList-derived class (When you change the “new DropDownListCustom” initialization to “new DropDownList”, the program works as intended, which leads me to believe that there is something special that a child-class of a System.Web.UI.WebControls class needs to do to make ViewState work correctly).
    2. It uses dynamic control creation. This is from the real-world scenario; what we do is generate the controls depending on some input data. The number of controls generated is dependent on the input data, which means that hardwiring it in the .aspx file is impossible.
    3. The initialization is only done when performing a postback (not on the initial page load). When thinking about it, this initialization shouldn’t even be necessary; the ViewState + postback handling in ASP.NET “should” be clever enough to set the default value of the DropDownList automatically. That’s how it usually work, isn’t it? But try commenting out the assignment to dropDownList1.SelectedValue and you’ll see that it makes absolutely no difference.

    Now, there are two ways to solve this:

    • Disable ViewState on the DropDownListCustom control. If the DropDownListCustom control is always (or most of the time) used in scenarios like this, you can create a constructor that sets the default value of the base.EnableViewState property to false (this is what I did). You can always reenable it for those controls that need it.
    • Move the div1.Controls.Add to line 24 in the sample (right before the “if (isPostback)”-line). This also makes it work.

    The reason why this fails is this: When adding controls dynamically, like we’re doing here, the loading of the persisted ViewState of the control being added takes place at a different stage in the ASP.NET Page Life-cycle than it would normally have taken… This, in combination with some bug/behavior when childclassing the DropDownList causes this behavior.

    One lesson learned here for me personally is that maybe ViewState shouldn’t be the default when I work on a new project. As mentioned earlier in the posting, the possibility is there to disable it in the Web.config. I don’t know if you can still re-enable it on individual pages (where it would be needed); if that’s the case, this might the optimal way to go. Then again, ViewState is extremely convenient sometimes. The bug I was fixing yesterday was actually caused by the ViewState stopping working some time ago (when introducing the DropDownListCustom). Before that, the ole’ ViewState buddy had silently been doing its job, without anybody complaining. This should be remembered when we start talking about his disadvantages. :-)

    Further reading

    Understanding ASP.NET View State: http://msdn.microsoft.com/en-us/library/ms972976.aspx
    ASP.NET Page Life Cycle Overview: http://msdn.microsoft.com/en-us/library/ms178472.aspx