HYXT Blog

we produce valuable software for K12.
clock February 4, 2009 19:01 by author Sky Jia (贾超)

ViewState is a very misunderstood animal. I would like to help put an end to the madness by attempting to explain exactly how the ViewState mechanism works, from beginning to end, and from many different use cases, such as declared controls vs. dynamic controls.

There are a lot of great articles out there that try to dispel the myths about ViewState. You might say this is like beating a dead horse (where ViewState is the horse, and the internet is the assailant). But this horse isn't dead, let me tell you. No, he's very much alive and he's stampeding through your living room. We need to beat him down once again. Don't worry, no horses were harmed during the authoring of this article.

It's not that there's no good information out there about ViewState, it's just all of them seem to be lacking something, and that is contributing to the community's overall confusion about ViewState. For example, one of the key features that is important to understand about ViewState is how it tracks dirtiness. Yet, here is a very good, in-depth article on ViewState that doesn't even mention it! Then there's this W3Schools article on ViewState that seems to indicate that posted form values are maintained via ViewState, but that's not true. (Don't believe me? Disable ViewState on that textbox in their example and run it again). And it's the #1 Google Search Result for "ASP.NET ViewState". Here is ASP.NET Documentation on MSDN that describes how Controls maintain state across postbacks. The documentation isn't wrong per say, but it makes a statement that isn't entirely correct:

"If a control uses ViewState for property data instead of a private field, that property automatically will be persisted across round trips to the client."

That seems to imply that anything you shove into the ViewState StateBag will be round-tripped in the client's browser. NOT TRUE! So it's really no wonder there is so much confusion on ViewState. There is no where I've found on the internet that has a 100% complete and accurate explanation of how it works! The best article I have ever found is this one by Scott Mitchell. That one should be required reading. However, it does not explain the relationship of controls and their child controls when it comes to initialization and ViewState Tracking, and it is this point alone that causes a bulk of the mishandlings of ViewState, at least in the experiences I've had.

So the point of this article will be to first give a complete understanding of how ViewState basically functions, from beginning to end, hopefully filling in the holes that many other articles have. After a complete explanation of the entire ViewState process, I will go into some examples of how developers typically misuse ViewState, usually without even realizing it, and how to fix it. I should also preface this with the fact that I wrote this article with ASP.NET 1.x in mind. However, there are very few differences in the ViewState mechanism in ASP.NET 2.0. For one, ControlState is a new type of ViewState in ASP.NET 2.0, but it treated exactly like ViewState, so we can safely ignore it for the purposes of this article.

First let me explain why I think understanding ViewState to it's core is so important:

    MISUNDERSTANDING OF VIEWSTATE WILL LEAD TO...
  1. Leaking sensitive data
  2. ViewState Attacks - aka the Jedi Mind Trick -- *waves hand* that plasma tv is for sale for $1.00
  3. Poor performance - even to the point of NO PERFORMANCE
  4. Poor scalability - how many users can you handle if each is posting 50k of data every request?
  5. Overall poor design
  6. Headache, nausea, dizziness, and irreversible frilling of the eyebrows.
If you develop an ASP.NET Application and you don't take ViewState seriously, this could happen to you:
ViewState Madness!!! Drop your red bull and surrender your cpu cycles. You will be frustrated. Performance is futile!
The ViewState form field. ViewState will add your web app's distinctiveness to it's own. Performance is futile.
I could go on but that is the gist of it. Now lets move on by starting back from the beginning:
    WHAT DOES VIEWSTATE DO?
    This is a list of ViewState's main jobs. Each of these jobs serves a very distinct purpose. Next we'll learn exactly how it fulfills those jobs.
  1. Stores values per control by key name, like a Hashtable
  2. Tracks changes to a ViewState value's initial state
  3. Serializes and Deserializes saved data into a hidden form field on the client
  4. Automatically restores ViewState data on postbacks
Even more important than understanding what it does, is understanding what it does NOT do:
    WHAT DOESN'T VIEWSTATE DO?
  1. Automatically retain state of class variables (private, protected, or public)
  2. Remember any state information across page loads (only postbacks) (that is unless you customize how the data is persisted)
  3. Remove the need to repopulate data on every request
  4. ViewState is not responsible for the population of values that are posted such as by TextBox controls (although it does play an important role)
  5. Make you coffee
While ViewState does have one overall purpose in the ASP.NET Framework, it's four main roles in the page lifecycle are quite distinct from each other. Logically, we can separate them and try to understand them individually. It is often the mishmash of information on ViewState that confuses people. Hopefully this breaks it down into more bite size nuggets. Mmmm... ViewState Nuggets.
ViewState Nuggets

1. VIEWSTATE STORES VALUES
If you've ever used a hashtable, then you've got it. There's no rocket science here. ViewState has an indexer on it that accepts a string as the key and any object as the value. For example: 

ViewState["Key1"] = 123.45M; // store a decimal value
ViewState["Key2"] = "abc"; // store a string
ViewState["Key3"] = DateTime.Now; // store a DateTime

Actually, "ViewState" is just a name. ViewState is a protected property defined on the System.Web.UI.Control class, from which all server controls, user controls, and pages, derive from. The type of the property is System.Web.UI.StateBag. Strictly speaking, the StateBag class has nothing to do with ASP.NET. It happens to be defined in the System.Web assembly, but other than it's dependency on the State Formatter, also defined in System.Web.UI, there's no reason why the StateBag class couldn't live along side ArrayList in the System.Collections namespace. In practice, Server Controls utilize ViewState as the backing store for most, if not all their properties. This is true of almost all Microsoft's built in controls (ie, label, textbox, button). This is important! You must understand this about controls you are using. Read that sentance again. I mean it... here it is a 3rd time: SERVER CONTROLS UTILIZE VIEWSTATE AS THE BACKING STORE FOR MOST, IF NOT ALL THEIR PROPERTIES. Depending on your background, when you think of a traditional property, you might imagine something like this: 

public string Text {
    get { return _text; }
    set { _text = value; }
}

What is important to know here is that this is NOT what most properties on ASP.NET controls look like. Instead, they use the ViewState StateBag, not a private instance variable, as their backing store: 

public string Text {
    get { return (string)ViewState["Text"]; }
    set { ViewState["Text"] = value; }
}

And I can't stress it enough -- this is true of almost ALL PROPERTIES, even STYLES (actually, Styles do it by implementing IStateManager, but essentially they do it the same way). When writing your own controls it would usually be a good idea to follow this pattern, but thought should first be put into what should and shouldn't be allowed to be dynamically changed on postbacks. But I digress -- that's a different subject. It is also important to understand how DEFAULT VALUES are implemented using this technique. When you think of a property that has a default value, in the traditional sense, you might imagine something like the following: 

public class MyClass {
    private string _text = "Default Value!";
 
    public string Text {
        get { return _text; }
        set { _text = value; }
    }
}

The default value is the default because it is what is returned by the property if no one ever sets it. How can we accomplish this when ViewState is being used as the private backing? Like this: 

public string Text {
    get {
        return ViewState["Text"] == null ?
             "Default Value!" :
              (string)ViewState["Text"];
    }
    set { ViewState["Text"] = value; }
}

Like a hashtable, the StateBag will return null as the value behind a key if it simply doesn't contain an entry with that key. So if the value is null, it has not been set, so return the default value, otherwise return whatever the value is. For you die-hards out there -- you may have detected a difference in these two implementations. In the case of ViewState backing, setting the property to NULL will result in resetting the property back to it's default value. With a "regular" property, setting it to null means it will simply be null. Well, that is just one reason why ASP.NET always tends to use String.Empty ("") instead of null. It's also not very important to the built in controls because basically all of their properties that can be null already are null by default. All I can say is keep this in mind if you write your own controls. And finally, as a footnote really, while this property-backing usage of the ViewState StateBag is how the StateBag is typically used, it isn't limited to just that. As a control or page, you can access you're own ViewState StateBag at any time for any reason, not just in a property. It is sometimes useful to do so in order to remember certain pieces of data across postbacks, but that too is another subject.

2. VIEWSTATE TRACKS CHANGES
Have you ever set a property on a control and then somehow felt... dirty? I sure have. In fact, after a twelve-hour day of setting properties in the office, I become so filthy my wife refuses to kiss me unless I'm holding flowers to mask the stench. I swear! Ok so setting properties doesn't really make you dirty. But it does make the entry in the StateBag dirty! The StateBag isn't just a dumb collection of keys and values like a Hashtable (please don't tell Hashtable I said that, he's scarey). In addition to storing values by key name, the StateBag has a TRACKING ability. Tracking is either on, or off. Tracking can be turned on by calling TrackViewState(), but once on, it cannot be turned off. When tracking is ON, and ONLY when tracking is ON, any changes to any of the StateBag's values will cause that item to be marked as "Dirty". StateBag even has a method you can use to detect if an item is dirty, aptly named IsItemDirty(string key). You can also manually cause an item to be considered dirty by calling SetItemDirty(string key). To illustrate, lets assume we have a StateBag that is not currently tracking: 

stateBag.IsItemDirty("key"); // returns false
stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // still returns false
 
stateBag["key"] = "def";
stateBag.IsItemDirty("key"); // STILL returns false
 
stateBag.TrackViewState();
stateBag.IsItemDirty("key"); // yup still returns false
 
stateBag["key"] = "ghi";
stateBag.IsItemDirty("key"); // TRUE!
 
stateBag.SetItemDirty("key", false);
stateBag.IsItemDirty("key"); // FALSE!

Basically, tracking allows the StateBag to keep track of which of it's values have been changed since TrackViewState() has been called. Values that are assigned before tracking is enabled are not tracked (StateBag turns a blind eye). It is important to know that any assignment will mark the item as dirty -- even if the value given matches the value it already has!

stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // returns false
stateBag.TrackViewState();
stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // returns true

ViewState could have been written to compare the new and old values before deciding if the item should be dirty. But recall that ViewState allows any object to be the value, so you aren't talking about a simple string comparison, and the object doesn't have to implement IComparable so you're not talking about a simple CompareTo either. Alas, because serialization and deserialization will be occuring, an instance you put into ViewState won't be the same instance any longer after a postback. That kind of comparison is not important for ViewState to do it's job, so it doesn't. So that's tracking in a nutshell.

But you might wonder why StateBag would need this ability in the first place. Why on earth would anyone need to know only changes since TrackViewState() is called? Why wouldn't they just utilize the entire collection of items? This one point seems to be at the core of all the confusion on ViewState. I have interviewed many professionals, sometimes with years and years of ASP.NET experience logged in their resumes, who have failed miserably to prove to me that they understand this point. Actually, I have never interviewed a single candidate who has! First, to truly understand why Tracking is needed, you will need to understand a little bit about how ASP.NET sets up declarative controls. Declarative controls are controls that are defined in your ASPX or ASCX form. Here: 

<asp:Label id="lbl1" runat="server" Text="Hello World" />

I do declare that this label is declared on your form. The next thing we need to make sure you understand is ASP.NET's ability to wire up declared attributes to control properties. When ASP.NET parses the form, and finds a tag with runat=server, it creates an instance of the specified control. The variable name it assigns the instance to is based on the ID you assigned it (by the way, many don't realize that you don't have to give a control an ID at all, ASP.NET will use an automatically generated ID. Not specifying an ID has advantages, but that is a different subject). But that's not all it does. The control's tag may contain a bunch of attributes on it. In our label example up above, we have a "Text" attribute, and it's value is "Hello World". Using reflection, ASP.NET is able to detect whether the control has property by that name, and if so, sets its value to the declared value. Obviously the attribute is declared as a string (hey, its stored in a text file after all), so if the property it maps to isn't of type string, it must figure out how to convert the given string into the correct type, before calling the property setter. How it does that my friend is also an entirely different topic (it involves TypeConverters and static Parse methods). Suffice it to say it figures it out, and calls the property setter with the converted value.

Recall that all-important statement from the first role of the StateBag. Here it is again: Server Controls utilize ViewState as the backing store for most, if not all their properties. That means when you declare an attribute on a server control, that value is usually ultimately stored as an entry in that control's ViewState StateBag. Now recall how tracking works. Remember that if the StateBag is "tracking", then setting a value to it will mark that item as dirty. If it isn't tracking, it won't be marked dirty. So the question is -- when ASP.NET calls the SET on the PROPERTY that corresponds to the ATTRIBUTE that is DECLARED on the control, is the StateBag TRACKING or isn't it? The answer is no it is not tracking, because tracking doesn't begin until someone calls TrackViewState() on the StateBag, and ASP.NET does that during the OnInit phase of the page/control lifecycle. This little trick ASP.NET uses to populate properties allows it to easily detect the difference between a declaratively set value and dynamically set value. If you don't yet realize why that is important, please keep reading.

3. SERIALIZATION AND DESERIALIZATION 
Aside from how ASP.NET creates declarative controls, the first two capabilities of ViewState we've discussed so far have been strictly related to the StateBag class (how it's similar to a hashtable, and how it tracks dirty values). Here is where things get bigger. Now we will have to start talking about how ASP.NET uses the ViewState StateBag's features to make the (black) magic of ViewState happen.

If you've ever done a "View Source" on an ASP.NET page, you've no doubt encountered the serialization of ViewState. You probably already knew that ViewState is stored in a hidden form field aptly named _ViewState as a base64 encoded string, because when anyone explains how ViewState works, that's usually the first thing they mention.

A brief aside -- before we understand how ASP.NET comes up with this single encoded string, we must understand the hierarchy of controls on the page. Many developers with years of experience still don't realize that a page consists of a tree of controls, because all they work on are ASPX pages, and all they need to worry about are controls that are directly declared on those pages... but controls can contain child controls, which can contain their own child controls, etc. This forms a tree of controls, where the ASPX page itself is the root of that tree. The 2nd level is all the controls declared at the top level in the ASPX page (usually that consists of just 3 controls -- a literal control to represent the content before the form tag, a HtmlForm control to represent the form and all its child controls, and another literal control to represent all the content after the close form tag). On the 3rd level are all the controls contained within those controls (ie, controls that are declared within the form tag), and so on and so forth. Each one of the controls in the tree has it's very own ViewState -- it's very own instance of a StateBag. There's a protected method defined on the System.Web.UI.Control class called SaveViewState. It returns type 'object'. The implementation for Control.SaveViewState is to simply pass the call along to the Control's StateBag (it too has a SaveViewState() method). By calling this method recursively on every control in the control tree, ASP.NET is able to build another tree that is structured not unlike the control tree itself, except instead of a tree of controls, it is a tree of data.

The data at this point is not yet converted into the string you see in the hidden form field, it's just an object tree of the data to be saved. Here is where it finally comes together... are you ready? When the StateBag is asked to save and return it's state (StateBag.SaveViewState()), it only does so for the items contained within it that are marked as Dirty. That is why StateBag has the tracking feature. That is the only reason why it has it. And oh what a good reason it is -- StateBag could just process every single item stored within it, but why should data that has not been changed from it's natural, declarative state be persisted? There's no reason for it to be -- it will be restored on the next request when ASP.NET reparses the page anyway (actually it only parses it once, building a compiled class that does the work from then on). Despite this smart optimization employed by ASP.NET, unnecessary data is still persisted into ViewState all the time due to misuse. I will get into examples that demonstrate these types of mistakes later on.

POP QUIZ
If you've read this far, congratulations, I am rewarding you with a pop quiz. Aren't I nice? Here it is: Let's say you have two nearly identical ASPX forms: Page1.aspx and Page2.aspx. Contained within each page is just a form tag and a label, like so: 

<form id="form1" runat="server">
    <asp:Label id="label1" runat="server" Text="" />
</form>

They are identical except for one minor difference. In Page1.aspx, we shall declare the label's text to be "abc": 

<asp:Label id="label1" runat="server" Text="abc" />

...And on Page2.aspx, we shall declare the label's text to be something much longer (the preamble to the Constitution of the United States of America): 

<asp:Label id="label1" runat="server" Text="We the people of the United States,
        in order to form a more perfect union, establish justice, insure
        domestic tranquility, provide for the common defense, promote the
        general welfare, and secure the blessings of liberty to ourselves and
        our posterity, do ordain and establish this Constitution for the United
        States of America." />


Imagine you browse to Page1.aspx, you will see "abc" and nothing more. Then you use your browser to view the HTML source of the page. You will see the infamous hidden _ViewState hidden field with encoded data in it. Note the size of that string. Now you browse to Page2.aspx, and you see the preamble. You use your browser to view the HTML source once again, and you note the size of the encoded _ViewState field. The question is: Are the two sizes you noted the same, or are they different? Before we get to the answer, lets make it a little bit more involved. Lets say you also put a button next to the label (on each page): 

<asp:Button id="button1" runat="server" Text="Postback" />


There is no code in the click event handler for this button, so clicking on it doesn't do anything except make the page flicker. With this new button in place, you repeat the experiment, except this time when browsing to each page, you click the Postback button before looking at the HTML source. So the question is once again... Are the encoded ViewState values the same, or different? The correct answer to the first part the question is THEY ARE THE SAME! They are the same because in neither of the two ViewState strings are any data related to the label at all. If you understand ViewState, this is obvious. The Text property of the label is set to the declared value before it's ViewState is being tracked. That means if you were to check the dirty flag of the Text item in the StateBag, it would not be marked dirty. StateBag ignores items that aren't dirty when SaveViewState() is called, and it is the object it returns that is serialized into the hidden _ViewState field. Therefore, the text property is not serialized. Since the Text is not serialized in either case, and the forms are identical in every other way, the sizes of the encoded ViewStates on each page must be the same. In fact, no matter how large or small of a string you stuff into that text attribute, the size will remain the same.

The correct answer to the second part is again, THEY ARE THE SAME! In order for data to be serialized, it must be marked as dirty. In order to be marked as dirty, it's value must be set after TrackViewState() is called. But even when we perform a postback, ASP.NET recreates and populates the server controls in the same way. The Text property is still set to it's declared value just like it was in the first request. No other code is setting the text property, so there's no way the StateBag item could become dirty, even on a postback. Therefore, the sizes of the encoded ViewStates on each page after a postback must be the same.

So now we understand how ASP.NET determines what data needs to be serialized. But we don't know how it is serialized. That topic is outside the scope of this article (are you missing an assembly reference?), so if you're really interested in how it works, read up on the LosFormatter for ASP.NET 1.x or the ObjectStateFormatter for ASP.NET 2.0.

Finally on this topic is DESERIALIZATION. Obviously all this fancy dirty tracking and serialization wouldn't do any good if we couldn't get the data back again. That too is outside the scope of this article, but suffice it to say the process is just the reverse. ASP.NET rebuilds the object tree it serialized by reading the posted _ViewState form value and deserializing it with the LosFormatter (v1.x) or the ObjectStateFormatter (v2.0).

4. AUTOMATICALLY RESTORES DATA
This is last on our list of ViewState features. It is tempting to tie this feature in with Deserialization above, but it is not really part of that process. ASP.NET deserializes the ViewState data, and THEN it repopulates the controls with that data. Many articles out there confuse these two processes.

Defined on System.Web.UI.Control (again, the class that every control, user control, and page derive from) is a LoadViewState() method which accepts an object as parameter. This is the opposite of the SaveViewState() method we already discussed, which returns an object. Like SaveViewState(), LoadViewState() simple forwards the call on to it's StateBag object, calling LoadViewState on it. The StateBag then simply repopulates it's key/object collection with the data in the object. In case you are wondering, the object it is given is a System.Web.UI.Pair class, which is just a simple type with a First and Second field on it. The "First" field is an ArrayList of key names, and the "Second" field is an ArrayList of values. So StateBag just iterates over the lists, calling this.Add(key, value) for each item. The important thing to realize here is that the data it was given via LoadViewState() are only items that where marked dirty on the previous request. Prior to loading the ViewState items, the StateBag may already have values in it. Those values may be from declarative properties like we discussed, but they may also be values that were explicitly set by the developer prior to the LoadViewState call. If one of the items passed into LoadViewState already exists in the StateBag for some reason, it will be overwritten.

That right there is the magic of automatic state management. When the page first begins to load during a postback (even prior to initialization), all the properties are set to their declared natural defaults. Then OnInit occurs. During the OnInit phase, ASP.NET calls TrackViewState() on all the StateBags. Then LoadViewState() is called with the deserialized data that was dirty from the previous request. The StateBag calls Add(key, value) for each of those items. Since the StateBag is tracking at this point, the value is marked dirty, so that it may be persisted once again for the next postback. Brilliant! Whew. Now you are an expert on ViewState management.

IMPROPER USE OF VIEWSTATE
Now that we know exactly how ViewState works, we can finally begin to understand the problems that arise when it is used improperly. In this section I will describe cases that illustrate how a lot of ASP.NET developers misuse ViewState. But these aren't just obvious mistakes. Some of these will illustrate nuances about ViewState that will give you an even deeper understanding of how it all fits together. 
    CASES OF MISUSE
  1. Forcing a Default
  2. Persisting static data
  3. Persisting cheap data
  4. Initializing child controls programmatically
  5. Initializing dynamically created controls programmatically
1. Forcing a Default
This is one of the most common misuses, and it is also the easiest to fix. The fixed code is also usually more compact than the wrong code. Yes, doing things the right way can lead to less code. Imagine that. This usually occurs when a control developer wants a particular property to have a particular default value, and does not understand the dirty tracking mechanism, or doesn't care. For example, lets say the Text property a control is supposed to be some value that comes from a Session variable. Developer Joe writes the following code: 

public class JoesControl : WebControl {
    public string Text {
        get { return this.ViewState["Text"] as string; }
        set { this.ViewState["Text"] = value; }
    }
 
    protected override void OnLoad(EventArgs args) {
        if(!this.IsPostback) {
            this.Text = Session["SomeSessionKey"] as string;
        }
 
        base.OnLoad(e);
    }
}

This developer has committed a ViewState crime, call the ViewState police! There's two big problems with this approach. First of all, since Joe is developing a control, and he has taken the time to create a public Text property, it stands to reason that Joe may want developers that use his control to be able to set the Text property to something else. Jane is a page developer that is attempting to do just that, like so: 

<abc:JoesControl id="joe1" runat="server" Text="ViewState rocks!" />

Jane is going to have a bad day. No matter what Jane puts into that Text attribute, Joe's control will refuse to listen to her. Poor Jane. She's using this control just like you use every other ASP.NET control, but this one works differently. Joe's control is overwriting Jane's Text value! Worse than that, since Joe sets it during the OnLoad phase, it is marked dirty in ViewState. So to add insult to injury, Jane is now incurring an increase in her page's serialized ViewState size for doing nothing more than putting Joe's Control on her page. I guess Joe doesn't like Jane very much. Maybe Joe's just trying to get back at Jane for something. Well, since we all know which sex rules this world, we can assume Jane ends up getting Joe to fix his control. Much to Jane's delight, this is what Joe comes up with: 

public class JoesControl : WebControl {
    public string Text {
        get {
            return this.ViewState["Text"] == null ?
                Session["SomeSessionKey"] :
                this.ViewState["Text"] as string;
        }
        set { this.ViewState["Text"] = value; }
    }
}

Look at how much less code we have here. Joe doesn't even have to override OnLoad. Because the StateBag returns null if the given key does not exist, Joe can detect whether his Text property has been set already by checking for null. If it is, he can safely return his would-be default value. If it's not null, he happily returns whatever value it is. Simple as can be. Now when Jane uses Joe's control, not only is her Text attribute honored, she no longer incurs a hit on her ViewState size, either. Better behavior. Better performance. Less code. Everyone wins!

2. Persisting static data
By Static, I mean data that never changes or is not expected to change during the lifetime of a page, or even during the users session. Lets say Joe, our would-be shoddy asp.net developer, has been tasked with adding the current user's name to the top of a page in the company's eCommerce application. It's a nice way of telling the user, "hey, we know who you are!" It makes them feel special and that the site is working. Positive feedback. Lets say this eCommerce application has a business layer API that allows Joe to easily get the name of the currently authenticated user: CurrentUser.Name. Joe completes his task: 

(ShoppingCart.aspx)
<asp:Label id="lblUserName" runat="server" />


(ShoppingCart.aspx.cs)
protected override void OnLoad(EventArgs args) {
    this.lblUserName.Text = CurrentUser.Name;
    base.OnLoad(e);
}

Sure enough, the current user's name will show up. Piece of cake, Joe thinks. Of course we know Joe has committed another sin. The label control he is using is tracking it's ViewState when it is assigned the current user's name. That means not only will the Label render the user name, but that user name will be encoded into the ViewState hidden form field. Why make ASP.NET go through all the work of serializing and deserializing the user name, when you are just going to reassign it after all? That's just rude! Even when confronted, Joe shrugs at the problem. It's only a few bytes! But it's a few bytes you can save so easily. There are two solutions to this problem. First... you could just disable ViewState on the label. 

<asp:Label id="lblUserName" runat="server" EnableViewState="false" />

Problem solved. But there's an even better solution. Label has to be one of the most overused controls there are, bested only by the Panel control. It comes from the mindset of Visual Basic Programmers. To show text on a VB Form you needed a label. Labels are supposed to be the ASP.NET WebForm counterpart, so it's only nature to think you need a label to display a text value that isn't hardcoded in the webform. Fair enough, but that's not true. Label's render a <span> tag around their text content. You must ask yourself whether your really need this span tag at all. Unless you are applying a STYLE to this label, the answer is NO. This would suffice just fine: 

<%= CurrentUser.Name %>

Not only do you get to avoid having to declare a label on the form (which means less code, albeit designer-generated code), but you've followed the spirit of the code-behind model: separation of code from design! In fact, if Joe's company had a dedicated designer responsible for the look and feel of the eCommerce site, Joe could have simply passed on the task. "That's the designers job", he could have balked, and rightfully so. There is another reason why you might THINK you need a Label, and that is when something in the code behind may need to programmatically access or manipulate that label. Ok, fair enough. But you must still ask yourself whether you really need a SPAN tag surrounding the text. Introducing the most underused control in ASP.NET: The LITERAL! 

<asp:Literal id="litUserName" runat="server" EnableViewState="false"/>

No span tag here.

3. Persisting cheap data
This one is a superset of #2. Static data is definitely cheap to get. But not all cheap data is static. Sometimes we have data that may change during the lifetime of an application, possibly from moment to moment, but that data is virtually free to retrieve. By free, I mean the performance cost of looking it up is insignificant. A common instance of this mistake is when populating a dropdown list of U.S. States. Unless you are writing a web application that you plan on warping back in time to December 7, 1787 (here), the list of US States is not going to change any time soon. However, as a programmer that hates to type, you certainly wouldn't want to have to type these states by hand into your web form. And in the event a state does rebel (we can only dream... you know who you are), you wouldn't want to have to perform a code change to strike it from the list. Our proverbial programmer Joe decides he will populate his dropdown list from a USSTATES table in a database. The eCommerce site is already using a database, so its trivial for him to add the table and query it. 

<asp:DropdownList id="lstStates" runat="server"
    DataTextField="StateName" DataValueField="StateCode" />

protected override void OnLoad(EventArgs args) {
    if(!this.IsPostback) {
        this.lstStates.DataSource = QueryDatabase();
        this.lstStates.DataBind();
    }
    base.OnLoad(e);
}

As is the nature of databound controls in ASP.NET, the state dropdown will be using ViewState to remember it's databound list of list items. At the time of this ranting, there are a total of 50 US States. Not only does the dropdown list contain a ListItem for each and every state, but each and every one of those states and their state codes are being serialized into the encoded ViewState. That's a lot of data to be stuffing down the pipe every time the page loads, especially over a dialup connection. I often wonder what it would be like if I explained to my grandmother the reason why her internet is so slow is because her computer is telling the server what all the US States are. I don't think she'd understand. She'd probably just start explaining how when she was young, there were only 46 states. Too bad... those extra 4 states are really wearing down your bandwidth. Damn you late comers! You know who you are!

Like the problem with static data, the general solution to this problem is to just disable ViewState on the control. Unfortunately, that is not always going to work. Whether it does depends on the nature of the control you are binding, and what features of it you are dependant on. In this example, if Joe simply added EnableViewState="false" to the dropdown, and removed the if(!this.IsPostback) condition, he would successfully remove the state data from ViewState, but he would immediately run into a troubling problem. The dropdown will no longer restore it's selected item on postbacks. WAIT!!! This is another source of confusion with ViewState. The reason the dropdown fails to remember it's selected item on postbacks is NOT because you have disabled ViewState on it. Postback controls such as dropdownlist and textbox restore their posted state (the selected item of a dropdown ist 'posted') even when ViewState is disabled, because even with ViewState disabled the control is still able to post its value. It forgets it's selected value because you are rebinding it in OnLoad, which is after the dropdown has already loaded it's posted value. When you databind it again, the first thing it does is throw that into the bit bucket (you know, digital trash). That means if a user selects California from the list, then click on a submit button, the dropdown will stubbornly return the default item (the first item if you don't specify it otherwise). Thankfully, there is an easy solution: Move the DataBind into OnInit: 

<asp:DropdownList id="lstStates" runat="server"
    DataTextField="StateName" DataValueField="StateCode" EnableViewState="false" />

protected override void OnInit(EventArgs args) {
    this.lstStates.DataSource = QueryDatabase();
    this.lstStates.DataBind();
    base.OnInit(e);
}

The short explanation for why this works: You are populating the dropdown list with items before it attempts to load it's posted value. Now the dropdown will behave just like it did when Joe first designed it, only the rather large list of states will NOT be persisted into the ViewState hidden field! Brilliant! More importantly, this rule applies to any data that is cheap and easy to get to. You might argue that making a database query on every request is MORE costly than persisting the data through ViewState. In this case I believe you'd be wrong. Modern database systems (say, SQL Server) have sophisticated caching mechanism and are extremely efficient if configured correctly. The state list needs to be repopulated on every request no matter what you're doing. All you've done is change it from being pushed and pulled down a slow, unreliable 56kbps internet connection that may have to travel for thousands of miles, to being pulled over at worse a 10 megabit LAN connection a couple hundred feet between your internet server and database server. AND if you really wanted to improve things, you could cache the results of the database query in the application. You do the math!

4. Initializing child controls programmatically
Let's face it. You can't do everything declaratively. Sometimes you have to get logic involved. That's why we all have jobs, right? The trouble is ASP.NET does not provide an easy way to programmatically initialize properties of child controls correctly. You can override OnLoad and do it there -- but then you're persisting data that probably doesn't need to be persisted into ViewState. You can override OnInit and do it there instead, but that suffers from the same problem. Remember when we learned how ASP.NET calls TrackViewState() during the OnInit phase? It does this recursively on the entire control tree, but it does it from the BOTTOM of the tree UP! In other words, as a control or webform, the OnInit phase of your child controls occurs BEFORE your own. A control will begin tracking ViewState changes in this phase, which means by the time your own OnInit phase begins, your child controls ViewState are all already tracking! Lets say Joe would like to display the current date and time in a label declared on the form. 

<asp:Label id="lblDate" runat="server" />

protected override void OnInit(EventArgs args) {
    this.lblDate.Text = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
    base.OnInit(e);
}

Even though Joe is setting the label text in the earliest event possible on his webform, it's already too late. The label is tracking ViewState changes, and the current date and time will inevitably be persisted into ViewState. This particular example could fall under the cheap data issue above. Joe could simply disable ViewState on the label to solve this problem. But here we are going to solve it a different way in order to illustrate an important concept. What would be nice is if Joe could declaratively set the label text to what he wants, something like: 

<asp:Label id="Label1" runat="server" Text="<%= DateTime.Now.ToString() %>" />

You may have intuitively attempted this before. But ASP.NET will slap you in the face for it. The "<%= %>" syntax can not be used to assign values to properties of server-side controls. Joe could use the "<%# %>" syntax instead, but that isn't very different than the databinding method we've already covered (disabling ViewState and databinding it every request). The problem is we would like to be able to assign a value through code, but allow the control to continue to work in exactly the way it normally would. Perhaps some code is going to be manipulating this label, and we want any changes made to it to be persisted through ViewState like they normally would be. For example, maybe Joe wants to give the users a way to remove the date display from the form, replacing it with a blank date instead: 

private void cmdRemoveDate_Click(object sender, EventArgs args) {
    this.lblDate.Text = "--/--/---- --:--:--";
}

If the user clicks this button, the current date and time will vanish. But if we solved our original ViewState problem by disabling ViewState on the label, the date and time will magically reappear again on the next postback that occurs, because the label's ViewState being disabled means it will not automatically be restored. That's not good. What on Earth is Joe supposed to do now?

What we really want is to declaratively set a value that is based on logic, not static. If it were declared the label could continue to work like it normally does -- the initial state wouldn't be persisted since it is set before ViewState is tracking, and changes to it would be persisted in ViewState. Like I said... ASP.NET does not provide an easy way to accomplish this task. For you ASP.NET 2.0 developers out there, you do have the $ sign syntax, which allows you to use expression builders to declare values that actually come from a dynamic source (ie, resources, declared connection strings). There's no expression builder for "just run this code" so I don't think that helps you either (UPDATE: Unless you use my customCodeExpressionBuilder!). Also for ASP.NET 2.0 developers, there's OnPreInit. That is actually a great place to initialize child control properties programmatically because it occurs before the child control's OnInit (and therefore before it is tracking ViewState) and after the controls are created. However, OnPreInit is not recursive like the other control phase methods are. That means it is only accessible on the PAGE itself. That doesn't help you what-so-ever if you are developing a CONTROL. It's too bad OnPreInit isn't recursive just like OnInit, OnLoad, and OnPreRender are, I don't see a reason for the inconsistency. The root of the problem is simply that we need to be able to assign the Text property of the label BEFORE it begins tracking its ViewState. We already know the page's OnInit event (the first event that occurs in the page) is already too late for that. So what if we could somehow hook into the Init event of the label? You can't add an event handler in code for that, because the soonest you can do it is in your OnInit which is after the source event has already occurred. And you can't do it in the constructor for the page, because declared controls are not yet created at that point. There are two possibilities:

1. Declaratively hook into the Init event: 
<asp:Label id="Label2" runat="server" OnInit="lblDate_Init" />

This works because the OnInit attribute is processed before the label's own OnInit event occurs, giving us an opportunity to manipulate it before it beings tracking ViewState changes. Our event handler would set its text.

2. Create a custom control: 
public class DateTimeLabel : Label {
    public DateTimeLabel() {
        this.Text = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
    }
}

Then instead of a regular label on the form, a DateTimeLabel is used. Since the control is initializing it's own state, it can do so before tracking begins. It does it during the constructor if possible, so that a declared value will be honored.

5. Initializing dynamically created controls programmatically
This is the same problem as before, but since you are in more control of the situation, it is much easier to solve. Lets say Joe has written a custom control that at some point is dynamically creating a Label. 

public class JoesCustomControl : Control {
    protected override void CreateChildControls() {
        Label l = new Label();
 
        this.Controls.Add(l);
        l.Text = "Joe's label!";
    }
}

Hmmm. When do dynamically created controls begin tracking ViewState? You can create and add dynamically created controls to your controls collection at almost any time during the page lifecycle, but ASP.NET uses the OnInit phase to start ViewState tracking. Won't our dynamic label miss out on that event? No. The trick is, Controls.Add() isn't just a simple collection add request. It does much more. As soon as a dynamic control is added to the control collection of a control that is rooted in the page (if you follow its parent controls eventually you get to the page), ASP.NET plays "catch up" with the event sequence in that control and any controls it contains. So let's say you add a control dynamically in the OnPreRender event (although there plenty of reasons why you would not want to do that). At that point, your OnInit, LoadViewState, LoadPostBackData, and OnLoad events have transpired. The second the control enters your control collection, all of these events happen within the control.

That means my friends the dynamic control is tracking ViewState immediately after you add it. Besides your constructor, the earliest you can add dynamic controls is in OnInit, where child controls are already tracking ViewState. In Joe's control, he's adding them in the CreateChildControls() method, which ASP.NET calls whenever it needs to make sure child controls exist (when it is called can vary based on whether you are an INamingContainer, whether it is a postback, and whether anything else calls EnsureChildControl()). The latest this can happen is OnPreRender, but if it happens any time after or during OnInit, you will be dirtying ViewState again, Joe. The solution is simple but easy to miss: 

public class JoesCustomControl : Control {
    protected override void CreateChildControls() {
        Label l = new Label();
        l.Text = "Joe's label!";
 
        this.Controls.Add(l);
    }
}

Subtle. Instead of initializing the label's text after adding it to the control collection, Joe initializes it before it is added. This ensures without a doubt that the Label is not tracking ViewState when it is initialized. Actually you can use this trick to do more than just initialize simple properties. You can databind controls even before they are part of the control tree. Remember our US State dropdown list example? If we can create that dropdown list dynamically, we can solve that problem without even disabling its ViewState: 

public class JoesCustomControl : Control {
    protected override void OnInit(EventArgs args) {
        DropDownList states = new DropDownList();
        states.DataSource = this.GetUSStatesFromDatabase();
        states.DataBind();
 
        this.Controls.Add(states);
    }
}


It works amazingly well. The dropdown list will behave as if the states are simply built-in list items. They are not persisted in ViewState, yet ViewState is still enabled on the control, meaning you can still take advantage of its ViewState dependant features like the OnSelectedIndexChanged event. You can even do this with DataGrids, although that depends on how you are using it (you will run into problems if you are using sorting, paging, or using the SelectedIndex feature).

BE VIEWSTATE FRIENDLY
Now that you have a complete understanding of how ViewState does it's magic, and how it interacts with the page lifecycle in asp.net, it should be easy to be ViewState Friendly! That is the key really... ViewState optimization is easy as pie when you understand what is going on, often times resulting in even less code than the non-friendly code. Have any suggestions, comments, error reports? Please leave a comment or send me an email!


clock December 2, 2008 18:44 by author Sky Jia (贾超)

From http://weblogs.asp.net/scottgu/archive/2008/11/21/jquery-intellisense-in-vs-2008.aspx by Scott Guthrie

Last month I blogged about how Microsoft is extending support for jQuery.  Over the last few weeks we've been working with the jQuery team to add great jQuery intellisense support within Visual Studio 2008 and Visual Web Developer 2008 Express (which is free).  This is now available to download and use.

Steps to Enable jQuery Intellisense in VS 2008

To enable intellisense completion for jQuery within VS you'll want to follow three steps:

Step 1: Install VS 2008 SP1

VS 2008 SP1 adds richer JavaScript intellisense support to Visual Studio, and adds code completion support for a broad range of JavaScript libraries.

You can download VS 2008 SP1 and Visual Web Developer 2008 Express SP1 here.

Step 2: Install VS 2008 Patch KB958502 to Support "-vsdoc.js" Intellisense Files

Two weeks ago we shipped a patch that you can apply to VS 2008 SP1 and VWD 2008 Express SP1 that causes Visual Studio to check for the presence of an optional "-vsdoc.js" file when a JavaScript library is referenced, and if present to use this to drive the JavaScript intellisense engine.

These annotated "-vsdoc.js" files can include XML comments that provide help documentation for JavaScript methods, as well as additional code intellisense hints for dynamic JavaScript signatures that cannot automatically be inferred.  You can learn more about this patch here.  You can download it for free here.

Step 3: Download the jQuery-vsdoc.js file

We've worked with the jQuery team to put together a jQuery-vsdoc.js file that provides help comments and support for JavaScript intellisense on chained jQuery selector methods.  You can download both jQuery and the jQuery-vsdoc file from the official download page on the jQuery.com site:

Save the jquery-vsdoc.js file next to your jquery.js file in your project (and make sure its naming prefix matches the jquery file name):

You can then reference the standard jquery file with an html <script/> element like so:

Or alternatively reference it using the <asp:scriptmanager/> control, or by adding a /// <reference/> comment at the top of a standalone .js file. 

When you do this VS will now look for a -vsdoc.js file in the same directory as the script file you are referencing, and if found will use it for help and intellisense.  The annotated

For example, we could use jQuery to make a JSON based get request, and get intellisense for the method (hanging off of $.):

As well as help/intellisense for the $.getJSON() method's parameters:

 

The intellisense will continue to work if you nest a callback function within the method call.  For example, we might want to iterate over each JSON object returned from the server:

And for each of the items we could execute another nested callback function:

We could use the each callback function to dynamically append a new image to a list (the image src attribute will point to the URL of the returned JSON media image):

And on each dynamically created image we could wire-up a click event handler so that when it is pressed it will disappear via an animation:

Notice how the jQuery intellisense works cleanly at each level of our code. 

JavaScript Intellisense Tips and Tricks

Jeff King from the Web Tools team wrote up a great post earlier this week that answers a number of common questions about how JavaScript intellisense works with VS 2008.  I highly recommend reading it.

One trick he talks about which I'll show here is a technique you can use when you want to have JavaScript intellisense work within user-controls/partials (.ascx files).  Often you don't want to include a JavaScript library <script src=""/> reference  within these files, and instead have this live on the master page or content page the user control is used within.  The problem of course when you do this is that by default VS has no way of knowing that this script is available within the user control - and so won't provide intellisense of it for you.

One way you can enable this is by adding the <script src=""/> element to your user control, but then surround it with a server-side <% if %> block that always evaluates to false at runtime:

At runtime ASP.NET will never render this script tag (since it is wrapped in an if block that is always false).  However, VS will evaluate the <script/> tag and provide intellisense for it within the user-control.  A useful technique to use for scenarios like the user control one.  Jeff has even more details in his FAQ post as well as his original jQuery intellisense post.  Rick Strahl also has a good post about using jQuery intellisense here.

More Information

To learn more about jQuery, I recommend watching Stephen Walther's ASP.NET and jQuery PDC talk. Click here to download his code samples and powerpoint presentation.

Rick Strahl also has a really nice Introduction to jQuery article that talks about using jQuery with ASP.NET.  Karl Seguin has two nice jQuery primer posts here and here that provide shorter overviews of some of the basics of how to use jQuery. 

I also highly recommend the jQuery in Action book.

Hope this helps,

Scott 


clock November 12, 2008 13:25 by author Sky Jia (贾超)

Posted by Al Tenhundfeld on Oct 26, 2008 11:49 PM

 With the recent release of URL-rewrite module for IIS 7.0 and the inclusion of ASP.NET routing into the .NET Framework 3.5 SP1, many ASP.NET developers are questioning how these two features relate to each other and when each should be used.

Ruslan Yakushev has an instructive post on LearnIIS.net.

The essential difference is that IIS URL rewriting is handled at a lower level than ASP.NET routing and is invisible to the client.

Ruslan provides a visual workflow of the IIS 7 URL Rewriting process. You'll see that the URL Rewrite Module is activated before the request is passed to a request handler, e.g., the ASP.NET managed ASPX handler. IIS URL rewriting is unaware of specific request handlers.

He also provides a visual workflow the ASP.NET Routing process. You'll see the ASP.NET routing is a request dispatcher and must be fully aware of which handler a specific request should be routed to.

From Ruslan's description:

  • 1. URL rewriting is used to manipulate URL paths before the request is handled by the Web server. The URL-rewriting module does not know anything about what handler will eventually process the rewritten URL. In addition, the actual request handler might not know that the URL has been rewritten.
  • 2. ASP.NET routing is used to dispatch a request to a handler based on the requested URL path. As opposed to URL rewriting, the routing component knows about handlers and selects the handler that should generate a response for the requested URL. You can think of ASP.NET routing as an advanced handler-mapping mechanism.

 

  • The IIS URL-rewrite module can be used with any type of Web application, which includes ASP.NET, PHP, ASP, and static files. ASP.NET routing can be used only with .NET Framework-based Web applications.
  • The IIS URL-rewrite module works the same way regardless of whether integrated or classic IIS pipeline mode is used for the application pool. For ASP.NET routing, it is preferable to use integrated pipeline mode. ASP.NET routing can work in classic mode, but in that case the application URLs must include file extensions or the application must be configured to use "*" handler mapping in IIS.
  • The URL-rewrite module can make rewriting decisions based on domain names, HTTP headers, and server variables. By default, ASP.NET routing works only with URL paths and with the HTTP-Method header.
  • In addition to rewriting, the URL-rewrite module can perform HTTP redirection, issue custom status codes, and abort requests. ASP.NET routing does not perform those tasks.
  • The URL-rewrite module is not extensible in its current version. ASP.NET routing is fully extensible and customizable. 

clock October 23, 2008 13:46 by author Sky Jia (贾超)

From  http://blogs.msdn.com/ace_team/archive/2008/08/11/asp-net-performance-high-cpu-utilization-case-studies-and-solutions.aspx by MS ACE Team 

This post shares case studies of high CPU utilization of ASP.NET web sites. High CPU utilization was caused by lack of batch compilation, multiple folders, and use of XmlSerializer. In all cases the result was high CPU and poor performance; the symptom was.NET CLR Loading\Current Assemblies counter showing “unusual” number of loaded assemblies.

Case Study #1 – Lack Of Batch Compilation

Customer reported a high CPU utilization during load/stress testing. After quick investigation we identified that debug attribute was configured to “true” in web.config. Here is what ASP.NET authorities have to say about configuring debug to “true” for ASP.NET web sites:

To prevent further deployment mistakes like this one we created simple performance deployment checklist that included checking debug=”false” configuration among other checks. Following are others checks you might consider when deploying newer version of ASP.NET web site to production:

  1. Delete Temporary ASP.NET files.
  2. Short-circuit the HTTP pipeline
  3. Thread Pool Is Tuned By Using The formula To Reduce Contention

Case Study #2 – Multiple Folders

Customer reported slow response of the ASP.NET web site. After quick investigation we identified that the application’s deployment assumes multiple folders – high tens of folders. This approach took place due to team’s decision to develop every functional module as a separate folder.

ASP.NET batch compilation is the process of compiling ASP.NET markup (content of aspx files) into temporary dll’s. Compilation requires invoking compiler (csc.exe for C#) – that is pretty heavy activity. Process Explorer shows it clearly:

ASP.NET Batch compilation

ASP.NET batch compilation occurs on per folder basis. Said that, if your application divided into multiple sub-folders that contain ASP.NET pages each time any of the folders accessed for the first time the batch compilation is invoked.

To overcome the issue we created simple solution we called ASP.NET Warmer. Complete description of the solution can be found here - Use FREE Tools From IIS Resource Kit To Warm Up Your ASP.NET 1.1 Application By Batch Compilation. The solution included three simple steps:

  1. Identify ASPX pages to “touch” thus invoking batch compilation. We used LogParser to accomplish this task.
  2. Build a program that will actually “touch” these ASPX pages identified in step 1. We used free command line utility called TinyGet from IIS Resource Kit to accomplish this task.
  3. Schedule periodic invocation of the utility.

Case Study #3 – XmlSerializer

Customer reported high memory consumption and high CPU utilization that usually required process recycling. After quick code inspection we identified that the customer’s code uses XmlSerializer to serialize and deserialize types. The serializalbe type was built up of 250 properties. Each request generated 450 such types.

Tess has published complete lab with the source code and analysis for such case, including perfom snapshot (Tess, what a great resource!!). Here Process Explorer shows clearly activation of CSC.exe - C# compiler - on the fly during each request. Green – new instance, Red – disposed instance:

clip_image002

Conclusion

  • Case #1 shows the importance of deploying of ASP.NET web application with performance in mind.
  • Case #2 shows the importance of planning (architecture and design) of ASP.NET web application with performance in mind.
  • Case #3 shows the importance of coding of ASP.NET web application with performance in mind.
  • All cases share simple techniques of monitoring ASP.NET web application in production (maintenance)
  • All the case studies could be easily prevented by proper education of the dev and IT team for Performance Development Lifecycle (PDL).

My Related Posts

Alik Levin

My name is Alik Levin and I am focusing on Security and Performance in .Net applications. 

When I do not blog about Security and Performance I blog about personal development. 

 


clock October 13, 2008 10:46 by author Sky Jia (贾超)

ASP.NET是一个非常强大的构建Web应用的平台,它提供了极大的灵活性和能力以致于可以用它来构建所有类型的Web应用。 
绝大多数的人只熟悉高层的框架如: WebForms WebServices --这些都在ASP.NET层次结构在最高层。

这篇文章的资料收集整理自各种微软公开的文档,通过比较 IIS5IIS6IIS7 这三代 IIS 对请求的处理过程,让我们熟悉 ASP.NET的底层机制并对请求(request)是怎么从Web服务器传送到ASP.NET运行时有所了解。通过对底层机制的了解,可以让我们对 ASP.net 有更深的理解。

IIS 5 ASP.net 请求处理过程

对图的解释:

IIS 5.x 一个显著的特征就是 Web Server 和真正的 ASP.NET Application 的分离。作为 Web Server IIS运行在一个名为 InetInfo.exe 的进程上,InetInfo.exe 是一个Native Executive,并不是一个托管的程序,而我们真正的 ASP.NET Application 则是运行在一个叫做 aspnet_wp Worker Process 上面,在该进程初始化的时候会加载CLR,所以这是一个托管的环境。

ISAPI  指能够处理各种后缀名的应用程序。 ISAPI 是下面单词的简写Internet Server Application Programe Interface,互联网服务器应用程序接口。

IIS 5 模式的特点:

1、首先,同一台主机上在同一时间只能运行一个 aspnet_wp 进程,每个基于虚拟目录的 ASP.NET Application 对应一个 Application Domain ,也就是说每个 Application 都运行在同一个 Worker Process 中,Application之间的隔离是基于 Application Domain 的,而不是基于Process的。

2、其次,ASP.NET  ISAPI 不但负责创建 aspnet_wp Worker Process,而且负责监控该进程,如果检测到 aspnet_wp Performance 降低到某个设定的下限,ASP.NET  ISAPI 会负责结束掉该进程。当 aspnet_wp 结束掉之后,后续的 Request 会导致ASP.NET ISAPI 重新创建新的 aspnet_wp Worker Process

3、最后,由于 IIS Application 运行在他们各自的进程中,他们之间的通信必须采用特定的通信机制。本质上 IIS 所在的 InetInfo 进程和 Worker Process 之间的通信是同一台机器不同进程的通信(local interprocess communications),处于Performance的考虑,他们之间采用基于Named pipe的通信机制。ASP.NET ISAPIWorker Process之间的通信通过他们之间的一组Pipe实现。同样处于Performance的原因,ASP.NET ISAPI 通过异步的方式将Request 传到Worker Process 并获得 Response,但是 Worker Process 则是通过同步的方式向 ASP.NET ISAPI 获得一些基于 Server 的变量。

  

IIS6 ASP.net 请求处理过程

对图的解释:

IIS 5.x 是通过 InetInfo.exe 监听 Request 并把Request分发到Work Process。换句话说,在IIS 5.x中对Request的监听和分发是在User Mode中进行,在IIS 6中,这种工作被移植到kernel Mode中进行,所有的这一切都是通过一个新的组件:http.sys 来负责。

注:为了避免用户应用程序访问或者修改关键的操作系统数据,windows提供了两种处理器访问模式:用户模式(User Mode)和内核模式(Kernel Mode)。一般地,用户程序运行在User mode下,而操作系统代码运行在Kernel Mode下。Kernel Mode的代码允许访问所有系统内存和所有CPU指令。

User Mode下,http.sys接收到一个基于 aspx http request,然后它会根据IIS中的 Metabase 查看该基于该 Request Application 属于哪个Application Pool如果该Application Pool不存在,则创建之。否则直接将 request 发到对应Application Pool Queue中。

每个 Application Pool 对应着一个Worker Processw3wp.exe,毫无疑问他是运行在User Mode下的。在IIS Metabase 中维护着 Application Pool worker processMappingWASWeb Administrative service)根据这样一个mapping,将存在于某个Application Pool Queuerequest 传递到对应的worker process(如果没有,就创建这样一个进程)。在 worker process 初始化的时候,加载ASP.NET ISAPIASP.NET ISAPI 进而加载CLR。最后的流程就和IIS 5.x一样了:通过AppManagerAppDomainFactory Create方法为 Application 创建一个Application Domain;通过 ISAPIRuntime ProcessRequest处理Request,进而将流程进入到ASP.NET Http Runtime Pipeline

  

IIS 7  ASP.net 请求处理过程

  

IIS7 站点启动并处理请求的步骤如下图:

步骤 1 6 ,是处理应用启动,启动好后,以后就不需要再走这个步骤了。

上图的8个步骤分别如下:

1、当客户端浏览器开始HTTP 请求一个WEB 服务器的资源时,HTTP.sys 拦截到这个请求。 
2
HTTP.sys contacts WAS to obtain information from the configuration store.

3WAS 向配置存储中心请求配置信息。applicationHost.config 
4
WWW 服务接受到配置信息,配置信息指类似应用程序池配置信息,站点配置信息等等。 
5
WWW 服务使用配置信息去配置 HTTP.sys 处理策略。 
6
WAS starts a worker process for the application pool to which the request was made.

7The worker process processes the request and returns a response to HTTP.sys.

8、客户端接受到处理结果信息。

W3WP.exe 进程中又是如果处理得呢?? IIS 7 的应用程序池的托管管道模式分两种:经典和集成。这两种模式下处理策略各不相通。

本文作者:郭红俊 http://blog.joycode.com/ghj

  

IIS 6 以及 IIS7 经典模式的托管管道的架构

       IIS7之前,ASP.NET 是以 IIS ISAPI extension 的方式外加到 IIS,其实包括 ASP 以及 PHP,也都以相同的方式配置(PHP IIS 采用了两种配置方式,除了 IIS ISAPI extension 的方式,也包括了 CGI 的方式,系统管理者能选择 PHP 程序的执行方式),因此客户端对 IIS HTTP 请求会先经由 IIS 处理,然后 IIS 根据要求的内容类型,如果是 HTML 静态网页就由 IIS 自行处理,如果不是,就根据要求的内容类型,分派给各自的 IIS ISAPI extension;如果要求的内容类型是 ASP.NET,就分派给负责处理 ASP.NET IIS ISAPI extension,也就是 aspnet_isapi.dll。下图是这个架构的示意图。

IIS  7 应用程序池的托管管道模式  经典  模式也是这样的工作原理。这种模式是兼容IIS 6 的方式,以减少升级的成本。

IIS6 的执行架构图,以及 IIS7  应用程序池配置成经典模式的执行架构图

  

IIS  7 应用程序池的托管管道模式  集成模式

       IIS 7 完全整合 .NET 之后,架构的处理顺序有了很大的不同(如下图),最主要的原因就是 ASP.NET IIS 插件(ISAPI extension)的角色,进入了 IIS 核心,而且也能以 ASP.NET 模块负责处理 IIS 7 的诸多类型要求。这些 ASP.NET 模块不只能处理 ASP.NET 网页程序,也能处理其他如 ASP 程序、PHP 程序或静态 HTML 网页,也因为 ASP.NET 的诸多功能已经成为 IIS 7 的一部份,因此 ASP 程序、PHP 程序或静态 HTML 网页等类型的要求,也能使用像是Forms认证(Forms Authentication)或输出缓存(Output Cache)等 ASP.NET 2.0 的功能(但须修改 IIS 7 的设定值)。也因为 IIS 7 允许自行以 ASP.NET API 开发并加入模块,因此 ASP.NET 网页开发人员将更容易扩充 IIS 7 和网站应用程序的功能,甚至能自行以 .NET 编写管理 IIS 7 的程序(例如以程控 IIS 7 以建置网站或虚拟目录)。

IIS 7 的执行架构图(集成托管信道模式下的架构)

  

小结

IIS5 IIS6 的改进,主要是 HTTP.sys 的改进。

IIS6 IIS7 的改进,主要是 ISAPI 的改进。

  

参考资料:

ASP.NET Process Model之一:IIS ASP.NET ISAPI 
http://www.cnblogs.com/artech/archive/2007/09/09/887528.html

ASP.NET Internals – IIS and the Process Model 
http://dotnetslackers.com/articles/iis/ASPNETInternalsIISAndTheProcessModel.aspx

模组化的IIS 7 .NET 能力整合 
http://www.microsoft.com/taiwan/technet/columns/profwin/33-iis7-componentization-integration.mspx

Introduction to IIS 7.0 Architecture 
http://learn.iis.net/page.aspx/101/introduction-to-iis7-architecture/


clock October 7, 2008 12:08 by author War3

From: http://weblogs.asp.net/scottgu/archive/2008/09/28/jquery-and-microsoft.aspx

 

jQuery is a lightweight open source JavaScript library (only 15kb in size) that in a relatively short span of time has become one of the most popular libraries on the web.

A big part of the appeal of jQuery is that it allows you to elegantly (and efficiently) find and manipulate HTML elements with minimum lines of code.  jQuery supports this via a nice "selector" API that allows developers to query for HTML elements, and then apply "commands" to them.  One of the characteristics of jQuery commands is that they can be "chained" together - so that the result of one command can feed into another.  jQuery also includes a built-in set of animation APIs that can be used as commands.  The combination allows you to do some really cool things with only a few keystrokes.

For example, the below JavaScript uses jQuery to find all <div> elements within a page that have a CSS class of "product", and then animate them to slowly disappear:

As another example, the JavaScript below uses jQuery to find a specific <table> on the page with an id of "datagrid1", then retrieves every other <tr> row within the datagrid, and sets those <tr> elements to have a CSS class of "even" - which could be used to alternate the background color of each row:

[Note: both of these samples were adapted from code snippets in the excellent jQuery in Action book]

Providing the ability to perform selection and animation operations like above is something that a lot of developers have asked us to add to ASP.NET AJAX, and this support was something we listed as a proposed feature in the ASP.NET AJAX Roadmap we published a few months ago.  As the team started to investigate building it, though, they quickly realized that the jQuery support for these scenarios is already excellent, and that there is a huge ecosystem and community built up around it already.  The jQuery library also works well on the same page with ASP.NET AJAX and the ASP.NET AJAX Control Toolkit.

Rather than duplicate functionality, we thought, wouldn't it be great to just use jQuery as-is, and add it as a standard, supported, library in VS/ASP.NET, and then focus our energy building new features that took advantage of it?  We sent mail the jQuery team to gauge their interest in this, and quickly heard back that they thought that it sounded like an interesting idea too.

Supporting jQuery

I'm excited today to announce that Microsoft will be shipping jQuery with Visual Studio going forward.  We will distribute the jQuery JavaScript library as-is, and will not be forking or changing the source from the main jQuery branch.  The files will continue to use and ship under the existing jQuery MIT license.

We will also distribute intellisense-annotated versions that provide great Visual Studio intellisense and help-integration at design-time.  For example:

and with a chained command:

The jQuery intellisense annotation support will be available as a free web-download in a few weeks (and will work great with VS 2008 SP1 and the free Visual Web Developer 2008 Express SP1).  The new ASP.NET MVC download will also distribute it, and add the jQuery library by default to all new projects.

We will also extend Microsoft product support to jQuery beginning later this year, which will enable developers and enterprises to call and open jQuery support cases 24x7 with Microsoft PSS.

Going forward we'll use jQuery as one of the libraries used to implement higher-level controls in the ASP.NET AJAX Control Toolkit, as well as to implement new Ajax server-side helper methods for ASP.NET MVC.  New features we add to ASP.NET AJAX (like the new client template support) will be designed to integrate nicely with jQuery as well. 

We also plan to contribute tests, bug fixes, and patches back to the jQuery open source project.  These will all go through the standard jQuery patch review process.

Summary

We are really excited to be able to partner with the jQuery team on this.  jQuery is a fantastic library, and something we think can really benefit ASP.NET and ASP.NET AJAX developers.  We are looking forward to having it work great with Visual Studio and ASP.NET, and to help bring it to an even larger set of developers.

For more details on today's announcement, please check out John Resig's post on the jQuery team blog.  Scott Hanselman is also about to post a nice tutorial that shows off integrating jQuery with ASP.NET AJAX (including the new client templating engine) as well as ADO.NET Data Services (which shipped in .NET 3.5 SP1 and was previously code-named "Astoria").

Hope this helps,

Scott


Search

Calendar

<<  September 2010  >>
SuMoTuWeThFrSa
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

Categories

Tags