ASP.NET From Scratch
Web Server and ASP.NET Application Life Cycle in Depth IIS6 and IIS 7
A Web Server (like Internet Information Server/Apache/etc.) is a piece of software that enables a website to be viewed using HTTP. We can abstract this concept by saying that a web server is a piece of software that allows resources (web pages, images, etc.) to be requested over the HTTP protocol. I am sure many of you have thought that a web server is just a special super computer, but it's just the software that runs on it that makes the difference between a normal computer and a web server.
As everyone knows, in a Web Communication, there are two main actors: the Client and the Server.
The client and the server, of course, need a connection to be able to communicate with each other, and a common set of rules to be able to understand each other. The rules they need to communicate are called protocols. Conceptually, when we speak to someone, we are using a protocol. The protocols in human communication are rules about appearance, speaking, listening, and understanding. These rules, also called protocols of conversation, represent different layers of communication. They work together to help people communicate successfully. The need for protocols also applies to computing systems. A communications protocol is a formal description of digital message formats and the rules for exchanging those messages in or between computing systems and in telecommunications.
HTTP knows all the "grammar", but it doesn't know anything about how to send a message or open a connection. That's why HTTP is built on top of TCP/IP. Below, you can see the conceptual model of this protocol on top of the HTTP protocol:
TCP/IP is in charge of managing the connection and all the low level operations needed to deliver the message exchanged between the client and the server.
In this article, I won't explain how TCP/IP works, because I should write a whole article on it, but it's good to know it is the engine that allows the client and the server to have message exchanges.
HTTP is a connectionless protocol, but it doesn't mean that the client and the server don't need to establish a connection before they start to communicate with each other. But, it means that the client and the server don't need to have any prearrangements before they start to communicate.
Connectionless means the client doesn't care if the server is ready to accept a request, and on the other hand, the server doesn't care if the client is ready to get the response, but a connection is still needed.
In connection-oriented communication, the communicating peers must first establish a logical or physical data channel or connection in a dialog preceding the exchange of user data.
Now, let's see what happens when a user puts an address into the browser address bar.
- The browser breaks the URL into three parts:
- The protocol ("HTTP")
- The server name (www.Pelusoft.co.uk)
- The file name (index.html)
- The browser communicates with a name server(DNS) to translate the server name "www.Pelusoft.co.uk" into an IP address, which it uses to connect to the server machine.
- The browser then forms a connection to the server at that IP address on port 80. (We'll discuss ports later in this article.)
- Following the HTTP protocol, the browser sents a GET request to the server, asking for the file "http://www.pelusoft.co.uk.com/index.htm". (Note that cookies may be sent from the browser to the server with the GET request -- see How Internet Cookies Work for details.)
- The server then sents the HTML text for the web page to the browser. Cookies may also be sent from the server to the browser in the header for the page.)
- The browser reads the HTML tags and formats the page onto your screen.
- The protocol ("HTTP")
- The server name (www.Pelusoft.co.uk)
- The file name (index.html)
The current practice requires that the connection be established by the client prior to each request, and closed by the server after sending the response. Both clients and servers should be aware that either party may close the connection prematurely, due to user action, automated time-out, or program failure, and should handle such closing in a predictable fashion. In any case, the closing of the connection by either or both parties always terminates the current request, regardless of its status.
At this point, you should have an idea about how the HTTP - TCP/IP protocol works. Of course, there is a lot more to say, but the scope of this article is just a very high view of these protocols just to better understand all the steps that occur since the user starts to browse a web site.
Now it's time to go ahead, moving the focus on to what happens when the web server receives the request and how it can get the request itself.
As I showed earlier, a web server is a "normal computer" that is running a special software that makes it a Web Server. Let's suppose that IIS runs on our web server. From a very high view, IIS is just a process which is listening on a particular port (usually 80). Listening means it is ready to accept a connections from clients on port 80. A very important thing to remember is: IIS is not ASP.NET. This means that IIS doesn't know anything about ASP.NET; it can work by itself. We can have a web server that is hosting just HTML pages or images or any other kind of web resource. The web server, as I explained earlier, has to just return the resource the browser is asking for.
Old Browser is using Serial connection HandShaking Mechanism
Modern Browsers using parallel connection Handshaking mechanism
Modern browsers are using Persistent Connection mechanism in Modern browsers
HTTP persistent connection, also called HTTP keep-alive, or HTTP connection reuse, is the idea of using a single TCP connection to send and receive multiple HTTP requests/responses, as opposed to opening a new connection for every single request/response pair.
ASP.NET and IIS
The web server can also support server scripting (as ASP.NET). What I show in this paragraph is what happens on the server running ASP.NET and how IIS can "talk" with the ASP.NET engine. When we install ASP.NET on a server, the installation updates the script map of an application to the corresponding ISAPI extensions to process therequest given to IIS. For example, the "aspx" extension will be mapped to aspnet_isapi.dll and hence requests for anaspx page to IIS will be given to aspnet_isapi (the ASP.NET registration can also be done using Aspnet_regiis). The script map is shown below:
The ISAPI filter is a plug-in that can access an HTTP data stream before IIS gets to see it. Without the ISAPI filter, IIS can not redirect a request to the ASP.NET engine (in the case of a .aspx page). From a very high point of view, we can think of the ISAPI filter as a router for IIS requests: every time there is a resource requested whose file extension is present on the map table (the one shown earlier), it redirect the request to the right place. In the case of an .aspx page, it redirects the request to the .NET runtime that knows how to elaborate the request.
When a request comes in:
- IIS creates/runs the work processor (w3wp.exe) if it is not running.
- The aspnet_isapi.dll is hosted in the w3wp.exe process. IIS checks for the script map and routes the requestto aspnet_isapi.dll.
- The request is passed to the .NET runtime that is hosted into w3wp.exe as well.
Finally, the request gets into the ASP.NET runtime
This paragraph focuses on how the runtime handles the request and shows all the objects involved in the process.
First of all, let's have a look at what happens when the request gets to the runtime.
- When ASP.NET receives the first request for any resource in an application, a class named Application Manager creates an Application domain. (Application domains provide isolation between applications for global variables, and allow each application to be unloaded separately.)
- Within an application domain, an instance of the class named Hosting Environment is created, which provides access to information about the application such as the name of the folder where the application is stored.
- After the application domain has been created and the Hosting Environment object instantiated, ASP.NET creates and initializes core objects such as HttpContext, HttpRequest, and HttpResponse.
- After all core application objects have been initialized, the application is started by creating an instance of the HttpApplication class.
- If the application has a Global.asax file, ASP.NET instead creates an instance of the Global.asax class that is derived from the HttpApplication class and uses the derived class to represent the application.
Those are the first steps that happens against a client request. Most articles don't say anything about these steps. In this article, we will analyze in depth what happens at each step.
Below, you can see all the steps the request has to pass though before it is elaborated.
Application Manager
The first object we have to talk about is the Application Manager. Application Manager is actually an object that sits on top of all running ASP.NET AppDomains, and can do things like shut them all down or check for idle status. For example, when you change the configuration file of your web application, the Application Manager is in charge to restart the AppDomain to allow all the running application instances (your web site instance) to be created again for loading the new configuration file you may have changed.
Requests that are already in the pipeline processing will continue to run through the existing pipeline, while any newrequest coming in gets routed to the new AppDomain. To avoid the problem of "hung requests", ASP.NET forcefully shuts down the AppDomain after the request timeout period is up, even if requests are still pending.
Application Manager is the "manager", but the Hosting Environment contains all the "logic" to manage the application instances. It's like when you have a class that uses an interface: within the class methods, you just call the interface method. In this case, the methods are called within the Application Manager, but are executed in the Hosting Environment (let's suppose the Hosting Environment is the class that implements the interface).
At this point, you should have a question: how is it possible the Application Manager can communicate with the Hosting Environment since it lives in an AppDomain? (We said the AppDomain creates a kind of boundary around the application to isolate the application itself.) In fact, the Hosting Environment has to inherit from the MarshalByRefObject class to use Remoting to communicate with the Application Manager. The Application Manager creates a remote object (the Hosting Environment) and calls methods on it.
So we can say the Hosting Environment is the "remote interface" that is used by the Application Manager, but the code is "executed" within the Hosting Environment object.
Application Manager
The first object we have to talk about is the Application Manager. Application Manager is actually an object that sits on top of all running ASP.NET AppDomains, and can do things like shut them all down or check for idle status. For example, when you change the configuration file of your web application, the Application Manager is in charge to restart the AppDomain to allow all the running application instances (your web site instance) to be created again for loading the new configuration file you may have changed.
Requests that are already in the pipeline processing will continue to run through the existing pipeline, while any newrequest coming in gets routed to the new AppDomain. To avoid the problem of "hung requests", ASP.NET forcefully shuts down the AppDomain after the request timeout period is up, even if requests are still pending.
Application Manager is the "manager", but the Hosting Environment contains all the "logic" to manage the application instances. It's like when you have a class that uses an interface: within the class methods, you just call the interface method. In this case, the methods are called within the Application Manager, but are executed in the Hosting Environment (let's suppose the Hosting Environment is the class that implements the interface).
At this point, you should have a question: how is it possible the Application Manager can communicate with the Hosting Environment since it lives in an AppDomain? (We said the AppDomain creates a kind of boundary around the application to isolate the application itself.) In fact, the Hosting Environment has to inherit from the MarshalByRefObject class to use Remoting to communicate with the Application Manager. The Application Manager creates a remote object (the Hosting Environment) and calls methods on it.
So we can say the Hosting Environment is the "remote interface" that is used by the Application Manager, but the code is "executed" within the Hosting Environment object.
HttpApplication
On the previous paragraph, I used the term "Application" a lot. HttpApplication is an instance of your web application. It's the object in charge to "elaborate" the request and return the response that has to be sent back to the client. An HttpApplication can elaborate only one request at a time. However, to maximize performance,HttpApplication instances might be reused for multiple requests, but it always executes one request at a time.
This simplifies application event handling because you do not need to lock non-static members in the application class when you access them. This also allows you to store request-specific data in non-static members of the application class. For example, you can define a property in the Global.asax file and assign it a request-specific value.
You can't manually create an instance of HttpApplication; it is the Application Manager that is in charge to do that. You can only configure what is the maximum number of HttpApplications you want to be created by the Application Manager. There are a bunch of keys in the machine config that can affect the Application Manager behavior:
With maxWorkerThreads and minWorkerThreads, you set up the minimum and maximum number of HttpApplications. For more information, have a look at: ProcessModel Element.
Just to clarify what we have said until now, we can say that against a request to a WebApplication, we have:
- A Worker Process w3wp.exe is started (if it is not running).
- An instance of ApplicationManager is created.
- An ApplicationPool is created.
- An instance of a Hosting Environment is created.
- A pool of HttpAplication instances is created (defined with the machine.config).
Until now, we talked about just one WebApplication, let's say WebSite1, under IIS. What happens if we create another application under IIS for WebSite2?
- We will have the same process explained above.
- WebSite2 will be executed within the existing Worker Process w3wp.exe (where WebSite1 is running).
- The same Application Manager instance will manage WebSite2 as well. There is always an instance per Work Proces w3wp.exe.
- WebSite2 will have its own AppDomain and Hosting Environment.
- Within a new AppDomain will be run instances of WebSite2 (HttpApplication instances).
It's very important to notice that each web application runs in a separate AppDomain so that if one fails or does something wrong, it won't affect the other web apps that can carry on their work. At this point, we should have another question:
What would happen if a Web Application, let's say WebSite1, does something wrong affecting the Worker Process (even if it's quite difficult)?
What if I want to recycle the application domain?
To summarize what we have said, an AppPool consists of one or more processes. Each web application that you are running consists of (usually, IIRC) an Application Domain. The issue is when you assign multiple web applications to the same AppPool, while they are separated by the Application Domain boundary, they are still in the same process (w3wp.exe). This can be less reliable/secure than using a separate AppPool for each web application. On the other hand, it can improve performance by reducing the overhead of multiple processes.
An Internet Information Services (IIS) application pool is a grouping of URLs that is routed to one or more worker processes. Because application pools define a set of web applications that share one or more worker processes, they provide a convenient way to administer a set of web sites and applications and their corresponding worker processes. Process boundaries separate each worker process; therefore, a web site or application in an application pool will not be affected by application problems in other application pools. Application pools significantly increase both the reliability and manageability of a web infrastructure.
I want to better understand the difference between an AppDomain and an Application Pool
Just for better understanding, let's say you are working with Internet Explorer. As you know, you can open more than one tab for browsing more than one web site in the same instance of IE.Let' say you open four tabs browsing different web sites, so that each tab will show a different web site.
After lots of pints of beer, let's assume that each tab is running within a different App Domain and each web site we are browsing is a different web app under IIS. All the web sites we are browsing are sharing the same instance of IE (iexplorer.exe). In this example, let's compare the IE instance (iexplorer.exe) to the ASP.NET Worker Process (w3wp.exe). If one tab is stuck for any reason (as sometime happens :-)), it's going to affect all the other tabs running under the same iexplorer.exe instance (some times, IE gets stuck and it doesn't respond to any interaction anymore, showing Not responding), so you are forced to kill the process to carry on working.
By killing the process, you will not able to browse any of the web sites you were browsing, even if it was just one process that made got IE stuck. So what can we do if we want to isolate web site browsing at process level so that if one web site does something wrong, we can carry on browsing the other web sites? Simple, you can open two instance of IE and open two tabs on each instance. In this case, two iexplore.exe instances will be running, and they will be completely independent of each other: if a tab is stuck on one instance of Internet Explorer, you can kill that process, but the other one will carry on to work.
ASP.NET Authentication And Authorization
Before proceeding ahead we need to understand four important vocabularies which you will see in this article again and again: - authentication, authorization, principal and identity. Let’s first start with authentication and authorization. If you search in www.google.com for the dictionary meaning of authentication and authorization, you will land up with something below:-
Authentication: - prove genuineness
Authorization: - process of granting approval or permission on resources.
The same dictionary meaning applies to ASP.NET as well. In ASP.NET authentication means to identify the user or in other words its nothing but to validate that he exists in your database and he is the proper user. Authorization means does he have access to a particular resource on the IIS website. A resource can be an ASP.NET web page, media files (MP4, GIF, JPEG etc), compressed file (ZIP, RAR) etc.
So the first process which happens is authentication and then authorization. Below is a simple graphical representation of authentication and authorization. So when the user enters ‘userid’ and ‘password’ he is first authenticated and identified by the user name.
Now when the user starts accessing resources like pages, ASP DOTNET authentication, videos etc, he is checked whether he has the necessary access for the resources. The process of identifying the rights for resources is termed as ‘Authorization’.
Detecting authentication and authorization: - The principal and identity objects
At any moment of time if you want to know who the user is and what kind of authentication type he using you can use the identity object. If you want to know what kind of roles it’s associated with then we need to use the principal object. In other words to get authentication details we need to the identity object and to know about authorization details of that identity we need the principal object.
Types of authentication and authorization in ASP.NET
There are three ways of doing authentication and authorization in ASP.NET:-
• Windows authentication: - In this methodology ASP.NET web pages will use local windows users and groups to authenticate and authorize resources.
• Forms Authentication: - This is a cookie based authentication where username and password are stored on client machines as cookie files or they are sent through URL for every request. Form-based authentication presents the user with an HTML-based Web page that prompts the user for credentials.
• Passport authentication :- Passport authentication is based on the passport website provided
by the Microsoft .So when user logins with credentials it will be reached to the passport website ( i.e. hotmail,devhood,windows live etc) where authentication will happen. If Authentication is successful it will return a token to your website.
• Anonymous access: - If you do not want any kind of authentication then you will go for Anonymous access.
GenericPrincipal and GenericIdentity objects represent users who have been authenticated using Forms authentication or other custom authentication mechanisms. With these objects, the role list is obtained in a custom manner, typically from a database.
FormsIdentity and PassportIdentity objects represent users who have been authenticated with Forms and Passport authentication respectively.
Windows Authentication
When you configure
your ASP.NET application as windows authentication it will use local windows user and
groups to do authentication and
authorization for your ASP.NET pages. Below
is a simple snap shot which shows my windows users and roles on my computer.
5 steps to enable authentication and authorization using windows
We will do a small sample to get a grasp of how authentication and authorization works with windows.
We will create 2 users one ‘Administrator’ and other a simple user with name
‘Shiv’. We will create two simple ASPX pages ‘User.aspx’ page and ‘Admin.aspx’
page. ‘Administrator’ user will have access to both ‘Admin.aspx’ and
‘User.aspx’ page , while user ‘Shiv’ will only have access to ‘User.aspx’ page.
Create a website - Step 1
The next step is to
create a simple web site with 3 pages (User.aspx, Admin.aspx and Home.aspx) as
shown below.
Creating user in windows directory - Step 2
The next step is we
go to the windows directory and create two users. You can see in my computer we
have ‘Administrator’ and ‘Shiv’.
Setup We.Config file - Step 3
Setup Authorization - Step 4
We also need to
specify the authorization part. We need to insert the below snippet in the
‘web.config’ file stating that only ‘Administrator’ users will have access to
Setup Configure IIS - Step 5
The next step is to
compile the project and upload the same on an IIS virtual directory. On the IIS
virtual directory we need to ensure to remove anonymous access and check the
integrated windows authentication as shown
in the below figure.
Basic Authentication
We then copied the ‘Authorization:Basic’ data and ran the
below program. LOL, we can see our windows userid and password.
Integrated Authentication
Integrated Windows authentication
(formerly called NTLM, and also known as Windows NT Challenge/Response authentication) uses either Kerberos v5 authentication or NTLM authentication, depending upon the client and
server configuration.
(The above paragraph is ripped from http://msdn.microsoft.com/en-us/library/ff647076.aspx
).
Let’s try to understand what NTLM and Kerberos authentication
is all about and then we will try to understand other aspects of integrated authentication.
NTLM is a challenge response authentication
protocol. Below is how the sequence of events happens:-
• Client sends the username and password to the server.
• Server sends a challenge.
• Client responds to the challenge with 24 byte result.
• Servers checks if the response is properly computed by contacting the domain
controller.
• If everything is proper it grants the request.
Order of Security Precedence
One of the things
which you must have noticed is that integrated, digest and basic authentication are check boxes. In other words we
can check all the three at one moment of time. If you check all the 3 options
at one moment of time depending on browser security support one of the above
methods will take precedence.
Let’s understand how the security precedence
works as per browser security.
• Browser makes a request; it sends the first request as Anonymous. In other
words it does not send any credentials.
• If the server does not accept Anonymous IIS responds with an "Access
Denied" error message and sends a list of the authentication types that are supported by the
browser.
• If Windows NT Challenge/Response is the only one supported method then the
browser must support this method to communicate with the server. Otherwise, it
cannot negotiate with the server and the user receives an "Access
Denied" error message.
• If Basic is the only supported method, then a dialog box appears in the
browser to get the credentials, and then passes these credentials to the
server. It attempts to send these credentials up to three times. If these all
fail, the browser is not connected to the server.
• If both Basic and Windows NT Challenge/Response are supported, the browser
determines which method is used. If the browser supports Windows NT
Challenge/Response, it uses this method and does not fall back to Basic. If
Windows NT Challenge/Response is not supported, the browser uses Basic.
You can read more about precedence from http://support.microsoft.com/kb/264921.
In order words the precedence is:-
1. Windows NT challenge ( Integrated security)
2. Digest
3. Basic
Forms Authentication
Forms authentication is
a cookie/URL based authentication where
username and password are stored on client machines as cookie files or they are
sent encrypted on the URL for every request if cookies are not supported.
Below are the various steps which happen in forms authentication:-
• Step 1:- User enters “userid” and “password” through a
custom login screen developed for authentication
and authorization.
• Step 2:- A check is made to ensure that the user is valid.
The user can be validated from ‘web.config’ files, SQL Server, customer
database, windows active directory and various other kinds of data sources.
• Step 3:- If the user is valid then a cookie text file is
generated on the client end. This cookie test file signifies that the user has
been authenticated. Hence forth when the client computer browses other
resources of your ASP.NET site the
validation is not conducted again. The cookie file indicates that the user has
logged in.
Form Authentication using Web.config as a data store
Forms authentication using ASP.NET Membership and Role
Forms Authentication using Single Sign On
Passport Authentication
Passport authentication is based on the passport website
provided by the Microsoft .So when user logins with credentials it will be
reached to the passport website ( i.e. hotmail,devhood,windows live etc) where authentication will happen. If Authentication is successful it will return a
token to your website.
I am leaving this section for now, will update in more details soon.
ASP.NET Impersonation
Visual Studio .NET 2003
Another
important security feature is the ability to control the identity under
which code is executed. Impersonation is when ASP.NET executes code in
the context of an authenticated and authorized client. By default,
ASP.NET does not use impersonation and instead executes all code using
the same user account as the ASP.NET process, which is typically the
ASPNET account. This is contrary to the default behavior of ASP, which
uses impersonation by default. In Internet Information Services (IIS) 6,
the default identity is the NetworkService account.
Note
Impersonation can significantly affect performance and scaling. It is
generally more expensive to impersonate a client on a call than to make
the call directly.
Using impersonation,
ASP.NET applications can optionally execute the processing thread using
the identity of the client on whose behalf they are operating. You
usually use impersonation for resource access control. Delegation is a
more powerful form of impersonation and makes it possible for the server
process to access remote resources while acting as the client. For more
information, see ASP.NET Delegation.
Note
Impersonation is local to a particular thread. When code changes
threads, such as when using thread pooling, the new thread executes
using the process identity by default. When impersonation is required on
the new thread, your application should save the security token (WindowsIdentity.Token Property) from the original thread as part of the state for the completion thread.
If
you enable impersonation, ASP.NET can either impersonate the
authenticated identity received from IIS or one specified in the
application's Web.config file. You have the following three options when
configuring impersonation:
- Impersonation is disabled.
This is the default setting. For backward compatibility with ASP, you
must enable impersonation and change the ASP.NET process identity to use
the Local System account. In this instance, the ASP.NET thread runs
using the process token of the application worker process regardless of
which combination of IIS and ASP.NET authentication is used. By default,
the process identity of the application worker process is the ASPNET
account. For more information, see ASP.NET Process Identity.
Copy
<identity impersonate="false" />
- Impersonation enabled.
In this instance, ASP.NET impersonates the token passed to it by IIS,
which is either an authenticated user or the anonymous Internet user
account (IUSR_machinename).
Copy
<identity impersonate="true" />
- Impersonation enabled for a specific identity. In this instance, ASP.NET impersonates the token generated using an identity specified in the Web.config file.
Copy
<identity impersonate="true"
userName="domain\user"
password="password" />
If
the application resides on a UNC share, ASP.NET always impersonates the
IIS UNC token to access that share unless a configured account is used.
If you provide an explicitly configured account, ASP.NET uses that
account in preference to the IIS UNC token.
You
should exercise care when using impersonation because it makes it
possible for an application to potentially process code using
permissions not anticipated by the application designer. For example, if
your application impersonates an authenticated intranet user, that
application possesses administrative privileges when impersonating a
user with those privileges. Likewise, if the impersonated user possesses
more restrictive permissions than anticipated, the user may not be able
to use the application.
ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0
Stage Description
User requests an application resource from the Web server. The
life cycle of an ASP.NET application starts with a request sent by a
browser to the Web server (for ASP.NET applications, typically IIS).
ASP.NET is an ISAPI extension under the Web server. When a Web server
receives a request, it examines the file-name extension of the requested
file, determines which ISAPI extension should handle the request, and
then passes the request to the appropriate ISAPI extension. ASP.NET
handles file name extensions that have been mapped to it, such as .aspx,
.ascx, .ashx, and .asmx.
Note
If
a file name extension has not been mapped to ASP.NET, ASP.NET will not
receive the request. This is important to understand for applications
that use ASP.NET authentication. For example, because .htm files are
typically not mapped to ASP.NET, ASP.NET will not perform authentication
or authorization checks on requests for .htm files. Therefore, even if a
file contains only static content, if you want ASP.NET to check
authentication, create the file using a file name extension mapped to
ASP.NET, such as .aspx.
Note
If
you create a custom handler to service a particular file name
extension, you must map the extension to ASP.NET in IIS and also
register the handler in your application's Web.config file. For more
information, see HTTP Handlers and HTTP Modules Overview.
ASP.NET receives the first request for the application. When ASP.NET receives the first request for any resource in an application, a class named ApplicationManager
creates an application domain. Application domains provide isolation
between applications for global variables and allow each application to
be unloaded separately. Within an application domain, an instance of the
class named HostingEnvironment
is created, which provides access to information about the application
such as the name of the folder where the application is stored.
The following diagram illustrates this relationship:
ASP.NET
also compiles the top-level items in the application if required,
including application code in the App_Code folder. For more information,
see "Compilation Life Cycle" later in this topic.
ASP.NET core objects are created for each request. After the application domain has been created and the HostingEnvironment object instantiated, ASP.NET creates and initializes core objects such as HttpContext, HttpRequest, and HttpResponse. The HttpContext class contains objects that are specific to the current application request, such as the HttpRequest and HttpResponse objects. The HttpRequest object contains information about the current request, including cookies and browser information. The HttpResponse object contains the response that is sent to the client, including all rendered output and cookies.
An HttpApplication object is assigned to the request After all core application objects have been initialized, the application is started by creating an instance of the HttpApplication
class. If the application has a Global.asax file, ASP.NET instead
creates an instance of the Global.asax class that is derived from the HttpApplication class and uses the derived class to represent the application.
Note
The first time an ASP.NET page or process is requested in an application, a new instance of HttpApplication is created. However, to maximize performance, HttpApplication instances might be reused for multiple requests.
When an instance of HttpApplication
is created, any configured modules are also created. For instance, if
the application is configured to do so, ASP.NET creates a SessionStateModule module. After all configured modules are created, the HttpApplication class's Init method is called.
The following diagram illustrates this relationship:
The request is processed by the HttpApplication pipeline. The following events are executed by the HttpApplication class while the request is processed. The events are of particular interest to developers who want to extend the HttpApplication class.
When
the first request is made to an application, ASP.NET compiles
application items in a specific order. The first items to be compiled
are referred to as the top-level items. After the first request, the
top-level items are recompiled only if a dependency changes. The
following table describes the order in which ASP.NET top-level items are
compiled.
Item Description
App_GlobalResources The
application's global resources are compiled and a resource assembly is
built. Any assemblies in the application's Bin folder are linked to the
resource assembly.
App_WebResources Proxy
types for Web services are created and compiled. The resulting Web
references assembly is linked to the resource assembly if it exists.
Profile properties defined in the Web.config file If
profile properties are defined in the application's Web.config file, an
assembly is generated that contains a profile object.
App_Code Source
code files are built and one or more assemblies are created. All code
assemblies and the profile assembly are linked to the resources and Web
references assemblies if any.
Global.asax The application object is compiled and linked to all of the previously generated assemblies.
After
the application's top level items have been compiled, ASP.NET compiles
folders, pages, and other items as needed. The following table describes
the order in which ASP.NET folders and items are compiled.
Item Description
App_LocalResources If
the folder containing the requested item contains an App_LocalResources
folder, the contents of the local resources folder are compiled and
linked to the global resources assembly.
Individual Web pages (.aspx files), user controls (.ascx files), HTTP handlers (.ashx files), and HTTP modules (.asmx files) Compiled as needed and linked to the local resources assembly and the top-level assemblies.
Themes, master pages, other source files Skin
files for individual themes, master pages, and other source code files
referenced by pages are compiled when the referencing page is compiled.
Compiled
assemblies are cached on the server and reused on subsequent requests
and are preserved across application restarts as long as the source code
is unchanged.
Because the application is
compiled on the first request, the initial request to an application can
take significantly longer than subsequent requests. You can precompile
your application to reduce the time required for the first request. For
more information, see How to: Precompile ASP.NET Web Site Projects.
ASP.NET Application Life Cycle Overview for IIS 7.0
A
request in IIS 7.0 Integrated mode passes through stages that are like
the stages of requests for ASP.NET resources in IIS 6.0. However, in IIS
7.0, these stages include several additional application events, such
as the MapRequestHandler, LogRequest, and PostLogRequest events.
The
main difference in processing stages between IIS 7.0 and IIS 6.0 is in
how ASP.NET is integrated with the IIS server. In IIS 6.0, there are two
request processing pipelines. One pipeline is for native-code ISAPI
filters and extension components. The other pipeline is for managed-code
application components such as ASP.NET. In IIS 7.0, the ASP.NET runtime
is integrated with the Web server so that there is one unified request
processing pipeline for all requests. For ASP.NET developers, the
benefits of the integrated pipeline are as follows:
· The integrated pipeline raises all the events that are exposed by the HttpApplication object, which enables existing ASP.NET HTTP modules to work in IIS 7.0 Integrated mode.
·
Both native-code and managed-code modules can be configured at the Web
server, Web site, or Web application level. This includes the built-in
ASP.NET managed-code modules for session state, forms authentication,
profiles, and role management. Furthermore, managed-code modules can be
enabled or disabled for all requests, regardless of whether the request
is for an ASP.NET resource like an .aspx file.
·
Managed-code modules can be invoked at any stage in the pipeline. This
includes before any server processing occurs for the request, after all
server processing has occurred, or anywhere in between.
· You can register and enable or disable modules through an application’s Web.config file.
The following illustration shows the configuration of an application's request pipeline. The example includes the following:
· The Anonymous native-code module and the Forms managed-code module (which corresponds to FormsAuthenticationModule). These modules are configured, and they are invoked during the Authentication stage of the request.
· The Basic native-code module and the Windows managed-code module (which corresponds to WindowsAuthenticationModule). They are shown, but they are not configured for the application.
·
The Execute handler stage, where the handler (a module scoped to a URL)
is invoked to construct the response. For aspx files, the PageHandlerFactory handler is used to respond to the request. For static files, the native-code StaticFileModule module responds to the request.
· The Trace native-code module. This is shown, but it is not configured for the application.
· The Custom module managed-code class. It is invoked during the Log request stage.
For
information about known compatibility issues with ASP.NET applications
that are being migrated from earlier versions of IIS to IIS 7.0, see the
"Known Differences Between Integrated Mode and Classic Mode" section of
Upgrading ASP.NET Applications to IIS 7.0: Differences between IIS 7.0 Integrated Mode and Classic mode.
Life Cycle Stages
The following table lists the stages of the ASP.NET application life cycle with Integrated mode in IIS 7.0.
Stage Description
A request is made for an application resource. The life cycle of an ASP.NET application starts with a request sent by a browser to the Web server.
In
Classic mode in IIS 7.0 and in IIS 6.0, the ASP.NET request pipeline is
separate from the Web server pipeline. Modules apply only to requests
that are routed to the ASP.NET ISAPI extension. If the file-name
extension of the requested resource type is not explicitly mapped to
ASP.NET, ASP.NET functionality is not invoked for the request because
the request is not processed by the ASP.NET runtime.
In
integrated mode in IIS 7.0, a unified pipeline handles all requests.
When the integrated pipeline receives a request, the request passes
through stages that are common to all requests. These stages are
represented by the RequestNotification
enumeration. All requests can be configured to take advantage of
ASP.NET functionality, because that functionality is encapsulated in
managed-code modules that have access to the request pipeline. For
example, even though the .htm file-name extension is not explicitly
mapped to ASP.NET, a request for an HTML page still invokes ASP.NET
modules. This enables you to take advantage of ASP.NET authentication
and authorization for all resources.
The unified pipeline receives the first request for the application. When the unified pipeline receives the first request for any resource in an application, an instance of the ApplicationManager
class is created, which is the application domain that the request is
processed in. Application domains provide isolation between applications
for global variables and enable each application to be unloaded
separately. In the application domain, an instance of the HostingEnvironment
class is created, which provides access to information about the
application, such as the name of the folder where the application is
stored.
During the first request,
top-level items in the application are compiled if required, which
includes application code in the App_Code folder. You can include custom
modules and handlers in the App_Code folder as described in Managed-code Modules in IIS 7.0 later in this topic.
Response objects are created for each request. After the application domain has been created and the HostingEnvironment object has been instantiated, application objects such as HttpContext, HttpRequest, and HttpResponse are created and initialized. The HttpContext class contains objects that are specific to the current application request, such as the HttpRequest and HttpResponse objects. The HttpRequest object contains information about the current request, which includes cookies and browser information. The HttpResponse object contains the response that is sent to the client, which includes all the rendered output and cookies.
The
following are some key differences between IIS 6.0 and IIS 7.0 running
in Integrated mode and with the .NET Framework 3.0 or later:
· The SubStatusCode property of the HttpResponse object is available for setting codes that are useful for failed-request tracing. For more information, see Troubleshooting Failed Requests Using Failed Request Tracing in IIS 7.0.
· The Headers property of the HttpResponse object provides access to response headers for the response.
· Two properties of the HttpContext object, IsPostNotification and CurrentNotification, are used when one event handler handles several HttpApplication events.
· The Headers and ServerVariables property of the HttpRequest object are write-enabled.
An HttpApplication object is assigned to the request After all application objects have been initialized, the application is started by creating an instance of the HttpApplication
class. If the application has a Global.asax file, ASP.NET instead
creates an instance of the Global.asax class that is derived from the HttpApplication class. It then uses the derived class to represent the application.
Note
The first time that an ASP.NET page or process is requested in an application, a new instance of the HttpApplication class is created. However, to maximize performance, HttpApplication instances might be reused for multiple requests.
Which ASP.NET modules are loaded (such as the SessionStateModule)
depends on the managed-code modules that the application inherits from a
parent application. It also depends on which modules are configured in
the configuration section of the application's Web.config file. Modules
are added or removed in the application's Web.config modules element in
the system.webServer section. For more information, see How to: Configure the <system.webServer> Section for IIS 7.0.
The request is processed by the HttpApplication pipeline. The following tasks are performed by the HttpApplication
class while the request is being processed. The events are useful for
page developers who want to run code when key request pipeline events
are raised. They are also useful if you are developing a custom module
and you want the module to be invoked for all requests to the pipeline.
Custom modules implement the IHttpModule interface. In Integrated mode in IIS 7.0, you must register event handlers in a module's Init method.
1.
Validate the request, which examines the information sent by the
browser and determines whether it contains potentially malicious markup.
For more information, see ValidateRequest and Script Exploits Overview.
2. Perform URL mapping, if any URLs have been configured in the UrlMappingsSection section of the Web.config file.
3. Raise the BeginRequest event.
4. Raise the AuthenticateRequest event.
5. Raise the PostAuthenticateRequest event.
6. Raise the AuthorizeRequest event.
7. Raise the PostAuthorizeRequest event.
8. Raise the ResolveRequestCache event.
9. Raise the PostResolveRequestCache event.
10. Raise the MapRequestHandler
event. An appropriate handler is selected based on the file-name
extension of the requested resource. The handler can be a native-code
module such as the IIS 7.0 StaticFileModule or a managed-code module
such as the PageHandlerFactory class (which handles .aspx files).
11. Raise the PostMapRequestHandler event.
12. Raise the AcquireRequestState event.
13. Raise the PostAcquireRequestState event.
14. Raise the PreRequestHandlerExecute event.
15. Call the ProcessRequest method (or the asynchronous version IHttpAsyncHandler.BeginProcessRequest) of the appropriate IHttpHandler class for the request. For example, if the request is for a page, the current page instance handles the request.
16. Raise the PostRequestHandlerExecute event.
17. Raise the ReleaseRequestState event.
18. Raise the PostReleaseRequestState event.
19. Perform response filtering if the Filter property is defined.
20. Raise the UpdateRequestCache event.
21. Raise the PostUpdateRequestCache event.
22. Raise the LogRequest event.
23. Raise the PostLogRequest event.
24. Raise the EndRequest event.
25. Raise the PreSendRequestHeaders event.
26. Raise the PreSendRequestContent event.
Page life cycle in IIS Integrated mode
Ex:
In
Integrated mode, the ASP.NET request-processing stages that are exposed
to modules are directly connected to the corresponding stages of the
IIS 7 pipeline. The complete pipeline contains the following stages,
which are exposed as HttpApplication events in ASP.NET:
1. BeginRequest. The request processing starts.
2. AuthenticateRequest. The request is authenticated. IIS 7 and ASP.NET authentication modules subscribe to this stage to perform authentication.
3. PostAuthenticateRequest.
4. AuthorizeRequest.
The request is authorized. IIS 7 and ASP.NET authorization modules
check whether the authenticated user has access to the resource
requested.
5. PostAuthorizeRequest.
6. ResolveRequestCache.
Cache modules check whether the response to this request exists in the
cache, and return it instead of proceeding with the rest of the
execution path. Both ASP.NET Output Cache and IIS 7 Output Cache
features execute.
7. PostResolveRequestCache.
8. MapRequestHandler. This stage is internal in ASP.NET and is used to determine the request handler.
9. PostMapRequestHandler.
10. AcquireRequestState. The state necessary for the request execution is retrieved. ASP.NET Session State and Profile modules obtain their data.
11. PostAcquireRequestState.
12. PreExecuteRequestHandler. Any tasks before the execution of the handler are performed.
13. ExecuteRequestHandler. The request handler executes. ASPX pages, ASP pages, CGI programs, and static files are served.
14. PostExecuteRequestHandler
15. ReleaseRequestState.
The request state changes are saved, and the state is cleaned up here.
ASP.NET Session State and Profile modules use this stage for cleanup.
16. PostReleaseRequestState.
17. UpdateRequestCache.
The response is stored in the cache for future use. The ASP.NET Output
Cache and IIS 7 Output Cache modules execute to save the response to
their caches.
18. PostUpdateRequestCache.
19. LogRequest. This stage logs the results of the request, and is guaranteed to execute even if errors occur.
20. PostLogRequest.
21. EndRequest. This stage performs any final request cleanup, and is guaranteed to execute even if errors occur.
By
using the familiar ASP.NET APIs, the ability to execute in the same
stages as IIS 7 modules makes tasks that were only previously accessible
in native ISAPI filters and extensions now possible in managed code.
For example, you can now write modules that do the following:
1. Intercept the request before any processing has taken place, for example rewriting URLs or performing security filtering.
2. Replace built-in authentication modes.
3. Modify the incoming request contents, such as request headers.
4. Filter outgoing responses for all content types.
See Developing an IIS 7 Module with .NET for a good example of how to extend IIS 7 with a custom ASP.NET authentication module.
Expanded ASP.NET APIs
The
ASP.NET APIs remain backward compatible with previous releases, which
allows existing modules to work in IIS 7 without modification, and to
apply to all application content without code changes.
However,
modules that are written for IIS 7 Integrated mode can take advantage
of a few additional APIs to enable key request-processing scenarios that
were not previously available.
The new HttpResponse.Headers
collection allows modules to inspect and manipulate response headers
that other application components generate. For example, you can change
the Content-Type header that is generated by an ASP page to prompt a
download dialog box in the browser. The Cookies collection on the
HttpResponse class is also enhanced to allow modification of cookies
that are generated as part of the request processing, even if they were
created outside of ASP.NET.
The HttpRequest.Headers
collection is write-enabled, which allows modules to manipulate the
incoming request headers. Use this to change the behavior of other
server components – for example, you can force a localized application
to respond to the client in a different language by dynamically changing
the value of the Accept-Language header.
Finally, the HttpRequest.ServerVariables
collection is now writeable, which allows IIS 7 server variables to be
set. ASP.NET modules use this functionality to change values that are
provided by IIS 7, and to create new server variables that are visible
to other application frameworks, like PHP.
Runtime Integration
In addition to the new APIs, Integrated mode enables existing ASP.NET functionality to provide more value to your application.
The
tracing facilities that are provided by ASP.NET, including the
System.Diagnostics.Trace class and the ASP.NET page tracing feature, now
emit trace information into the IIS 7 trace system. This enables the
trace information that is generated during request processing by both
IIS 7 and ASP.NET components to be placed in a single log file,
facilitating better diagnostics of server issues.
The
ASP.NET response-filtering feature, which allows responses to be
changed by using a Stream interface before it goes to the client, is
enhanced to allow filtering of non-ASP.NET content. Therefore, you can
use ASP.NET filtering on all server content, or selectively install the
filter only for requests to content that you want to process. With this
capability, you can write filtering features that inject or censor
certain content in the site's responses, regardless of whether this
content comes from an ASPX page or a static file.
Exploring Session in ASP.NET
Introduction
This
article will give you a very good understanding of session. In this
article, I have covered the basics of session, different ways of storing
session objects, session behaviour in web farm scenarios, session on
Load Balancer, etc. I have also explained details of session behaviour
in a live production environment. Hope you will enjoy this article and
provide your valuable suggestions and feedback.
What is Session?
Web is stateless,
which means a new instance of a web page class is re-created each time
the page is posted to the server. As we all know, HTTP is a stateless
protocol, it can't hold client information on a page. If the user
inserts some information and move to the next page, that data will be
lost and the user would not be able to retrieve that information. What
do we need here? We need to store information. Session provides a
facility to store information on server memory. It can support any type
of object to store along with our own custom objects. For every client,
session data is stored separately, which means session data is stored on
a per client basis. Have a look at the following diagram:
Fig: For every client, session data is stored separately
State
management using session is one of the best ASP.NET features, because
it is secure, transparent from users, and we can store any kind of
object in it. Along with these advantages, some times session can cause
performance issues in high traffic sites because it is stored in server
memory and clients read data from the server. Now let's have a look at
the advantages and disadvantages of using session in our web
applications.
Advantages and disadvantages of Session?
Following
are the basic advantages and disadvantages of using session. I have
describe in details with each type of session at later point of time.
Advantages:
· It helps maintain user state and data all over the application.
· It is easy to implement and we can store any kind of object.
· Stores client data separately.
· Session is secure and transparent from the user.
Disadvantages:
· Performance overhead in case of large volumes of data/user, because session data is stored in server memory.
·
Overhead involved in serializing and de-serializing session data,
because in the case of StateServer and SQLServer session modes, we need
to serialize the objects before storing them.
Besides
these, there are many advantages and disadvantages of session that are
based on the session type. I have discussed all of them in the
respective sections below.
Storing and retrieving values from Session
Storing
and retrieving values in session are quite similar to that in
ViewState. We can interact with session state with the
System.Web.SessionState.HttpSessionState class, because this provides
the built-in session object in ASP.NET pages.
The following code is used for storing a value to session:
Collapse | Copy Code
//Storing UserName in Session
Session["UserName"] = txtUser.Text;
Now, let's see how we can retrieve values from session:
Collapse | Copy Code
//Check weather session variable null or not
if (Session["UserName"] != null)
{
//Retrieving UserName from Session
lblWelcome.Text = "Welcome : " + Session["UserName"];
}
else
{
//Do Something else
}
We can also store other objects in session. The following example shows how to store a DataSet in session.
Collapse | Copy Code
//Storing dataset on Session
Session["DataSet"] = _objDataSet;
The following code shows how we to retrieve that DataSet from session:
Collapse | Copy Code
//Check weather session variable null or not
if (Session["DataSet"] != null)
{
//Retrieving UserName from Session
DataSet _MyDs = (DataSet)Session["DataSet"];
}
else
{
//Do Something else
}
References:
· MSDN (read the session variable section)
Session ID
ASP.NET
uses a 120 bit identifier to track each session. This is secure enough
and can't be reverse engineered. When a client communicates with a
server, only the session ID is transmitted between them. When the client
requests for data, ASP.NET looks for the session ID and retrieves the
corresponding data. This is done in the following steps:
· Client hits the web site and information is stored in the session.
· Server creates a unique session ID for that client and stores it in the Session State Provider.
· The client requests for some information with the unique session ID from the server.
· Server looks in the Session Providers and retrieves the serialized data from the state server and type casts the object.
Take a look at the the pictorial flow:
Fig: Communication of client, web server, and State Provider
Session Mode and State Provider
In ASP.NET, there are the following session modes available:
· InProc
· StateServer
· SQLServer
· Custom
For every session state, there is a Session Provider. The following diagram will show you how they are related:
Fig: Session state architecture
We
can choose the session state provider based on which session state we
are selecting. When ASP.NET requests for information based on the
session ID, the session state and its corresponding provider are
responsible for sending the proper information. The following table
shows the session mode along with the provider name:
Session State Mode State Provider
InProc In-memory object
StateServer Aspnet_state.exe
SQLServer Database
Custom Custom provider
Apart from that, there is another mode Off.
If we select this option, the session will be disabled for the
application. But our objective is to use session, so we will look into
the above four session state modes.
Session States
Session
state essentially means all the settings that you have made for your
web application for maintaining the session. Session State itself is a
big thing. It says all about your session configuration, either in the web.config or from the code-behind. In the web.config,
<SessionState> elements are used for setting the configuration of
the session. Some of them are Mode, Timeout, StateConnectionString,
CustomProvider, etc. I have discussed about each and every section of
the connection string. Before I discuss Session Mode, take a brief
overview of session events.
References:
· Application and Session Events
Session Mode
I
have already discussed about session modes in ASP.NET. Following are
the different types of session modes available in ASP.NET:
· Off
· InProc
· StateServer
· SQLServer
· Custom
If we set session Mode="off" in web.config, session will be disabled in the application. For this, we need to configure web.config the following way:
InProc Session Mode
This
is the default session mode in ASP.NET. Its stores session information
in the current Application Domain. This is the best session mode for web
application performance. But the main disadvantage is that, it will
lose data if we restart the server. There are some more advantages and
disadvantages of the InProc session mode. I will come to those points
later on.
Overview of InProc session mode
As
I have already discussed, in InProc mode, session data will be stored
on the current application domain. So it is easily and quickly
available.
InProc
session mode stores its session data in a memory object on the
application domain. This is handled by a worker process in the
application pool. So if we restart the server, we will lose the session
data. If the client request for data, the state provider read the data
from an in-memory object and returns it to the client. In web.config, we have to mention the session mode and also set the timeout.
The above session timeout setting keeps the session alive for 30 minute. This is configurable from the code-behind too.
Collapse | Copy Code
Session.TimeOut=30;
There
are two types of session events available in ASP.NET: Session_Start()
and Session_End and this is the only mode that supports the
Session_End() event. This event is called after the session timeout
period is over. The general flow for the InProc session state is like
this:
When
the Session_End() is called depends on the session timeout. This is a
very fast mechanism because no serialization occurs for storing and
retrieving data, and data stays inside the same application domain.
When should we use the InProc session mode?
InProc
is the default session mode. It can be very helpful for a small web
site and where the number of users is very less. We should avoid InProc
in a Web Garden scenario (I will come to this topic later on).
Advantages and disadvantages
Advantages:
·
It store session data in a memory object of the current application
domain. So accessing data is very fast and data is easily available.
· There is not requirement of serialization to store data in InProc session mode.
· Implementation is very easy, similar to using the ViewState.
Disadvantages:
Although InProc session is the fastest, common, and default mechanism, it has a lot of limitations:
· If the worker process or application domain is recycled, all session data will be lost.
· Though it is the fastest, more session data and more users can affect performance, because of memory usage.
· We can't use it in web garden scenarios.
· This session mode is not suitable for web farm scenarios.
As
per the above discussion, we can conclude that InProc is a very fast
session storing mechanism but suitable only for small web applications.
InProc session data will get lost if we restart the server, or if the
application domain is recycled. It is also not suitable for Web Farm and
Web Garden scenarios.
StateServer Session Mode
Overview of StateServer session mode
This
is also called Out-Proc session mode. StateServer uses a stand-alone
Windows Service which is independent of IIS and can also be run on a
separate server. This session state is totally managed by aspnet_state.exe.
This server may run on the same system, but it's outside of the main
application domain where your web application is running. This means if
you restart your ASP.NET process, your session data will still be alive.
This approaches has several disadvantages due to the overhead of the
serialization and de-serialization involved, it also increases the cost
of data access because every time the user retrieves session data, our
application hits a different process.
Configuration for StateServer session mode
In StateServer mode, session data is stored in a separate server which is independent of IIS and it is handled by aspnet_state.exe. This process is run as a Windows Service. You can start this service from the Windows MMC or from the command prompt.
By default, the "Startup Type" of the ASP.NET state service is set to Manual; we have to set it to Automatic.
From
the command prompt, just type "net start aspnet_state". By default,
this service listens to TCP port 42424, but we can change the port from
the Registry editor as show in the picture below:
Now have a look at the web.config
configuration for the StateServer setting. For the StateServer setting,
we need to specify the stateConnectionString. This will identify the
system that is running the state server. By default,
stateConnectionString used the IP 127.0.0.1 (localhost) and port 42424.
When
we are using StateServer, we can configure the stateNetworkTimeOut
attribute to specify the maximum number of seconds to wait for the
service to respond before canceling the request. The default timeout
value is 10 seconds.
For
using StateServer, the object which we are going to store should be
serialized, and at the time of retrieving, we need to de-serialize it
back. I have described this below with an example.
We
use the StateServer session mode to avoid unnecessary session data loss
when restarting our web server. StateServer is maintained by the aspnet_state.exe
process as a Windows service. This process maintains all the session
data. But we need to serialize the data before storing it in StateServer
session mode.
As
shown in the above figure, when the client sends a request to the web
server, the web server stores the session data on the state server. The
StateServer may be the current system or a different system. But it will
be totally independent of IIS. The destination of the StateServer will
depend on the web.config stateConnectionString setting. If we set
it to 127.0.0.1:42424, it will store data in the local system itself.
For changing the StateServer destination, we need to change the IP, and
make sure aspnet_state.exe is up and running on that system. Otherwise you will get the following exception while trying to store data on session.
When
we are storing an object on session, it should be serialized. That data
will be stored in the StateServer system using the State Provider. And
at the time of retrieving the data, the State Provider will return the
data. The complete flow is given in the picture below:
Example of StateServer Session Mode
Here
is a simple example of using the StateServer session mode. I have
created this sample web application directly on IIS so that we can
easily understand its usage.
Step 1: Open Visual Studio > File > New > Web Sites. Choose Location as HTTP and create the web application.
Now if you open IIS, you will see a virtual directory created with the name of your web application, in my case it is StateServer.
Step 2:
Create s simple UI that will take the roll number and the name of a
student. We will store the name and roll number in a state server
session. I have also created a class StudentInfo. This class is listed
below:
Collapse | Copy Code
[Serializable]
public class StudentInfo
{
//Default Constructor
public StudentInfo()
{
}
/// <summary>
/// Create object of student Class
/// </summary>
/// <param name="intRoll">Int RollNumber</param>
/// <param name="strName">String Name</param>
public StudentInfo(int intRoll, string strName)
{
this.Roll = intRoll;
this.Name = strName;
}
private int intRoll;
private string strName;
public int Roll
{
get
{
return intRoll;
}
set
{
intRoll = value;
}
}
public string Name
{
get
{
return strName;
}
set
{
strName = value;
}
}
}
Now have a look at the code-behind. I have added two buttons: one for storing session and another for retrieving session.
Collapse | Copy Code
protected void btnSubmit_Click(object sender, EventArgs e)
{
StudentInfo _objStudentInfo =
new StudentInfo(Int32.Parse( txtRoll.Text) ,txtUserName.Text);
Session["objStudentInfo"] = _objStudentInfo;
ResetField();
}
protected void btnRestore_Click(object sender, EventArgs e)
{
StudentInfo _objStudentInfo = (StudentInfo) Session["objStudentInfo"];
txtRoll.Text = _objStudentInfo.Roll.ToString();
txtUserName.Text = _objStudentInfo.Name;
}
Step 3: Configure your web.config for state server as I have already explained. And please make sure aspnet_state.exe is up and running on the configured server.
Step 4: Run the application.
Enter the data, click on Submit.
There are the following tests that I have made which will totally explain how exactly StateServer is useful.
First:
Remove the [Serializable ] keyword from the StudentInfo class and try
to run the application. When you click on the Submit button, you will
get the following error:
Which clearly says that you have to serialize the object before storing it.
Second: Run the application, store data by clicking on the Submit button. Restart IIS.
In
the case of InProc, you will have already lost your session data, but
with StateServer, click on Restore Session and you will get your
original data, because StateServer data does not depend on IIS. It keeps
it separately.
Third: Stop aspnet_state.exe from the Windows Services MMC and submit the data. You will get the following error:
because your State Server process is not running. So please keep in mind these three points when using StateServer mode.
Advantages and Disadvantages
Based on the above discussion:
Advantages:
· It keeps data separate from IIS so any issues with IIS will not hamper session data.
· It is useful in web farm and web garden scenarios.
Disadvantages:
· Process is slow due to serialization and de-serialization.
· State Server always needs to be up and running.
I
am stopping here on StateServer, you will find some more interesting
points on it in the Load Balancer, Web Farm, and Web Garden section.
References:
· State Server Session Mode
· ASP.NET Session State
SQLServer Session Mode
Overview of SQL Server Session Mode
This
session mode provide us more secure and reliable session management in
ASP.NET. In this session mode, session data is serialized and stored in A
SQL Server database. The main disadvantage of this session storage
method is the overhead related with data serialization and
de-serialization. It is the best option for using in web farms though.
To setup SQL Server, we need these SQL scripts:
· For installing: InstallSqlState.sql
· For uninstalling: UninstallSQLState.sql
The easiest way to configure SQL Server is using the aspnet_regsql command.
I
have explained in detail the use of these files in the configuration
section. This is the most useful state management in web farm scenarios.
When should we use SQLServer Session Mode?
· SQL Server session mode is a more reliable and secure session state management.
· It keeps data in a centralized location (database).
· We should use the SQLServer session mode when we need to implement session with more security.
· If there happens to be frequent server restarts, this is an ideal choice.
· This is the perfect mode for web farm and web garden scenarios (I have explained this in detail later).
· We can use SQLServer session mode when we need to share session between two different applications.
Configuration for SQLServer Session Mode
In SQLServer session mode, we store session data in SQL Server, so we need to first provide the database connection string in web.config. The sqlConnectionString attribute is used for this.
After
we setup the connection string, we need to configure the SQL Server. I
will now explain how to configure your your SQL Server using the aspnet_regsql command.
Step 1: From command prompt, go to your Framework version directory. E.g.: c:\windows\microsoft.net\framework\<version>.
Step 2: Run the aspnet_regsql command with the following parameters:
Have a look at the parameters and their uses:
Parameters Description
-ssadd Add support for SQLServer mode session state.
-sstype p P stands for Persisted. It persists the session data on the server.
-S Server name.
-U User name.
-P Password.
After you run the command, you will get the following message:
That's all.
Step 3: Open SQL Server Management Studio, check if a new database ASPState has been created, and there should be two tables:
· ASPStateTempApplications
· ASPStateTempSessions
Change the configuration string of the StateServer example and run the same sample application.
Just store the roll number and user name and click on the Submit button. Open the ASPStateTempSessions table from SQL Server Management Studio.. here is your session data:
Now do the following test that I have already explained in the StateServer mode section:
1. Remove the Serialize keyword from the StydentInfo class
2. Reset IIS and click on Restore Session
3. Stop SQL Server Services
I think I have explained the SQLServer session mode well.
Advantages and Disadvantages
Advantages:
· Session data not affected if we restart IIS.
· The most reliable and secure session management.
· It keeps data located centrally, is easily accessible from other applications.
· Very useful in web farms and web garden scenarios.
Disadvantages:
· Processing is very slow in nature.
· Object serialization and de-serialization creates overhead for the application.
· As the session data is handled in a different server, we have to take care of SQL Server. It should be always up and running.
References:
· Read more about SQLServer mode
Custom Session Mode
Commonly
we use the InProc, StateServer, or SQLServer session modes for our
application, but we also need to know the fundamentals of the Custom
session mode. This session mode is quite interesting, because Custom
session gives full control to us to create everything, even the session
ID. You can write your own algorithm to generate session IDs.
You
can implement custom providers that store session data in other storage
mechanisms simply by deriving from the SessionStateStoreProviderBase
class. You can also generate a new session ID by implementing
ISessionIDManager.
These are the methods called during the implementation of Custom session:
In
the Initialize method, we can set a custom provider. This will
initialize the connection with that provider. SetItemExpireCallback is
used to set SessionTimeOut. We can register a method that will be called
at the time of session expiration. InitializeRequest is called on every
request and CreateNewStoreData is used to create a new instance of
SessionStateStoreData.
We can use Custom session mode in the following cases:
· We want to store session data in a place other than SQL Server.
· When we have to use an existing table to store session data.
· When we need to create our own session ID.
We need to configure our web.config like this:
If you want to explore this more, please check the References section.
Advantages and Disadvantages
Advantages:
· We can use an existing table for storing session data. This is useful when we have to use an existing database.
· It's not dependent on IIS, so restarting the web server does not have any effect on session data.
· We can crate our own algorithm for generating session ID.
Disadvantages:
· Processing of data is very slow.
· Creating a custom state provider is a low-level task that needs to be handled carefully to ensure security.
It is always recommended to use a third party provider rather than create your own.
References:
Overview of production deployment
Production
environments are where we deploy our applications on a live production
server. It is a major and big challenge for web developers to deploy
their applications on a live server, because in a big production
environment, there are a large number of users and it is hard to handle
the load for so many users with a single server. Here comes in the
concepts of Web Farm, Load Balancer, Web Garden, etc.
Just
a few months back, I deployed a web application in a live production
environment which is accessed by millions of user and there were more
than 10 Active Directory instances, more than 10 web servers over a Load
Balancer, and several database server, Exchange Server, LCS Server,
etc. The major risk involved in multiple servers is session management.
The following picture shows a general diagram of production
environments:
I will try to explain the different scenarios that you need to keep in mind while deploying your application.
Application Pool
This
is one of the most important things you should create for your
applications in a production environment. Application pools are used to
separate sets of IIS worker processes that share the same configuration.
Application pools enable us to isolate our web application for better
security, reliability, and availability. The worker process serves as
the process boundary that separates each application pool so that when
one worker process or application has an issue or is recycled, other
applications or worker processes are not affected.
Identity of Application Pool
Application
pool identity configuration is an important aspect of security in IIS
6.0 and IIS 7.0, because it determines the identity of the worker
process when the process is accessing a resource. In IIS 7.0, there are
three predefined identities that are the same as in IIS 6.0.
Application Pool Identity Description
LocalSystem Built-in
account that has administrative privileges on the server. It can access
both local and remote resources. For any kind accessing of server files
or resources, we have to set the identity of the application pool to
LocalSystem.
LocalServices Built-in account has privileges of an authenticated local user account. It does not have any network access permission.
NetworkServices This is the default identity of Application Pool. NetworkServices has the privileges of an authenticated local user account.
Open IIS Console, right click on Application Pool Folder > Create New.
Give the Application Pool ID and click OK.
Now,
right click on the Virtual Directory (I am using StateServer web sites)
and assign StateServerAppPool to the StateServer Virtual Directory.
So
this StateServer web site will run independently with
StateServerAppPool. Any problem related with other applications will not
affect this application. This is the main advantage of creating
application pools separately.
Web Garden
By default, each application pool runs with a single worker process (W3Wp.exe).
We can assign multiple worker processes with a single application pool.
An application pool with multiple worker processes is called a Web
Garden. Many worker processes with the same Application Pool can
sometimes provide better throughput performance and application response
time. And each worker process should have its own Thread and memory
space.
As
shown in the picture, in IIS, there may be multiple application pools
and each application pool will have at least one worker process. A Web
Garden should contain multiple worker processes.
There
are certain restrictions in using a Web Garden with your web
application. If we use the InProc session mode, our application will not
work correctly because the session will be handled by a different
worker process. To avoid this problem, we should use the OutProc session
mode and we can use a session state server or SQL-Server session state.
Main advantage:
The worker processes in a Web Garden share the requests that arrive for
that particular application pool. If a worker process fails, another
worker process can continue processing the requests.
Right click on Application Pool > Go to Performance tab > Check Web Garden section (highlighted in picture):
By default, it would be 1. Just change it to more than one.
I
have already explained that InProc is handled by a worker process. It
keeps data inside its memory object. Now if we have multiple worker
processes, then it would be very difficult to handle the session because
each and every worker process has its own memory, so if my first
request goes to WP1 and it keeps my session data and the second request
goes to WP2, I am trying to retrieve session data and it will not be
available, which will throw an error. So please avoid Web Gardens in
InProc session mode.
We
can use StateServer or SQLServer session modes in Web Gardens because as
I have already explained, these two session modes do not depend on
worker processes. In my example, I have also explained that if you
restart IIS, you are still able to access your session data.
In short:
Session Mode Recommended
InProc No
StateServer Yes
SQLServer Yes
Web Farm and Load Balancer
This
is the most common terms that are used in production deployments. These
terms come in when we are using multiple web servers for deploying our
applications. The main reason for using these is we have to distribute
the load over multiple servers. A Load Balancer is used to distribute
the load on multiple servers.
If
we take a look at the above diagram, the client request the URL and it
will hit a Load Balancer, which decides which server to access. The load
balancer will distribute the traffic over all the different web
servers.
Now how does this affect Session?
Handling session is one of the most challenging jobs in a web farm.
InProc:
In InProc session mode, session data is stored in an in-memory object
of the worker process. Each server will have its own worker process and
will keep session data inside its memory.
If
one server is down, and if the request goes to a different server, the
user is not able to get session data. So it is not recommended to use
InProc in Web Farms.
StateServer:
I have already explained what a state server is and how to configure a
state server, etc. For web farm scenarios, you can easily understand how
much this is important because all session data will be stored in a
single location.
Remember,
in a web farm, you have to make sure you have the same
<machinekey> in all your web servers. Other things are the same as
I have describe earlier. All web.config files will have the same configuration (stateConnectionString) for session state.
SQL Server:
This is another approach, the best that we can use in a web farm. We
need to configure the database first. The required steps have been
explained covered.
As
shown in the above picture, all web server session data will be stored
in a single SQL Server database. And it is easily accessible. Keep one
thing in mind, you should serialize objects in both StateServer and
SQLServer modes. If one of the web servers go down, the load balancer
will distribute the load to other servers and the user will still be
able to read session data from the server, because data is stored in a
centralized database server.
In summary, we can use either StateServer or SQLServer session mode in a web farm. We should avoid InProc.
Session and Cookies
Clients
use cookies to work with session. Because clients need to present the
appropriate session ID with each request. We can do this in the
following ways:
Using cookies
ASP.NET
creates a special cookie named ASP.NET_SessionId automatically when a
session collection is used. This is the default. Session ID is
transmitted through that cookie.
cookie is a small bit of text that accompanies requests and pages as
they go between the Web server and browser. The cookie contains
information the Web application can read whenever the user visits the
site.
For example, if a
user requests a page from your site and your application sends not just a
page, but also a cookie containing the date and time, when the user's
browser gets the page, the browser also gets the cookie, which it stores
in a folder on the user's hard disk.
Later,
if user requests a page from your site again, when the user enters the
URL the browser looks on the local hard disk for a cookie associated
with the URL. If the cookie exists, the browser sends the cookie to your
site along with the page request. Your application can then determine
the date and time that the user last visited the site. You might use the
information to display a message to the user or check an expiration
date.
Cookies are
associated with a Web site, not with a specific page, so the browser and
server will exchange cookie information no matter what page the user
requests from your site. As the user visits different sites, each site
might send a cookie to the user's browser as well; the browser stores
all the cookies separately.
Cookies
help Web sites store information about visitors. More generally,
cookies are one way of maintaining continuity in a Web application—that
is, of performing state management. Except for the brief time when they
are actually exchanging information, the browser and Web server are
disconnected. Each request a user makes to a Web server is treated
independently of any other request. Many times, however, it's useful for
the Web server to recognize users when they request a page. For
example, the Web server on a shopping site keeps track of individual
shoppers so the site can manage shopping carts and other user-specific
information. A cookie therefore acts as a kind of calling card,
presenting pertinent identification that helps an application know how
to proceed.
Cookies are
used for many purposes, all relating to helping the Web site remember
users. For example, a site conducting a poll might use a cookie simply
as a Boolean value to indicate whether a user's browser has already
participated in voting so that the user cannot vote twice. A site that
asks a user to log on might use a cookie to record that the user already
logged on so that the user does not have to keep entering credentials.
Cookie Limitations
Most
browsers support cookies of up to 4096 bytes. Because of this small
limit, cookies are best used to store small amounts of data, or better
yet, an identifier such as a user ID. The user ID can then be used to
identify the user and read user information from a database or other
data store. (See the section "Cookies and Security" below for
information about security implications of storing user information.)
Browsers
also impose limitations on how many cookies your site can store on the
user's computer. Most browsers allow only 20 cookies per site; if you
try to store more, the oldest cookies are discarded. Some browsers also
put an absolute limit, usually 300, on the number of cookies they will
accept from all sites combined.
A
cookie limitation that you might encounter is that users can set their
browser to refuse cookies. If you define a P3P privacy policy and place
it in the root of your Web site, more browsers will accept cookies from
your site. However, you might have to avoid cookies altogether and use a
different mechanism to store user-specific information. A common method
for storing user information is session state, but session state
depends on cookies, as explained later in the section "Cookies and
Session State."
Writing Cookies
The browser is responsible for managing cookies on a user system. Cookies are sent to the browser via the HttpResponse object that exposes a collection called Cookies. You can access the HttpResponse object as the Response property of your Page
class. Any cookies that you want to send to the browser must be added
to this collection. When creating a cookie, you specify a Name and Value.
Each cookie must have a unique name so that it can be identified later
when reading it from the browser. Because cookies are stored by name,
naming two cookies the same will cause one to be overwritten.
You
can also set a cookie's date and time expiration. Expired cookies are
deleted by the browser when a user visits the site that wrote the
cookies. The expiration of a cookie should be set for as long as your
application considers the cookie value to be valid. For a cookie to
effectively never expire, you can set the expiration date to be 50 years
from now.
Cookies with More Than One Value
You
can store one value in a cookie, such as user name and last visit. You
can also store multiple name-value pairs in a single cookie. The
name-value pairs are referred to as subkeys. (Subkeys are laid out much
like a query string in a URL.) For example, instead of creating two
separate cookies named userName and lastVisit, you can create a single
cookie named userInfo that has the subkeys userName and lastVisit.
You
might use subkeys for several reasons. First, it is convenient to put
related or similar information into a single cookie. In addition,
because all the information is in a single cookie, cookie attributes
such as expiration apply to all the information. (Conversely, if you
want to assign different expiration dates to different types of
information, you should store the information in separate cookies.)
Reading Cookies
When
a browser makes a request to the server, it sends the cookies for that
server along with the request. In your ASP.NET applications, you can
read the cookies using the HttpRequest object, which is available as the Request property of your Page class. The structure of the HttpRequest object is essentially the same as that of the HttpResponse object, so you can read cookies out of the HttpRequest object much the same way you wrote cookies into the HttpResponse object. The following code example shows two ways to get the value of a cookie named username and display its value in a Label control:
Cookie munging
Some
older browsers do not support cookies or the user may disable cookies
in the browser, in that case, ASP.NET transmits session ID in a
specially modified (or “munged”) URL.
When
the user requests for a page on a server, the server encoded the
session ID and adds it with every HREF link in the page. When the user
clicks on a link, ASP.NET decodes that session ID and passes it to the
page that the user is requesting. Now the requesting page can retrieve
session variables. This all happens automatically if ASP.NET detects
that the user's browser does not support cookies.
For this, we have to make our session state cookie-less.
Ex: <SesstionState Cookieless=”true”></SesstionState>
Removing Session
Following are the list of methods that are used to remove Session:
Method Description
Session.Remove(strSessionName); Removes an item from the session state collection.
Session.RemoveAll() Removes all items from the session collection.
Session.Clear() Remove
all items from session collection. Note: There is no difference between
Clear and RemoveAll. RemoveAll() calls Clear() internally.
Session.Abandon() Cancels the current session.
Enabling and disabling Session
For
performance optimization, we can enable or disable session because each
and every page read and write access of the page involves some
performance overhead. So it is always better to enable and disable
session based on requirements rather than enable it always. We can
enable and disable session state in two ways:
· Page level
· Application level
Page level
We can disable session state in page level using the EnableSessionState attribute in the Page directive.
This will disable the session activities for that particular page.
The same way, we can make it read-only also. This will permit to access session data but will not allow writing data on session.
Application level
Session state can be disabled for the entire web application using the EnableSessionState property in Web.Config.
Generally we use page level because some pages may not require any session data or may only read session data.
Introduction
This article is a
beginner's tutorial on ASP.NET caching mechanism. We will try to see
different types of caching available in ASP.NET and which caching
technique is right for which scenario. We will also try to see how can
we customize the caching behaviour so that it suits our needs.
Background
As
ASP.NET web developers, we are mostly involved in developing web pages
that are dynamic, i.e., contents coming from databases, Server
directories, XML files or getting pulled from some other websites.
Caching means to store something in memory that is being used frequently
to provide better performance. Now can we think of the usability of
caching in ASP.NET.
Let us
imagine a scenario when the contents of a web page are being pulled
from a database. The user asks for contents depending on some criteria.
Now if the database is getting changed very frequently that even between
two requests of same user, we anticipate database change, then we can
in no way cache the data that the user is requesting. But if the
database is not getting changed that frequently, we can have some
caching in place so that if the user is requesting the same data very
frequently, we don't hit the database every time (since we know contents
are not changed).
The two
keys terms here are frequency and criteria. Frequency is the number of
times we are anticipating the user requests for a particular page and
criteria is what governs the uniqueness of result that is being
displayed on the page.
Frequency
is important because we need to figure out the interval in which
database is changing and compare it with the frequency of user requests
so that we can have caching in place and also make sure that user is not
viewing out dated data.
Criteria
is important because we need to make sure that we have caching
implemented for the page on every unique criteria. It should not be the
case that user is requesting contents based on criteria01
and we are showing him the cached results of criteria00
(cached earlier for him).
So
with all this theory in mind, let's go ahead and see how ASP.NET
provides caching features without us writing a lot of code to manage the
same.
Types of Caching
There are two types of caching available in ASP.NET:
1. Page Output Caching
2. Application Caching
Page Output Caching
Page
output caching refer to the ability of the web server to cache a
certain webpage after user request in its memory so that further
requests for the same page will check for the cached page's validity and
will not result in resource usage (DB access or file access) and the
page will be returned to user from cache.
Now
the question is how can we ensure that the user is not viewing the out
dated data. ASP.NET provides us various configuration options which will
let us program in such a way that we can ensure that the user never
gets stale data.
Let us
have a simple web page with a textbox, button and a label. Right now,
the caching is not enabled for this page so everytime the postback
occurs, the request to the web server is made. We can verify this by
displaying the current time in the label.
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
}
Now let us go ahead and enable caching for this page by adding the following declaration to the page:
<%@ OutputCache Duration="30" VaryByParam="none" %>
Here
we are saying that this page should be cached for 30 seconds, We can
verify this by pressing the button. The time string will not change for
30 seconds and the second property VaryByParam
specifies that caching doesn't depend on anything doing so can lead to a
situation where user can see stale data, like in our case for 30
seconds if we write something in textbox and do a postback, it will keep
reverting to the old data that was in the textbox at the time page was
cached.
So it's a good idea to say that the cached page is not valid if the data in textbox is changed so let's do that now:
<%@ OutputCache Duration="30" VaryByParam="TextBox1" %>
So now we can see that the page output will be cached as long as the contents of the textbox
are not changed. If we change the contents of the textbox
, then the server processes the page again and then caches it again.
So what we saw is that we can specify the Duration
the page should be cached which is related to the talk about frequency we did earlier. The Duration
should be chosen so that during that time we are not expecting any change in data and for the criteria, we saw how we can use VaryByCustom
to make sure that the output for every different criteria is generated and the cached copy is not just presented to the user.
Let us look as some other parameters that we can use to customize caching behavior.
· VaryByParam
: List of string
s that are sent to server via POST
that are checked to validate cache
· VaryByControl
: List of controls whose value will determine the validity of cache
· SqlDependency
: Defines the Database-tablename pair on which the validity of cache depends
· VaryByCustom
: Used for custom output cache requirements
· VaryByHeader
: HTTPs header that determines the cache validity
If we need different output pages based on query string
, then we can specify the list of querystring
parameters here or we can simply say VaryByParam ="*"
to do the same for all querystring
parameters. Now let us just have a quick look at what we need to do if we need to change the cached page based on query string
parameter.
<%@ OutputCache Duration="30" VaryByParam="name" %>
protected void Button2_Click(object sender, EventArgs e)
{
int name;
if (Request.QueryString["name"] == null)
{
name = 1;
}
else
{
name = Convert.ToInt32(Request.QueryString["name"]) + 1;
}
Response.Redirect("varybyqs.aspx?name=" + name.ToString());
}
In order to cache a page's output, we need to specify an @OutputCache
directive at the top of the page. The syntax is as shown below:
<%@ OutputCache Duration=5 VaryByParam="None" %>
As you can see, there are two attributes to this directive. They are:
Duration
- The time in seconds of how long the output should be cached. After
the specified duration has elapsed, the cached output will be removed
and page content generated for the next request. That output will again
be cached for 10 seconds and the process repeats.
VaryByParam
- This attribute is compulsory and specifies the querystring parameters to vary the cache.
In the above snippet, we have specified the VaryByParam
attribute as None
which means the page content to be served is the same regardless of the
parameters passed through the querystring [see Example 1 in the sample
download].
If there are two requests to the same page with varying querystring parameters, e.g.: .../PageCachingByParam.aspx?id=12 and .../PageCachingByParam.aspx?id=15] and separate page content is generated for each of them, the directive should be:
<%@ OutputCache Duration=5 VaryByParam="id" %>
The page content for the two requests will each be cached for the time specified by the Duration
attribute [see Example 2 in the sample download].
To specify multiple parameters, use semicolon to separate the parameter names. If we specify the VaryByParam
attribute as *
, the cached content is varied for all parameters passed through the querystring.
Some
pages generate different content for different browsers. In such cases,
there is provision to vary the cached output for different browsers.
The @OutputCache
directive has to be modified to:
<%@ OutputCache Duration=5 VaryByParam="id" VaryByCustom="browser" %>
This
will vary the cached output not only for the browser but also its major
version. I.e., IE5, IE 6, Netscape 4, Netscape 6 will all get different
cached versions of the output.
Partial Page Caching (or) Fragment Caching
Sometimes
we might want to cache just portions of a page. For example, we might
have a header for our page which will have the same content for all
users. There might be some text/image in the header which might change
everyday. In that case, we will want to cache this header for a duration
of a day.
The solution
is to put the header contents into a user control and then specify that
the user control content should be cached. This technique is called fragment caching.
To specify that a user control should be cached, we use the @OutputCache
directive just like we used it for the page.
<%@ OutputCache Duration=10 VaryByParam="None" %>
With the above directive, the user control content will be cached for the time specified by the Duration
attribute [10 secs]. Regardless of the querystring parameters and
browser type and/or version, the same cached output is served. [See
Example 3 in the download for a demonstration].
Similar
to output caching, partial page caching allows you to cache certain
blocks of your website. You can, for example, only cache the center of
the page. Partial page caching is achieved with the caching of user
controls. You can build your ASP.NET pages consisting of numerous user
controls and then apply output caching on the user controls you select.
This will cache only parts of the page that you want, leaving other
parts of the page outside the reach of caching. This is a very nice
feature, and if done correctly, it can lead to pages that perform
better.
Note: Typically,
UserControls are placed on multiple pages to maximize reuse. However,
when these UserControls (ASCX files) are cached with the @OutputCache
directive, they are cached on a per page basis. That means even if a User Control outputs identical HTML when placed on pageA.aspx as it does when placed on pageB.aspx, its output is cached twice. You can prevent this happening by adding Shared = true
in the output cache directive.
<%@ OutputCache Duration="300" VaryByParam="*" Shared="true" %>
By putting the Shared
attributed, the memory savings can be surprisingly large. If you have an ASCX User control using the OutputCache
directive, remember that the User Control exists only for the first request.
Also,
if we have a requirement for partial page caching (Fragment caching),
we can simply use the controls that require caching and put them in a
user control. We can then use the same above mentioned technique to
enable caching behaviour in the custom control and we have partial page
caching in place. (See the code for implementation.)
Note:
The above mentioned approaches enabled us to use caching by using
declarations on the page. We can also control caching programmatically.
Application Data Caching
Output caching and partial page caching is useful if you want to cache the output of a page. However, if you like to cache a DataSet
object or any collection object, you can use data caching to implement that.
ASP.NET has a class called Cache
to cache specific data items for later use on a particular page or group of pages. The Cache
enables you to store everything from simple name/value pairs to more complex objects like datasets and entire aspx pages.
To store data into the cache, you can use the code below:
C#
Cache["MyDataSet"] = myDataSet;
To retrieve data from the cache, you can use the code below:
C#
DataSet ds = new DataSet();
ds = (DataSet) Cache["MyDataSet"];
Application data caching is a mechanism for storing the Data
objects on cache. It has nothing to do with the page caching. ASP.NET allows us to store the object in a Key
-Value
based cache. We can use this to store the data that need to cached. Let us work on the same example and try to store the DateTime
object in the Application Cache now.
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
Cache["time"] = DateTime.Now;
}
Label1.Text = ((DateTime)Cache["time"]).ToLongTimeString();
}
What this code will do is that it will store the DateTime
object in application cache and will keep displaying the time of initial request by using the object from the cache.
There are various parameters associated with application data caching that can be used to control its behavior.
· Dependencies
: Any file or item in cache that invalidates this cache item
· absoluteExpiration
: Absolute time when this object should be removed from cache
· slidingExpiration
: Relative time when this object should be removed from the cache
· priority
:
Defines the priority of the item. This is useful when server runs out
of memory as in that case it start removing items from cache with lowest
priority first
· onRemoveCallBack
:
This is the event handler that will be called when the object is
removed from cache. It gives us a place to take further actions.
Understanding Asp.net Cache Sliding Expiration and Absolute Expiration
Asp .Net provides two different ways to expire the cache on the basis of time. Here are two approaches:-
- Sliding Expiration
- Absolute Expiration
1. Absolute Expiration
Absolute
expiration means that your data will be removed from cache after fixed
amount of time either it is accessed or not. Generally we use it when we
are displaying data which is changing but we can afford to display
outdated data in our pages. Mostly I put all of my dropdown values in
cache with Absolute Expiration. Here is how you can code:-
DataTable dt = GetDataFromDatabase();
Cache.Insert("AbsoluteCacheKey", dt, null,
DateTime.Now.AddMinutes(1), //Data will expire after 1 minute
System.Web.Caching.Cache.NoSlidingExpiration);
2. Sliding Expiration
Sliding
expiration means that your data will be removed from cache if that is
not accessed for certain amount of time. Generally we store that data in
this cache mode which is accessed many time on certain occasions. For
example if you go in account settings section of a site, then you will
be frequently accessing account information in that section. But most of
the time you wont be using account setting's related data so there is
no point of storing that data in cache. In such scenarios sliding
expiration should be used. here is how you can save data in cache with
sliding expiration:-
DataTable dt = GetDataFromDatabase();
Cache.Insert("SlidingExpiration", data, null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
TimeSpan.FromMinutes(1));//Data will be cached for 1 mins
What is state management?
Web is Stateless
. It means a new instance of the web page class is re-created each time the page is posted to the server. As we all know HTTP
is a stateless protocol, its can't holds the client information on
page. As for example , if we enter a text and client on submit button,
text does not appear after post back , only because of page is recreated
on its round trip.
As
given in above pages, page is recreated before its comes to clients and
happened for each and every request. So it is a big issue to maintain
the state of the page and information for a web application. That is the
reason to start concept of State Management
. To overcome this problem ASP.NET 2.0 Provides some features like View State, Cookies, Session, Application objects
etc. to manage the state of page.
There
are some few selection criteria to selected proper way to maintain the
state, as there are many way to do that. Those criteria are:
· How much information do you need to store?
· Does the client accept persistent or in-memory cookies?
· Do you want to store the information on the client or on the server?
· Is the information sensitive?
· What performance and bandwidth criteria do you have for your application?
· What are the capabilities of the browsers and devices that you are targeting?
· Do you need to store information per user?
· How long do you need to store the information?
·
Do you have a Web farm (multiple servers), a Web garden (multiple
processes on one machine), or a single process that serves the
application?
So,
when ever you start to think about state management, you should think
about above criteria. based on that you can choose the best approaches
for manages state for your web application.
Different types of state management?
There are two different types of state management:
1. Client Side State Management
-
o
View State
-
o
Hidden Field
-
o
Cookies
-
o
Control State
2. Server Side State Management
-
o
Session
-
o
Application Object
-
o
Caching
-
o
Database
Client
Side state management does not use any server resource , it store
information using client side option. Server Side state management use
server side resource for store data. Selection of client side and server
side state management should be based on your requirements and the
selection criteria that are already given.
What is view state?
View State
is one of the most important and useful client side state management mechanism. It can store the page value at the time of post back (Sending and Receiving information from Server)
of
your page. ASP.NET pages provide the ViewState property as a built-in
structure for automatically storing values between multiple requests for
the same page.
Example:
If you want to add one variable in View State,
ViewState["Var"]=Count;
For Retrieving information from View State
string Test=ViewState["TestVal"];
Sometimes
you may need to typecast ViewState Value to retreive. As I give an
Example to strore and retreive object in view state in the last of
this article.
Advantages of view state?
This are the main advantage of using View State:
· Easy to implement
· No server resources are required
· Enhanced security features ,like it can be encoded and compressed.
Disadvantages of view state?
This are the main disadvantages of using View State:
· It can be performance overhead if we are going to store larger amount of data , because it is associated with page only.
· Its stored in a hidden filed in hashed format (which I have discussed later) still it can be easily trapped.
· It does not have any support on mobile devices.
When we should use view state?
I
already describe the criteria of selecting State management. A few
point you should remember when you select view state for maintain your
page state.
·
Size of data should be small , because data are bind with page controls
, so for larger amount of data it can be cause of performance overhead.
· Try to avoid storing secure data in view state
When we should avoid view state?
You won't need view state for a control for following cases,
· The control never change
· The control is repopulated on every postback
· The control is an input control and it changes only of user actions.
Where is view state stored?
View
State stored the value of page controls as a string which is hashed and
encoded in some hashing and encoding technology. It only contain
information about page and its controls. Its does not have any
interaction with server. It stays along with the page in the Client
Browser. View State use Hidden
field to store its information in a encoding format.
Suppose you have written a simple code , to store a value of control:
ViewState["Value"] = MyControl.Text;
Now, Run you application, In Browser, RighClick
> View
Source
, You will get the following section of code
Fig : View state stored in hidden field
Now
, look at the value. looks likes a encrypted string, This is Base64
Encoded string, this is not a encoded string. So it can easily be
decoded. Base64 makes a string suitable for HTTP transfer plus it makes
it a little hard to read . Read More about Base64 Encoding . Any body can decode that string and read the original value. so be careful about that. There is a security lack
of view state.
How to store object in view state?
We
can store an object easily as we can store string or integer type
variable. But what we need ? we need to convert it into stream of byte.
because as I already said , view state store information in hidden filed
in the page. So we need to use Serialization
. If object which we are trying to store in view state ,are not serializable , then we will get a error message .
Just take as example,
//Create a simple class and make it as Serializable
[Serializable]
public class student
{
public int Roll;
public string Name;
public void AddStudent(int intRoll,int strName)
{
this.Roll=intRoll;
this.Name=strName;
}
}
Now we will try to store object of "Student
" Class in a view state.
//Store Student Class in View State
student _objStudent = new student();
_objStudent.AddStudent(2, "Abhijit");
ViewState["StudentObject"] = _objStudent;
//Retrieve Student information view state
student _objStudent;
_objStudent = (student)ViewState["StudentObject"];
How to trace your view state information?
If you want to trace your view state information, by just enable "Trace
" option of Page Directive
Now Run your web application, You can view the details of View State Size along with control ID in Control Tree
Section. Don't worry about "Render Size Byte
" , this only the size of rendered control.
Fig : View State Details
Enabling and Disabling View State
You
can enable and disable View state for a single control as well as at
page level also. To turnoff view state for a single control , set Enable
ViewState Property of that control to false. e.g.:
TextBox1.EnableViewState =false;
To turnoff the view state of entire page, we need to set Enable
ViewState to false of Page Directive as shown bellow.
Even
you disable view state for the entire page , you will see the hidden
view state tag with a small amount of information, ASP.NET always store
the controls hierarchy for the page at minimum , even if view state is
disabled.
For enabling the same, you have to use the same property just set them as True
as for example, for a single control we can enabled view state in following way,
TextBox1.EnableViewState =true;
and for a page level,
How to make view state secure?
As I already discuss View state information is stored in a hidden filed in a form of Base64 Encoding
String, and it looks like:
Fig : View state stored in hidden field
Many of ASP.NET Programmers assume that this is an Encrypted format
, but I am saying it again, that this is not a encrypted string. It can be break easily. To make your view state secure, There are two option for that,
· First, you can make sure that the view state information is tamper-proof by using "hash code"
. You can do this by adding "Enable
ViewStateMAC=true
" with your page directive. MAC Stands for "Message Authentication Code"
A hash code
, is a cryptographically strong checksum
,
which is calculated by ASP.NET and its added with the view state
content and stored in hidden filed. At the time of next post back, the
checksum data again verified , if there are some mismatch, Post back
will be rejected. we can set this property to web.config file also.
· Second option is to set ViewStateEncryptionMode="Always"
with your page directives, which will encrypt the view state data. You can add this in following way
It ViewStateEncryptionMode
has three different options to set:
· Always
· Auto
· Never
Always
, mean encrypt the view state always, Never
means, Never encrypt the view state data and Auto
Says , encrypt if any control request specially for encryption. For auto , control must call Page.RegisterRequires
ViewStateEncryption()
method for request encryption.
we can set the Setting for "Enable
ViewStateMAC"
and ViewStateEncryptionMode"
in web.config also.
Note :
Try to avoid View State Encryption if not necessary , because it cause the performance issue
ASP.NET Page Life Cycle with State Management objects
Introducing Viewstate Outside the ASP.NET Context
In its very basic form, Viewstate is nothing more than a property which has a key/value pair indexer:
Viewstate[“mystringvariable”] = “myvalue”;
Viewstate[“myintegervariable”] = 1;
As you can see, the indexer accepts a string as a key and an object as the value. The ViewState property is defined in the “System.Web.UI.Control
”
class. Since all ASP.NET pages and controls derive from this class,
they all have access to the ViewState property. The type of the
ViewState property is “System.Web.UI.StateBag
”.
The very special thing about the StateBag
class is the ability to “track changes”. Tracking is, by nature, off; it can be turned on by calling the “Track
ViewState()
” method. Once tracking is on, it cannot be turned off. Only when tracking is on, any change to the StateBag
value will cause that item to be marked as “Dirty
”.
Info: In case you are wondering (and you should be) about the reason behind this “tracking” behavior of the StateBag
, do not worry; this will be explained in detail along with examples about how tracking works, in the next sections.
Introducing Viewstate Inside the ASP.NET Context
When
dealt within the context of ASP.NET, the Viewstate can be defined as
the technique used by an ASP.NET web page to remember the change of
state spanning multiple requests. As you know, ASP.NET is a stateless
technology; meaning that two different requests (two postbacks) to the
same web page are considered completely unrelated. This raises the need
of a mechanism to track the change of state for this web page between
the first and the second request.
The Viewstate of an ASP.NET page is created during the page life cycle, and saved into the rendered HTML using in the “__
VIEWSTATE” hidden HTML field. The value stored in the “__
VIEWSTATE” hidden field is the result of serialization of two types of data:
1. Any programmatic change of state of the ASP.NET page and its controls. (Tracking and “Dirty
” items come into play here. This will be detailed later.)
2. Any data stored by the developer using the Viewstate property described previously.
This value is loaded during postbacks, and is used to preserve the state of the web page.
Info:
The process of creating and loading the Viewstate during the page life
cycle will be explained in detail later. Moreover, what type of
information is saved in the Viewstate is also to be deeply discussed.
One
final thing to be explained here is the fact that ASP.NET server
controls use Viewstate to store the values of their properties. What
does this mean? Well, if you take a look at the source code of the TextBox
server control, for example, you will find that the “Text
” property is defined like this:
public string Text
{
get { return (string)ViewState["Text"]; }
set { ViewState["Text"] = value; }
}
You should apply this rule when developing your own server controls. Now, this does not mean that the value of the “Text
” property set at design time is saved in the rendered serialized ViewState field. For example, if you add the following TextBox
to your ASP.NET page:
<asp:TextBox runat="server" ID="txt" Text="sometext" />
According to the fact that the “Text
” property uses Viewstate to store its value, you might think that the value is actually serialized in the __
VIEWSTATE hidden field. This is wrong because the data serialized in the hidden __
VIEWSTATE consists only of state changes done programmatically. Design time data is not serialized into the __
VIEWSTATE (more on this later). For now, just know that the above declaration of the “Text
” property means that it is utilizing Viewstate in its basic form: an indexed property to store values much like the Hashtable
collection does.
Generating the compiled class
The
first step (actually, step 0 as explained in the info block below) of
the life cycle is to generate the compiled class that represents the
requested page. As you know, the ASPX page consists of a combination of
HTML and Server controls. A dynamic compiled class is generated that
represents this ASPX page. This compiled class is then stored in the “Temporary ASP.NET Files”
folder. As long as the ASPX page is not modified (or the application
itself is restarted, in which case the request will actually be the
first request and then the generation of the class will occur again),
then future requests to the ASPX page will be served by the same
compiled class.
Info:
If you have read my previous article about request processing, you will
likely recall that the last step of the request handling is to find a
suitable HTTP Handler to handle the request. Back then, I explained how
the HTTP Handler Factory will either locate a compiled class that
represents the requested page or will compile the class in the case of
the first request. Well, do you see the link? This is the compiled class
discussed here. So, as you may have concluded, this step of generating
the compiled class actually occurs during the ASP.NET request handling
architecture. You can think of this step as the intersection between
where the ASP.NET request handling architecture stops and the ASP.NET
page life cycle starts.
This
compiled class will actually contain the programmatic definition of the
controls defined in the aspx page. In order to fully understand the
process of dynamic generation, let us consider the following example of a
simple ASPX page for collecting the username and the password:
Now, upon the first request for the above page, the generated class is created and stored in the following location:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\
<application name>\< folder identifier1>\< file identifier1>.cs
The compiled class “DLL” is also created in the same location with the same file identifier, as follows:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\
<application name>\< folder identifier1>\< file identifier1>.dll
As
you can see, the generated class and its corresponding DLL are created,
and will serve any new request for the ASPX page until one of the
following conditions occur:
· The ASPX file is modified
· The application is restarted, for example, as a result of IIS reset or app domain restart
The
following code is extracted from the compiled class. Note that the code
is reformatted and “cleaned up” for presentation purposes.
OK, so now is the really interesting part. Start examining the code above, and you will be able to notice the following:
· The class – unsurprisingly – inherits from the “System.Web.IHttpHandler
”. As explained earlier, this makes it eligible for acting as an HTTP Handler for the request.
· All the controls – both HTML and Web Controls – are defined in the class. Notice how the static properties (such as “Text
” and “TextMode
”)
are set inside the class. This is very important to remember because
this is a vital point when discussing the Viewstate later in this
article.
· The “BuildControlTree
”
is called to create the control hierarchy. As you may know, controls
inside an ASPX page are built into a tree hierarchy. For example, in the
above example, the hierarchy would be as follows: The root parent is
the page class itself, under which the direct child controls are the
HTML Literal (the "b
" tag) and the HTML Form. The HTML Form, in its turn, has two direct child controls which are the HTML Literal (the "div
"
tag) and the HTML Table. The HTML Table, in its turn, has child
controls such as the Web Control for the username label and the Web
Control for the password label, and so on until the complete hierarchy
is built. Again, this is a very important point to remember because it
will be revisited when discussing the Viewstate.
PreInit (New to ASP.NET 2.0)
The entry point of the page life cycle is the pre-initialization phase called “PreInit
”.
This is the only event where programmatic access to master pages and
themes is allowed. Note that this event is not recursive, meaning that
it is accessible only for the page itself and not for any of its child
controls.
Init (Recursive)
Next is the initialization phase called “Init
”. The “Init
”
event is fired reclusively for the page itself and for all the child
controls in the hierarchy (which is created during the creation of the
compiled class, as explained earlier). Note that against many
developers’ beliefs, the event is fired in a bottom to up manner and not
an up to bottom within the hierarchy. This means that following up with
our previous example, the “Init
” event is fired first for
the most bottom control in the hierarchy, and then fired up the
hierarchy until it is fired for the page itself. You can test this
behavior yourself by adding a custom or user control to the page.
Override the “OnInit
” event handler in both the page and
the custom (or user) control, and add break points to both event
handlers. Issue a request against the page, and you will notice that the
event handler for the control will be fired up before that of the page.
InitComplete (New to ASP.NET 2.0)
The initialization complete event called “InitComplete
”
signals the end of the initialization phase. It is at the start of this
event that tracking of the ASP.NET Viewstate is turned on. Recall that
the StateBag
class (the Type of Viewstate) has a tracking ability which is off by default, and is turned on by calling the “Track
ViewState()
” method. Also recall that, only when tracking is enabled will any change to a Viewstate key mark the item as “Dirty
”. Well, it is at the start of “InitComplete
” where “Page.Track
ViewState()
” is called, enabling tracking for the page Viewstate.
Info:
Later, I will give detailed samples of how the Viewstate works within
each of the events of the life cycle. These examples will hopefully aid
in understanding the inner workings of the Viewstate.LoadViewState
This event happens only at postbacks. This is a recursive event, much like the “Init
” event. In this event, the Viewstate which has been saved in the __
VIEWSTATE during the previous page visit (via the Save
ViewState event) is loaded and then populated into the control hierarchy.
LoadPostbackdata (Recursive)
This event happens only at postbacks. This is a recursive event much like the “Init
”
event. During this event, the posted form data is loaded into the
appropriate controls. For example, assume that, on your form, you had a TextBox
server control, and you entered some text inside the TextBox
and posted the form. The text you have entered is what is called postback data. This text is loaded during the LoadPostbackdata
event and handed to the TextBox
.
This is why when you post a form, you find that the posted data is
loaded again into the appropriate controls. This behavior applies to
most controls like the selected item of a drop down list or the
“checked” state of a check box, etc…
A
very common conceptual error is the thought that Viewstate is
responsible for preserving posted data. This is absolutely false;
Viewstate has nothing to do with it. If you want a proof, disable the
Viewstate on your TextBox
control or even on the entire page, and you will find that the posted data is still preserved. This is the virtue of the LoadPostbackdata
event.
PreLoad (New to ASP.NET 2.0)
This event indicates the end of system level initialization.
Load (Recursive)
This event is recursive much like the “Init
”
event. The important thing to note about this event is the fact that by
now, the page has been restored to its previous state in case of
postbacks. That is because the Load
ViewState and the LoadPostbackdata
events are fired, which means that the page Viewstate and postback data are now handed to the page controls.
RaisePostbackEvent
This
event is fired only at postbacks. What this event does is inspect all
child controls of the page and determine if they need to fire any
postback events. If it finds such controls, then these controls fire
their events. For example, if you have a page with a Button
server control and you click this button causing a postback, then the RaisePostbackEvent
inspects the page and finds that the Button
control has actually raised a postback event – in this case, the Button
's Click
event. The Button
's Click
event is fired at this stage.
LoadComplete (New to ASP.NET 2.0)
This event signals the end of Load
.
Prerender (New to ASP.NET 2.0)
This event allows for last updates before the page is rendered.
PrerenderComplete (New to ASP.NET 2.0)
This event signals the end of “Prerender
”.
SaveViewstate (Recursive)
This event is recursive, much like the “Init
” event. During this event, the Viewstate of the page is constructed and serialized into the __
VIEWSTATE hidden field.
Info: Again, what exactly goes into the __
VIEWSTATE field will be discussed later.
SaveStateControl (New to ASP.NET 2.0)
State
Control is a new feature of ASP.NET 2.0. In ASP.NET 1.1, Viewstate was
used to store two kinds of state information for a control:
· Functionality state
· UI state
This resulted in a fairly large __
VIEWSTATE field. A very good example is the DataGrid
server control. In ASP.NET 1.1, DataGrid
uses the Viewstate to store its UI state such as sorting and paging. So, even if you wanted to disable Viewstate on the DataGrid
and rebind the data source on each postback, you simply cannot do that if your DataGrid
was using sorting or paging. The result was that the DataGrid
ended up using Viewstate to store both its bounded data and its UI state such as sorting and paging.
ASP.NET 2.0 solved this problem by partitioning the Viewstate into two:
· The Viewstate we are discussing here
· The Control State
The Control State is used to store the UI state of a control such as the sorting and paging of a DataGrid
. In this case, you can safely disable the DataGrid
Viewstate (provided, of course, that you rebind the data source at each
postback), and the sorting and paging will still work simply because
they are saved in the Control State.
The Control State is also serialized and stored in the same __
VIEWSTATE hidden field. The Control State cannot be set off.
Render (Recursive)
This is a recursive event much like the “Init
” event. During this event, the HTML that is returned to the client requesting the page is generated.
Unload (Recursive)
This is a recursive event much like the “Init
” event. This event unloads the page from memory, and releases any used resources.
Role of Viewstate in the Page Life Cycle
Viewstate in the “Init” event
The important thing to note in the “Init
” event is that Viewstate tracking is not yet enabled. In order to demonstrate this, let us take the following example:
protected override void OnInit(EventArgs e)
(
bool ret;
ret = ViewState.IsItemDirty("item");//returns false
ViewSTate["item"] = "1";
ret = ViewState.IsItemDirty("item");returns false
base.OnInit(e);
}
Note that in the above example, the item is still not marked as “Dirty
” even after it is being set. This is due to the fact that at this stage, the “Track
ViewState()
” method is not called yet. It will be called in the “InitComplete
” event.
Info: You can force the tracking of Viewstate at any stage that you want. For example, you can call the “Page.Track
ViewState()
” method at the start of the “Init
” event and thus enabling tracking. In this case, the “Init
” event will behave exactly like the “InitComplete
” event, to be discussed next.
Viewstate in the “InitComplete” event
In the “InitComplete
” event, the Viewstate tracking is enabled. If we take the same example:
protected override void OnInitComplete(EventArgs e)
(
bool ret;
ret = ViewState.IsItemDirty("item");//returns false
ViewSTate["item"] = "1";
ret = ViewState.IsItemDirty("item");//returns true
base.OnInitComplete(e);
}
This time, note that first, the item is not marked as “Dirty
”. However, once it is set, then it is marked as “Dirty
”. This is due to the fact that at the start of this event, the “Track
ViewState()
” method is called.
Viewstate in the “LoadViewState”and “SaveViewState” events
To
better understand the role of Viewstate in these events, let us take an
example. Say that you have a simple ASPX page that consists of the
following:
· A Label
server control with its “Text
” property set to “statictext”
· A Button
server control just to postback the page
· The “Load
” event of the page has a statement that sets the “Text
” property of the Label
control to “dynamictext”. This statement is wrapped inside a “!IsPostback
” condition
When the page first loads, the following will happen:
· During the “Load
” event, the “dynamictext” value will be assigned to the “Text
” property of the Label
· Later in the life cycle, the “SaveViewSatte
” event is fired, and it stores the new assigned value “dynamictext” in the __
VIEWSTATE serialized field (in the next sections, you will see how tracking came into play here)
Now, when you click the Button
control, the following will happen:
· The “Load
ViewState” event is fired. The __
VIEWSTATE value saved in the previous page visit is loaded. The “dynamictext” value is extracted and assigned back to the “Text
” property of the Label
.
· The “Load
” event is fired, but nothing happens there because the code is wrapped inside a “!IsPostback
” condition.
See
how that because of the Viewstate, the “dynamictext” value is persisted
across page postback. Without Viewstate and with the “!IsPostback”
condition inside the “Load” event, the value “dynamictext” would have
been lost after the postback.
Viewstate Walkthroughs
OK,
so by now, you should have a solid understanding about the page life
cycle, the Viewstate, and the role of the Viewstate in the page life
cycle. However, we are yet to discuss the cases that tests whether you
are an advanced Viewstate user or not. In the next walkthroughs, you
shall tackle most of these cases. By the end of this section, you can
safely call yourself an advanced Viewstate user.
Walkthrough 1: Viewstate of an empty or Viewstate-disabled page
So, let us start by a very simple question. Will you have a value stored in the __
VIEWSTATE
field if you have a blank ASP.NET page or a page with Viewstate
completely disabled? The answer is yes. As a test, create a blank
ASP.NET page and run it. Open the View Source page and note the __
VIEWSTATE
field. You will notice that it contains a small serialized value. The
reason is that the page itself saves 20 or so bytes of information into
the __
VIEWSTATE field, which it uses to distribute postback
data and Viewstate values to the correct controls upon postback. So,
even for a blank page or a page with disabled Viewstate, you will see a
few remaining bytes in the __
VIEWSTATE field.
Walkthrough 2: What is stored in the Viewstate?
As mentioned previously, the data stored in the __
VIEWSTATE field consists of the following:
· Data stored by developers using the Viewstate[“”]
indexer
· Programmatic change to the Control State
While the former is pretty much clear, the latter is to be explained thoroughly.
OK, so let us assume that you have a web page with only a Label
control on it. Now, let us say that at design time, you set the “Text
” property of the Label
to “statictext”. Now, load the page and open the View Source page. You will see the __
VIEWSTATE
field. Do you think “statictext” is saved there? The answer is, for
sure, not. Recall from our discussion about generating the compiled
class of the page, that static properties of controls are assigned at
the generated class? So, when the page is requested, the values stored
in the generated class are displayed. As such, static properties that
are set at design time are never stored in the __
VIEWSTATE field. However, they are stored in the generated compiled class, and thus they show up when rendering the page.
Now, let us say that you did some changes to your page such that it consists of the following:
· A Label
control with the value “statictext” assigned to its “Text
” property
· A Button
control to postback the page
· Inside the “Page_Load
” event handler of the page, add code to change the value of the Label
’s “Text
” property to “dynamictext”. Wrap this code inside a “!IsPostback
” condition.
Load the page and open the View Source page. This time, you will notice that the __
VIEWSTATE field is larger. This is because at runtime, you changed the value of the “Text
” property. And, since you have done this inside the “Load
” event, where, at this time, tracking of Viewstate is enabled (remember, tracking is enabled in the “InitComplete
” event), the “Text
” property is marked as “Dirty
”, and thus the “Save
Viewstate” event stores its new value in the __
VIEWSTATE field. Interesting!!
As a proof that the “dynamictext” value is stored in the __
VIEWSTATE field (apart from the fact that it is larger), click the Button
control causing a postback. You will find that the “dynamictext” value is retained in the Label
even though the code in the “Load
” event is wrapped inside the “!IsPostback
” condition. This is due to the fact that upon postback, the “Load
Viewstate” event extracted the value “dynamictext” which was saved by the “Save
ViewState” event during the previous page visit and then assigned it back to the Label
’s “Text
” property.
Let
us now go one step further. Repeat the exact same scenario, with one
exception: instead of adding the code that will change the value of the “Text
” property at the “Page_Load
” event handler, override the “OnPreInit
” event handler and add the code there. Now, first load the page, and you will see the new text displayed in the Label
. But, do you think this time it is stored in the __
VIEWSTATE field? The answer is no. The reason is that during the “PreInit
” event, Viewstate tracking is not yet enabled, so the change done to the “Text
” property is not tracked and thus not saved during the “Save
ViewState” event. As a proof, click the Button
causing a postback. You will see that the value displayed inside the Label
is the design time value “statictext”.
Let us even go one step further. If you have been following this long article carefully, you will recall that during the “Init
” event, tracking of Viewstate is not yet enabled. You have even seen an example in the section Viewstate in the “Init” event
of how an item keeps being not dirty even after it is being set. Now,
going back to our current example, you will most probably be tempted to
consider that if we add the code that changes the value of the “Text
” property inside the “OnInit
” event handler, you will get the same result as when you put it inside the “OnPreInit
”
event handler; after all, tracking of Viewstate is not enabled yet
during either event. Well, if you think so, then you are mistaken.
Reason: if you have been following this article carefully, you will
recall that the “InitComplete
” event (where tracking of
Viewstate is enabled) is not a recursive event; it is called only for
the page itself, but not for its child controls. This means that, for
the child controls, there is no “InitComplete
” event; so, where does the tracking of Viewstate start? The answer is at the start of the “Init
” event. So, this means that for the page itself, tracking of Viewstate is enabled at the “InitComplete
” event; that is why during the “OnInit
” event handler, the item was still marked as not being “Dirty
” even after modification. However, for child controls, there is no “InitComplete
” event, so the Viewstate tracking is enabled as early as the “Init
” event. And, since – again as was explained earlier – the “Init
” event is called recursively for the page and its controls in a bottom to up manner, by the time the “Init
” event of the page itself is fired, the “Init
”
event of the child controls is already being fired, and thus Viewstate
tracking for child controls is on by that time. As such, adding the code
that changes the value of the “Text
” property inside the “OnInit
” event handler will have the same effect as putting it inside the “Page_Load
” event handler.
Walkthorugh 3: What is the larger Viewstate?
Consider the following example: you have two ASP.NET pages: page1.aspx and page2.aspx. Both pages contain only a single Label
control. However, in page1, the Label
is declared at design time with its “Text
” property set to a small string (say 10 characters); in page2, the Label
is declared at design time with its “Text
”
property set to a lengthy string (say 1000 characters). Now, load both
pages at the same time, and examine the View Source for both pages.
Compare the two __
VIEWSTATE fields, what do you find? You will find that both fields are of the same size even though one Label
has its “Text
” property storing 10 characters while the other has its “Text
”
property storing 1000 characters. If you have read walkthroughs 1 and
2, you will for sure know the reason: design time property values are
not stored in the Viewstate. The __
VIEWSTATE value for both pages is simply the bytes emitted by the page itself.
Walkthrough 4: Complete page life cycle scenario
In
this walkthrough, we will go through each of the relevant page life
cycle events and see what role Viewstate has in each of these events. In
this example, we have as ASP.NET page with the following
characteristics:
· It contains a single Label
control (lbl
) with its “Text
” property set to “statictext”
· It contains a Button
control (btnA
) with code in its event handler that sets the “Text
” property of “lbl
” to “dynamictext”
· It contains a Button
control (btn
B) whose purpose is to cause a page postback
Now, let us examine what will happen during the page life cycle.
1. The page is first loaded
1. The compiled class of the page is generated and “statictext” is assigned to “lbl.Text
”
2. Tracking for Viewstate is enabled in the “InitComplete
” event
3. “Load
ViewState” is not fired because there is no postback
4. “Save
Viewstate” is fired, but nothing happens because no change of state is recorded
5. The page is rendered with the value “statictext” inside “lbl
”
2. btnA
is clicked
1. The previously generated compiled class is handed the request; “lbl.Text
” is set to “statictext”
2. Tracking for Viewstate is enabled
3. “Load
ViewState” is fired, but nothing happens because no change of state was recorded in the previous page visit
4. “RaisePostbackEvent
” event is executed and “btnA
” click event handler is fired; “lbl.Text
” is set to “dynamictext”; since tracking is enabled at this stage, this item is tracked (marked as “Dirty
”).
5. “Save
ViewState” is fired; “dynamictext” is serialized and stored in the __
VIEWSTATE field
6. The page is rendered with the value “dynamictext” inside “lbl
”
3. btnB
is clicked
1. The previously generated compiled class is handed the request; “lbl.Text” is set to “statictext”
2. Tracking for Viewstate is enabled
3. “Load
ViewState” is fired; since a change of state was recorded from the previous page visit, __
VIEWSTATE is loaded and the value “dynamictext” is extracted; this value is then assigned to “lbl
”
4. “RaisePostbackEvent
” event is executed; nothing happens here because “btnB
” has no event handler for its “Click
” event
5. “Save
ViewState” is fired, but nothing happens because no change of state is recorded
6. The page is rendered with the value “dynamictext” inside “lbl
”
Walkthrough 5: Reducing Viewstate size – Disabling Viewstate
Disabling
Viewstate would obviously reduce Viewstate size; but, it surely kills
the functionality along the way. So, a little more planning is required…
Consider the case where you have a page with a drop down list that should display the countries of the world. On the “Page_Load
”
event handler, you bind the drop down list to a data source that
contains the countries of the world; the code that does the binding is
wrapped inside a “!IsPostback
” condition. Finally, on the
page, you have a button that when clicked should read the selected
country from the drop down list. With the setup described above, you
will end up with a large __
VIEWSTATE field. This is due to
the fact that data bound controls (like the drop down list) store their
state inside the Viewstate. You want to reduce Viewstate; what options
do you have?
1. Option 1: Simply disable the Viewstate on the drop down list
2. Option 2: Disable the Viewstate on the drop down list, and remove the “!IsPostback
” condition
3. Option 3: Disable the Viewstate on the drop down list, and move the binding code without the “!IsPostback
” condition to the “OnInit
” or “OnPreInit
” event handlers
If
you implement Option 1, you will reduce the Viewstate alright, but with
it, you will also lose the list of countries on the first postback of
the page. When the page first loads, the code in the “Page_Load
”
event handler is executed and the list of countries is bound to the
list. However, because Viewstate is disabled on the list, this change of
state is not saved during the “Save
ViewState” event. When the button on the page is clicked causing a postback, since the binding code is wrapped inside a “!IsPostback
” condition, the “Load
ViewState” event has nothing saved from the previous page visit and the drop down list is empty.
If
you implement Option 2, you will reduce the Viewstate size and you will
not lose the list of countries on postback. However, another problem
arises: because the binding code is now executed at each “Page_Load
”,
the postback data is lost upon postback, and every time, the first item
of the list will be selected. This is true because in the page life
cycle, the “LoadPostbackdata
” event occurs before the “Load
” event.
Option 3 is the correct option. In this option, you have done the following:
· Disabled Viewstate on the drop down list
· Removed the “!IsPostback
” condition from the binding code
· Moved the binding code to the “OnInit
” event handler (or the “OnPreInit
” event handler)
Since the “Init
” event occurs before the “LoadPostbackdata
”
in the page life cycle, the postback data is preserved upon postbacks,
and the selected item from the list is correctly preserved.
Now,
remember that in Option 3, you have successfully reduced the Viewstate
size and kept the functionality working; but, this actually comes at the
cost of rebinding the drop down list at each postback. The performance
hit of revisiting the data source at each postback is nothing when
compared with the performance boost gained from saving a huge amount of
bytes being rendered at the client’s __
VIEWSTATE
field. This is especially true with the fact that most clients are
connected to the Internet via low speed dial up connections.
Walkthrough 6: Viewstate and Dynamic Controls
The
first fact that you should know about dynamic controls is that they
should be added to the page at each and every page execution. Never wrap
the code that initializes and adds the dynamic control to the page
inside a “!IsPostback
” condition. The
reason is that since the control is dynamic, it is not included in the
compiled class generated for the page. So, the control should be added
at every page execution for it to be available in the final control
tree. The second fact is that dynamic controls play “catch-up” with the
page life cycle once they are added. Say, you did the following:
Label lbl = new Label();
Page.Controls.Add(lbl);
Once the control is added to the “Controls
”
collection, it plays “catch-up” with the page life cycle, and all the
events that it missed are fired. This leads to a very important
conclusion: you can add dynamic controls at any time during the page
life cycle until the “PreRender
” event. Even when you add the dynamic control in the “PreRender
” event, once the control is added to the “Controls
” collection, the “Init
”, “Load
ViewState”, “LoadPostbackdata
”, “Load
”, and “Save
Viewstate”
are fired for this control. This is called “catch-up”. Note though that
it is recommended that you add your dynamic controls during the “PreInit
” or “Init
”
events. This is because it is best to add controls to the control tree
before tracking of the Viewstate of other controls is enabled…
Finally, what is the best practice for adding dynamic controls regarding Viewstate? Let us say that you want to add a Label
at runtime and assign a value to its “Text
” property. What is the best practice to do so? If you are thinking the below, then you are mistaken:
Label lbl = new Label();
Page.Controls.Add(lbl);
lbl.Text = "bad idea";
You are mistaken because using the above technique you are actually storing the value of the “Text
” property in the Vewstate. Why? Because, recall that once a dynamic control is added to the “Controls
” collection, a “catch-up” happens and the tracking for the Viewstate starts. So, setting the value of the “Text
” property will cause the value to be stored in the Viewstate.
However, if you do the below, then you are thinking the right way, because you are setting the “Text
” property before adding the control to the “Controls
” collection. In this case, the value of the “Text
” property is added with the control to the control tree and not persisted in Viewstate.
Label lbl = new Label();
lbl.Text = "good idea";
Page.Controls.Add(lbl);
ASP.NET Authentication And Authorization
Before proceeding ahead we need to understand four important vocabularies which you will see in this article again and again: - authentication, authorization, principal and identity. Let’s first start with authentication and authorization. If you search in www.google.com for the dictionary meaning of authentication and authorization, you will land up with something below:-
Authentication: - prove genuineness
Authorization: - process of granting approval or permission on resources.
The same dictionary meaning applies to ASP.NET as well. In ASP.NET authentication means to identify the user or in other words its nothing but to validate that he exists in your database and he is the proper user. Authorization means does he have access to a particular resource on the IIS website. A resource can be an ASP.NET web page, media files (MP4, GIF, JPEG etc), compressed file (ZIP, RAR) etc.
So the first process which happens is authentication and then authorization. Below is a simple graphical representation of authentication and authorization. So when the user enters ‘userid’ and ‘password’ he is first authenticated and identified by the user name.
Now when the user starts accessing resources like pages, ASP DOTNET authentication, videos etc, he is checked whether he has the necessary access for the resources. The process of identifying the rights for resources is termed as ‘Authorization’.
Detecting authentication and authorization: - The principal and identity objects
At any moment of time if you want to know who the user is and what kind of authentication type he using you can use the identity object. If you want to know what kind of roles it’s associated with then we need to use the principal object. In other words to get authentication details we need to the identity object and to know about authorization details of that identity we need the principal object.
Types of authentication and authorization in ASP.NET
There are three ways of doing authentication and authorization in ASP.NET:-
• Windows authentication: - In this methodology ASP.NET web pages will use local windows users and groups to authenticate and authorize resources.
• Forms Authentication: - This is a cookie based authentication where username and password are stored on client machines as cookie files or they are sent through URL for every request. Form-based authentication presents the user with an HTML-based Web page that prompts the user for credentials.
• Passport authentication :- Passport authentication is based on the passport website provided
by the Microsoft .So when user logins with credentials it will be reached to the passport website ( i.e. hotmail,devhood,windows live etc) where authentication will happen. If Authentication is successful it will return a token to your website.
• Anonymous access: - If you do not want any kind of authentication then you will go for Anonymous access.
GenericPrincipal and GenericIdentity objects represent users who have been authenticated using Forms authentication or other custom authentication mechanisms. With these objects, the role list is obtained in a custom manner, typically from a database.
FormsIdentity and PassportIdentity objects represent users who have been authenticated with Forms and Passport authentication respectively.
Windows Authentication
When you configure your ASP.NET application as windows authentication it will use local windows user and groups to do authentication and authorization for your ASP.NET pages. Below is a simple snap shot which shows my windows users and roles on my computer.
5 steps to enable authentication and authorization using windows
We will do a small sample to get a grasp of how authentication and authorization works with windows. We will create 2 users one ‘Administrator’ and other a simple user with name ‘Shiv’. We will create two simple ASPX pages ‘User.aspx’ page and ‘Admin.aspx’ page. ‘Administrator’ user will have access to both ‘Admin.aspx’ and ‘User.aspx’ page , while user ‘Shiv’ will only have access to ‘User.aspx’ page.
Create a website - Step 1
The next step is to create a simple web site with 3 pages (User.aspx, Admin.aspx and Home.aspx) as shown below.
Creating user in windows directory - Step 2
The next step is we go to the windows directory and create two users. You can see in my computer we have ‘Administrator’ and ‘Shiv’.
Setup We.Config file - Step 3
Setup Authorization - Step 4
We also need to specify the authorization part. We need to insert the below snippet in the ‘web.config’ file stating that only ‘Administrator’ users will have access to
Setup Configure IIS - Step 5
The next step is to compile the project and upload the same on an IIS virtual directory. On the IIS virtual directory we need to ensure to remove anonymous access and check the integrated windows authentication as shown in the below figure.
Basic Authentication
We then copied the ‘Authorization:Basic’ data and ran the below program. LOL, we can see our windows userid and password.
Integrated Authentication
Integrated Windows authentication (formerly called NTLM, and also known as Windows NT Challenge/Response authentication) uses either Kerberos v5 authentication or NTLM authentication, depending upon the client and server configuration.
(The above paragraph is ripped from http://msdn.microsoft.com/en-us/library/ff647076.aspx ).
Let’s try to understand what NTLM and Kerberos authentication is all about and then we will try to understand other aspects of integrated authentication.
NTLM is a challenge response authentication protocol. Below is how the sequence of events happens:-
• Client sends the username and password to the server.
• Server sends a challenge.
• Client responds to the challenge with 24 byte result.
• Servers checks if the response is properly computed by contacting the domain controller.
• If everything is proper it grants the request.
Order of Security Precedence
One of the things which you must have noticed is that integrated, digest and basic authentication are check boxes. In other words we can check all the three at one moment of time. If you check all the 3 options at one moment of time depending on browser security support one of the above methods will take precedence.
• Browser makes a request; it sends the first request as Anonymous. In other words it does not send any credentials.
• If the server does not accept Anonymous IIS responds with an "Access Denied" error message and sends a list of the authentication types that are supported by the browser.
• If Windows NT Challenge/Response is the only one supported method then the browser must support this method to communicate with the server. Otherwise, it cannot negotiate with the server and the user receives an "Access Denied" error message.
• If Basic is the only supported method, then a dialog box appears in the browser to get the credentials, and then passes these credentials to the server. It attempts to send these credentials up to three times. If these all fail, the browser is not connected to the server.
• If both Basic and Windows NT Challenge/Response are supported, the browser determines which method is used. If the browser supports Windows NT Challenge/Response, it uses this method and does not fall back to Basic. If Windows NT Challenge/Response is not supported, the browser uses Basic.
You can read more about precedence from http://support.microsoft.com/kb/264921.
In order words the precedence is:-
1. Windows NT challenge ( Integrated security)
2. Digest
3. Basic
Forms Authentication
Forms authentication is a cookie/URL based authentication where username and password are stored on client machines as cookie files or they are sent encrypted on the URL for every request if cookies are not supported.
Below are the various steps which happen in forms authentication:-
• Step 1:- User enters “userid” and “password” through a custom login screen developed for authentication and authorization.
• Step 2:- A check is made to ensure that the user is valid. The user can be validated from ‘web.config’ files, SQL Server, customer database, windows active directory and various other kinds of data sources.
• Step 3:- If the user is valid then a cookie text file is generated on the client end. This cookie test file signifies that the user has been authenticated. Hence forth when the client computer browses other resources of your ASP.NET site the validation is not conducted again. The cookie file indicates that the user has logged in.
Form Authentication using Web.config as a data store
Forms authentication using ASP.NET Membership and Role
Forms Authentication using Single Sign On
Passport Authentication
Passport authentication is based on the passport website
provided by the Microsoft .So when user logins with credentials it will be
reached to the passport website ( i.e. hotmail,devhood,windows live etc) where authentication will happen. If Authentication is successful it will return a
token to your website.
I am leaving this section for now, will update in more details soon.
ASP.NET Impersonation
Visual Studio .NET 2003
Another important security feature is the ability to control the identity under which code is executed. Impersonation is when ASP.NET executes code in the context of an authenticated and authorized client. By default, ASP.NET does not use impersonation and instead executes all code using the same user account as the ASP.NET process, which is typically the ASPNET account. This is contrary to the default behavior of ASP, which uses impersonation by default. In Internet Information Services (IIS) 6, the default identity is the NetworkService account.Note Impersonation can significantly affect performance and scaling. It is generally more expensive to impersonate a client on a call than to make the call directly.
Using impersonation, ASP.NET applications can optionally execute the processing thread using the identity of the client on whose behalf they are operating. You usually use impersonation for resource access control. Delegation is a more powerful form of impersonation and makes it possible for the server process to access remote resources while acting as the client. For more information, see ASP.NET Delegation.
Note Impersonation is local to a particular thread. When code changes threads, such as when using thread pooling, the new thread executes using the process identity by default. When impersonation is required on the new thread, your application should save the security token (WindowsIdentity.Token Property) from the original thread as part of the state for the completion thread.
If you enable impersonation, ASP.NET can either impersonate the authenticated identity received from IIS or one specified in the application's Web.config file. You have the following three options when configuring impersonation:
- Impersonation is disabled. This is the default setting. For backward compatibility with ASP, you must enable impersonation and change the ASP.NET process identity to use the Local System account. In this instance, the ASP.NET thread runs using the process token of the application worker process regardless of which combination of IIS and ASP.NET authentication is used. By default, the process identity of the application worker process is the ASPNET account. For more information, see ASP.NET Process Identity.
<identity impersonate="false" />
- Impersonation enabled. In this instance, ASP.NET impersonates the token passed to it by IIS, which is either an authenticated user or the anonymous Internet user account (IUSR_machinename).
<identity impersonate="true" />
- Impersonation enabled for a specific identity. In this instance, ASP.NET impersonates the token generated using an identity specified in the Web.config file.
<identity impersonate="true"
userName="domain\user"
password="password" />
If the application resides on a UNC share, ASP.NET always impersonates the IIS UNC token to access that share unless a configured account is used. If you provide an explicitly configured account, ASP.NET uses that account in preference to the IIS UNC token.
You should exercise care when using impersonation because it makes it possible for an application to potentially process code using permissions not anticipated by the application designer. For example, if your application impersonates an authenticated intranet user, that application possesses administrative privileges when impersonating a user with those privileges. Likewise, if the impersonated user possesses more restrictive permissions than anticipated, the user may not be able to use the application.
ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0
Stage | Description |
User requests an application resource from the Web server. | The
life cycle of an ASP.NET application starts with a request sent by a
browser to the Web server (for ASP.NET applications, typically IIS).
ASP.NET is an ISAPI extension under the Web server. When a Web server
receives a request, it examines the file-name extension of the requested
file, determines which ISAPI extension should handle the request, and
then passes the request to the appropriate ISAPI extension. ASP.NET
handles file name extensions that have been mapped to it, such as .aspx,
.ascx, .ashx, and .asmx. Note If a file name extension has not been mapped to ASP.NET, ASP.NET will not receive the request. This is important to understand for applications that use ASP.NET authentication. For example, because .htm files are typically not mapped to ASP.NET, ASP.NET will not perform authentication or authorization checks on requests for .htm files. Therefore, even if a file contains only static content, if you want ASP.NET to check authentication, create the file using a file name extension mapped to ASP.NET, such as .aspx. Note If you create a custom handler to service a particular file name extension, you must map the extension to ASP.NET in IIS and also register the handler in your application's Web.config file. For more information, see HTTP Handlers and HTTP Modules Overview. |
ASP.NET receives the first request for the application. | When ASP.NET receives the first request for any resource in an application, a class named ApplicationManager
creates an application domain. Application domains provide isolation
between applications for global variables and allow each application to
be unloaded separately. Within an application domain, an instance of the
class named HostingEnvironment
is created, which provides access to information about the application
such as the name of the folder where the application is stored. The following diagram illustrates this relationship: ASP.NET also compiles the top-level items in the application if required, including application code in the App_Code folder. For more information, see "Compilation Life Cycle" later in this topic. |
ASP.NET core objects are created for each request. | After the application domain has been created and the HostingEnvironment object instantiated, ASP.NET creates and initializes core objects such as HttpContext, HttpRequest, and HttpResponse. The HttpContext class contains objects that are specific to the current application request, such as the HttpRequest and HttpResponse objects. The HttpRequest object contains information about the current request, including cookies and browser information. The HttpResponse object contains the response that is sent to the client, including all rendered output and cookies. |
An HttpApplication object is assigned to the request | After all core application objects have been initialized, the application is started by creating an instance of the HttpApplication
class. If the application has a Global.asax file, ASP.NET instead
creates an instance of the Global.asax class that is derived from the HttpApplication class and uses the derived class to represent the application. Note The first time an ASP.NET page or process is requested in an application, a new instance of HttpApplication is created. However, to maximize performance, HttpApplication instances might be reused for multiple requests. When an instance of HttpApplication is created, any configured modules are also created. For instance, if the application is configured to do so, ASP.NET creates a SessionStateModule module. After all configured modules are created, the HttpApplication class's Init method is called. The following diagram illustrates this relationship: |
The request is processed by the HttpApplication pipeline. | The following events are executed by the HttpApplication class while the request is processed. The events are of particular interest to developers who want to extend the HttpApplication class. |
When the first request is made to an application, ASP.NET compiles application items in a specific order. The first items to be compiled are referred to as the top-level items. After the first request, the top-level items are recompiled only if a dependency changes. The following table describes the order in which ASP.NET top-level items are compiled.
Item | Description |
App_GlobalResources | The application's global resources are compiled and a resource assembly is built. Any assemblies in the application's Bin folder are linked to the resource assembly. |
App_WebResources | Proxy types for Web services are created and compiled. The resulting Web references assembly is linked to the resource assembly if it exists. |
Profile properties defined in the Web.config file | If profile properties are defined in the application's Web.config file, an assembly is generated that contains a profile object. |
App_Code | Source code files are built and one or more assemblies are created. All code assemblies and the profile assembly are linked to the resources and Web references assemblies if any. |
Global.asax | The application object is compiled and linked to all of the previously generated assemblies. |
After the application's top level items have been compiled, ASP.NET compiles folders, pages, and other items as needed. The following table describes the order in which ASP.NET folders and items are compiled.
Item | Description |
App_LocalResources | If the folder containing the requested item contains an App_LocalResources folder, the contents of the local resources folder are compiled and linked to the global resources assembly. |
Individual Web pages (.aspx files), user controls (.ascx files), HTTP handlers (.ashx files), and HTTP modules (.asmx files) | Compiled as needed and linked to the local resources assembly and the top-level assemblies. |
Themes, master pages, other source files | Skin files for individual themes, master pages, and other source code files referenced by pages are compiled when the referencing page is compiled. |
Compiled assemblies are cached on the server and reused on subsequent requests and are preserved across application restarts as long as the source code is unchanged.
Because the application is compiled on the first request, the initial request to an application can take significantly longer than subsequent requests. You can precompile your application to reduce the time required for the first request. For more information, see How to: Precompile ASP.NET Web Site Projects.
ASP.NET Application Life Cycle Overview for IIS 7.0
A request in IIS 7.0 Integrated mode passes through stages that are like the stages of requests for ASP.NET resources in IIS 6.0. However, in IIS 7.0, these stages include several additional application events, such as the MapRequestHandler, LogRequest, and PostLogRequest events.The main difference in processing stages between IIS 7.0 and IIS 6.0 is in how ASP.NET is integrated with the IIS server. In IIS 6.0, there are two request processing pipelines. One pipeline is for native-code ISAPI filters and extension components. The other pipeline is for managed-code application components such as ASP.NET. In IIS 7.0, the ASP.NET runtime is integrated with the Web server so that there is one unified request processing pipeline for all requests. For ASP.NET developers, the benefits of the integrated pipeline are as follows:
· The integrated pipeline raises all the events that are exposed by the HttpApplication object, which enables existing ASP.NET HTTP modules to work in IIS 7.0 Integrated mode.
· Both native-code and managed-code modules can be configured at the Web server, Web site, or Web application level. This includes the built-in ASP.NET managed-code modules for session state, forms authentication, profiles, and role management. Furthermore, managed-code modules can be enabled or disabled for all requests, regardless of whether the request is for an ASP.NET resource like an .aspx file.
· Managed-code modules can be invoked at any stage in the pipeline. This includes before any server processing occurs for the request, after all server processing has occurred, or anywhere in between.
· You can register and enable or disable modules through an application’s Web.config file.
The following illustration shows the configuration of an application's request pipeline. The example includes the following:
· The Anonymous native-code module and the Forms managed-code module (which corresponds to FormsAuthenticationModule). These modules are configured, and they are invoked during the Authentication stage of the request.
· The Basic native-code module and the Windows managed-code module (which corresponds to WindowsAuthenticationModule). They are shown, but they are not configured for the application.
· The Execute handler stage, where the handler (a module scoped to a URL) is invoked to construct the response. For aspx files, the PageHandlerFactory handler is used to respond to the request. For static files, the native-code StaticFileModule module responds to the request.
· The Trace native-code module. This is shown, but it is not configured for the application.
· The Custom module managed-code class. It is invoked during the Log request stage.
For information about known compatibility issues with ASP.NET applications that are being migrated from earlier versions of IIS to IIS 7.0, see the "Known Differences Between Integrated Mode and Classic Mode" section of Upgrading ASP.NET Applications to IIS 7.0: Differences between IIS 7.0 Integrated Mode and Classic mode.
Life Cycle Stages
The following table lists the stages of the ASP.NET application life cycle with Integrated mode in IIS 7.0.
Stage | Description |
A request is made for an application resource. | The life cycle of an ASP.NET application starts with a request sent by a browser to the Web server. In Classic mode in IIS 7.0 and in IIS 6.0, the ASP.NET request pipeline is separate from the Web server pipeline. Modules apply only to requests that are routed to the ASP.NET ISAPI extension. If the file-name extension of the requested resource type is not explicitly mapped to ASP.NET, ASP.NET functionality is not invoked for the request because the request is not processed by the ASP.NET runtime. In integrated mode in IIS 7.0, a unified pipeline handles all requests. When the integrated pipeline receives a request, the request passes through stages that are common to all requests. These stages are represented by the RequestNotification enumeration. All requests can be configured to take advantage of ASP.NET functionality, because that functionality is encapsulated in managed-code modules that have access to the request pipeline. For example, even though the .htm file-name extension is not explicitly mapped to ASP.NET, a request for an HTML page still invokes ASP.NET modules. This enables you to take advantage of ASP.NET authentication and authorization for all resources. |
The unified pipeline receives the first request for the application. | When the unified pipeline receives the first request for any resource in an application, an instance of the ApplicationManager
class is created, which is the application domain that the request is
processed in. Application domains provide isolation between applications
for global variables and enable each application to be unloaded
separately. In the application domain, an instance of the HostingEnvironment
class is created, which provides access to information about the
application, such as the name of the folder where the application is
stored. During the first request, top-level items in the application are compiled if required, which includes application code in the App_Code folder. You can include custom modules and handlers in the App_Code folder as described in Managed-code Modules in IIS 7.0 later in this topic. |
Response objects are created for each request. | After the application domain has been created and the HostingEnvironment object has been instantiated, application objects such as HttpContext, HttpRequest, and HttpResponse are created and initialized. The HttpContext class contains objects that are specific to the current application request, such as the HttpRequest and HttpResponse objects. The HttpRequest object contains information about the current request, which includes cookies and browser information. The HttpResponse object contains the response that is sent to the client, which includes all the rendered output and cookies. The following are some key differences between IIS 6.0 and IIS 7.0 running in Integrated mode and with the .NET Framework 3.0 or later: · The SubStatusCode property of the HttpResponse object is available for setting codes that are useful for failed-request tracing. For more information, see Troubleshooting Failed Requests Using Failed Request Tracing in IIS 7.0. · The Headers property of the HttpResponse object provides access to response headers for the response. · Two properties of the HttpContext object, IsPostNotification and CurrentNotification, are used when one event handler handles several HttpApplication events. · The Headers and ServerVariables property of the HttpRequest object are write-enabled. |
An HttpApplication object is assigned to the request | After all application objects have been initialized, the application is started by creating an instance of the HttpApplication
class. If the application has a Global.asax file, ASP.NET instead
creates an instance of the Global.asax class that is derived from the HttpApplication class. It then uses the derived class to represent the application. Note The first time that an ASP.NET page or process is requested in an application, a new instance of the HttpApplication class is created. However, to maximize performance, HttpApplication instances might be reused for multiple requests. Which ASP.NET modules are loaded (such as the SessionStateModule) depends on the managed-code modules that the application inherits from a parent application. It also depends on which modules are configured in the configuration section of the application's Web.config file. Modules are added or removed in the application's Web.config modules element in the system.webServer section. For more information, see How to: Configure the <system.webServer> Section for IIS 7.0. |
The request is processed by the HttpApplication pipeline. | The following tasks are performed by the HttpApplication
class while the request is being processed. The events are useful for
page developers who want to run code when key request pipeline events
are raised. They are also useful if you are developing a custom module
and you want the module to be invoked for all requests to the pipeline.
Custom modules implement the IHttpModule interface. In Integrated mode in IIS 7.0, you must register event handlers in a module's Init method. 1. Validate the request, which examines the information sent by the browser and determines whether it contains potentially malicious markup. For more information, see ValidateRequest and Script Exploits Overview. 2. Perform URL mapping, if any URLs have been configured in the UrlMappingsSection section of the Web.config file. 3. Raise the BeginRequest event. 4. Raise the AuthenticateRequest event. 5. Raise the PostAuthenticateRequest event. 6. Raise the AuthorizeRequest event. 7. Raise the PostAuthorizeRequest event. 8. Raise the ResolveRequestCache event. 9. Raise the PostResolveRequestCache event. 10. Raise the MapRequestHandler event. An appropriate handler is selected based on the file-name extension of the requested resource. The handler can be a native-code module such as the IIS 7.0 StaticFileModule or a managed-code module such as the PageHandlerFactory class (which handles .aspx files). 11. Raise the PostMapRequestHandler event. 12. Raise the AcquireRequestState event. 13. Raise the PostAcquireRequestState event. 14. Raise the PreRequestHandlerExecute event. 15. Call the ProcessRequest method (or the asynchronous version IHttpAsyncHandler.BeginProcessRequest) of the appropriate IHttpHandler class for the request. For example, if the request is for a page, the current page instance handles the request. 16. Raise the PostRequestHandlerExecute event. 17. Raise the ReleaseRequestState event. 18. Raise the PostReleaseRequestState event. 19. Perform response filtering if the Filter property is defined. 20. Raise the UpdateRequestCache event. 21. Raise the PostUpdateRequestCache event. 22. Raise the LogRequest event. 23. Raise the PostLogRequest event. 24. Raise the EndRequest event. 25. Raise the PreSendRequestHeaders event. 26. Raise the PreSendRequestContent event. |
Page life cycle in IIS Integrated mode
Ex:In Integrated mode, the ASP.NET request-processing stages that are exposed to modules are directly connected to the corresponding stages of the IIS 7 pipeline. The complete pipeline contains the following stages, which are exposed as HttpApplication events in ASP.NET:
1. BeginRequest. The request processing starts.
2. AuthenticateRequest. The request is authenticated. IIS 7 and ASP.NET authentication modules subscribe to this stage to perform authentication.
3. PostAuthenticateRequest.
4. AuthorizeRequest. The request is authorized. IIS 7 and ASP.NET authorization modules check whether the authenticated user has access to the resource requested.
5. PostAuthorizeRequest.
6. ResolveRequestCache. Cache modules check whether the response to this request exists in the cache, and return it instead of proceeding with the rest of the execution path. Both ASP.NET Output Cache and IIS 7 Output Cache features execute.
7. PostResolveRequestCache.
8. MapRequestHandler. This stage is internal in ASP.NET and is used to determine the request handler.
9. PostMapRequestHandler.
10. AcquireRequestState. The state necessary for the request execution is retrieved. ASP.NET Session State and Profile modules obtain their data.
11. PostAcquireRequestState.
12. PreExecuteRequestHandler. Any tasks before the execution of the handler are performed.
13. ExecuteRequestHandler. The request handler executes. ASPX pages, ASP pages, CGI programs, and static files are served.
14. PostExecuteRequestHandler
15. ReleaseRequestState. The request state changes are saved, and the state is cleaned up here. ASP.NET Session State and Profile modules use this stage for cleanup.
16. PostReleaseRequestState.
17. UpdateRequestCache. The response is stored in the cache for future use. The ASP.NET Output Cache and IIS 7 Output Cache modules execute to save the response to their caches.
18. PostUpdateRequestCache.
19. LogRequest. This stage logs the results of the request, and is guaranteed to execute even if errors occur.
20. PostLogRequest.
21. EndRequest. This stage performs any final request cleanup, and is guaranteed to execute even if errors occur.
By using the familiar ASP.NET APIs, the ability to execute in the same stages as IIS 7 modules makes tasks that were only previously accessible in native ISAPI filters and extensions now possible in managed code.
For example, you can now write modules that do the following:
1. Intercept the request before any processing has taken place, for example rewriting URLs or performing security filtering.
2. Replace built-in authentication modes.
3. Modify the incoming request contents, such as request headers.
4. Filter outgoing responses for all content types.
See Developing an IIS 7 Module with .NET for a good example of how to extend IIS 7 with a custom ASP.NET authentication module.
Expanded ASP.NET APIs
The ASP.NET APIs remain backward compatible with previous releases, which allows existing modules to work in IIS 7 without modification, and to apply to all application content without code changes.
However, modules that are written for IIS 7 Integrated mode can take advantage of a few additional APIs to enable key request-processing scenarios that were not previously available.
The new HttpResponse.Headers collection allows modules to inspect and manipulate response headers that other application components generate. For example, you can change the Content-Type header that is generated by an ASP page to prompt a download dialog box in the browser. The Cookies collection on the HttpResponse class is also enhanced to allow modification of cookies that are generated as part of the request processing, even if they were created outside of ASP.NET.
The HttpRequest.Headers collection is write-enabled, which allows modules to manipulate the incoming request headers. Use this to change the behavior of other server components – for example, you can force a localized application to respond to the client in a different language by dynamically changing the value of the Accept-Language header.
Finally, the HttpRequest.ServerVariables collection is now writeable, which allows IIS 7 server variables to be set. ASP.NET modules use this functionality to change values that are provided by IIS 7, and to create new server variables that are visible to other application frameworks, like PHP.
Runtime Integration
In addition to the new APIs, Integrated mode enables existing ASP.NET functionality to provide more value to your application.
The tracing facilities that are provided by ASP.NET, including the System.Diagnostics.Trace class and the ASP.NET page tracing feature, now emit trace information into the IIS 7 trace system. This enables the trace information that is generated during request processing by both IIS 7 and ASP.NET components to be placed in a single log file, facilitating better diagnostics of server issues.
The ASP.NET response-filtering feature, which allows responses to be changed by using a Stream interface before it goes to the client, is enhanced to allow filtering of non-ASP.NET content. Therefore, you can use ASP.NET filtering on all server content, or selectively install the filter only for requests to content that you want to process. With this capability, you can write filtering features that inject or censor certain content in the site's responses, regardless of whether this content comes from an ASPX page or a static file.
Exploring Session in ASP.NET
Introduction
This
article will give you a very good understanding of session. In this
article, I have covered the basics of session, different ways of storing
session objects, session behaviour in web farm scenarios, session on
Load Balancer, etc. I have also explained details of session behaviour
in a live production environment. Hope you will enjoy this article and
provide your valuable suggestions and feedback.
What is Session?
Web is stateless,
which means a new instance of a web page class is re-created each time
the page is posted to the server. As we all know, HTTP is a stateless
protocol, it can't hold client information on a page. If the user
inserts some information and move to the next page, that data will be
lost and the user would not be able to retrieve that information. What
do we need here? We need to store information. Session provides a
facility to store information on server memory. It can support any type
of object to store along with our own custom objects. For every client,
session data is stored separately, which means session data is stored on
a per client basis. Have a look at the following diagram:
Fig: For every client, session data is stored separately
State
management using session is one of the best ASP.NET features, because
it is secure, transparent from users, and we can store any kind of
object in it. Along with these advantages, some times session can cause
performance issues in high traffic sites because it is stored in server
memory and clients read data from the server. Now let's have a look at
the advantages and disadvantages of using session in our web
applications.
Advantages and disadvantages of Session?
Following are the basic advantages and disadvantages of using session. I have describe in details with each type of session at later point of time.
Advantages:
· It helps maintain user state and data all over the application.· It is easy to implement and we can store any kind of object.
· Stores client data separately.
· Session is secure and transparent from the user.
Disadvantages:
· Performance overhead in case of large volumes of data/user, because session data is stored in server memory.· Overhead involved in serializing and de-serializing session data, because in the case of StateServer and SQLServer session modes, we need to serialize the objects before storing them.
Besides these, there are many advantages and disadvantages of session that are based on the session type. I have discussed all of them in the respective sections below.
Storing and retrieving values from Session
Storing and retrieving values in session are quite similar to that in ViewState. We can interact with session state with the System.Web.SessionState.HttpSessionState class, because this provides the built-in session object in ASP.NET pages.The following code is used for storing a value to session:
Collapse | Copy Code
//Storing UserName in Session
Session["UserName"] = txtUser.Text;
Now, let's see how we can retrieve values from session:
Collapse | Copy Code
//Check weather session variable null or not
if (Session["UserName"] != null)
{
//Retrieving UserName from Session
lblWelcome.Text = "Welcome : " + Session["UserName"];
}
else
{
//Do Something else
}
We can also store other objects in session. The following example shows how to store a DataSet in session.
Collapse | Copy Code
//Storing dataset on Session
Session["DataSet"] = _objDataSet;
The following code shows how we to retrieve that DataSet from session:
Collapse | Copy Code
//Check weather session variable null or not
if (Session["DataSet"] != null)
{
//Retrieving UserName from Session
DataSet _MyDs = (DataSet)Session["DataSet"];
}
else
{
//Do Something else
}
References:
· MSDN (read the session variable section)
Session ID
ASP.NET
uses a 120 bit identifier to track each session. This is secure enough
and can't be reverse engineered. When a client communicates with a
server, only the session ID is transmitted between them. When the client
requests for data, ASP.NET looks for the session ID and retrieves the
corresponding data. This is done in the following steps:
· Client hits the web site and information is stored in the session.
· Server creates a unique session ID for that client and stores it in the Session State Provider.
· The client requests for some information with the unique session ID from the server.
· Server looks in the Session Providers and retrieves the serialized data from the state server and type casts the object.
Take a look at the the pictorial flow:
Fig: Communication of client, web server, and State Provider
Session Mode and State Provider
In ASP.NET, there are the following session modes available:
· InProc
· StateServer
· SQLServer
· Custom
For every session state, there is a Session Provider. The following diagram will show you how they are related:
Fig: Session state architecture
We can choose the session state provider based on which session state we are selecting. When ASP.NET requests for information based on the session ID, the session state and its corresponding provider are responsible for sending the proper information. The following table shows the session mode along with the provider name:
Session State Mode | State Provider |
InProc | In-memory object |
StateServer | Aspnet_state.exe |
SQLServer | Database |
Custom | Custom provider |
Apart from that, there is another mode Off. If we select this option, the session will be disabled for the application. But our objective is to use session, so we will look into the above four session state modes.
Session States
Session
state essentially means all the settings that you have made for your
web application for maintaining the session. Session State itself is a
big thing. It says all about your session configuration, either in the web.config or from the code-behind. In the web.config,
<SessionState> elements are used for setting the configuration of
the session. Some of them are Mode, Timeout, StateConnectionString,
CustomProvider, etc. I have discussed about each and every section of
the connection string. Before I discuss Session Mode, take a brief
overview of session events.
References:
· Application and Session Events
Session Mode
I have already discussed about session modes in ASP.NET. Following are the different types of session modes available in ASP.NET:· Off
· InProc
· StateServer
· SQLServer
· Custom
If we set session Mode="off" in web.config, session will be disabled in the application. For this, we need to configure web.config the following way:
InProc Session Mode
This is the default session mode in ASP.NET. Its stores session information in the current Application Domain. This is the best session mode for web application performance. But the main disadvantage is that, it will lose data if we restart the server. There are some more advantages and disadvantages of the InProc session mode. I will come to those points later on.Overview of InProc session mode
As I have already discussed, in InProc mode, session data will be stored on the current application domain. So it is easily and quickly available.
InProc
session mode stores its session data in a memory object on the
application domain. This is handled by a worker process in the
application pool. So if we restart the server, we will lose the session
data. If the client request for data, the state provider read the data
from an in-memory object and returns it to the client. In web.config, we have to mention the session mode and also set the timeout.
The above session timeout setting keeps the session alive for 30 minute. This is configurable from the code-behind too.
Collapse | Copy Code
Session.TimeOut=30;
There are two types of session events available in ASP.NET: Session_Start() and Session_End and this is the only mode that supports the Session_End() event. This event is called after the session timeout period is over. The general flow for the InProc session state is like this:
When the Session_End() is called depends on the session timeout. This is a very fast mechanism because no serialization occurs for storing and retrieving data, and data stays inside the same application domain.
When should we use the InProc session mode?
InProc is the default session mode. It can be very helpful for a small web site and where the number of users is very less. We should avoid InProc in a Web Garden scenario (I will come to this topic later on).
Advantages and disadvantages
Advantages:
· It store session data in a memory object of the current application domain. So accessing data is very fast and data is easily available.
· There is not requirement of serialization to store data in InProc session mode.
· Implementation is very easy, similar to using the ViewState.
Disadvantages:
Although InProc session is the fastest, common, and default mechanism, it has a lot of limitations:
· If the worker process or application domain is recycled, all session data will be lost.
· Though it is the fastest, more session data and more users can affect performance, because of memory usage.
· We can't use it in web garden scenarios.
· This session mode is not suitable for web farm scenarios.
As per the above discussion, we can conclude that InProc is a very fast session storing mechanism but suitable only for small web applications. InProc session data will get lost if we restart the server, or if the application domain is recycled. It is also not suitable for Web Farm and Web Garden scenarios.
StateServer Session Mode
Overview of StateServer session mode
This
is also called Out-Proc session mode. StateServer uses a stand-alone
Windows Service which is independent of IIS and can also be run on a
separate server. This session state is totally managed by aspnet_state.exe.
This server may run on the same system, but it's outside of the main
application domain where your web application is running. This means if
you restart your ASP.NET process, your session data will still be alive.
This approaches has several disadvantages due to the overhead of the
serialization and de-serialization involved, it also increases the cost
of data access because every time the user retrieves session data, our
application hits a different process.
Configuration for StateServer session mode
In StateServer mode, session data is stored in a separate server which is independent of IIS and it is handled by aspnet_state.exe. This process is run as a Windows Service. You can start this service from the Windows MMC or from the command prompt.By default, the "Startup Type" of the ASP.NET state service is set to Manual; we have to set it to Automatic.
From the command prompt, just type "net start aspnet_state". By default, this service listens to TCP port 42424, but we can change the port from the Registry editor as show in the picture below:
Now have a look at the web.config configuration for the StateServer setting. For the StateServer setting, we need to specify the stateConnectionString. This will identify the system that is running the state server. By default, stateConnectionString used the IP 127.0.0.1 (localhost) and port 42424.
When we are using StateServer, we can configure the stateNetworkTimeOut attribute to specify the maximum number of seconds to wait for the service to respond before canceling the request. The default timeout value is 10 seconds.
For using StateServer, the object which we are going to store should be serialized, and at the time of retrieving, we need to de-serialize it back. I have described this below with an example.
We
use the StateServer session mode to avoid unnecessary session data loss
when restarting our web server. StateServer is maintained by the aspnet_state.exe
process as a Windows service. This process maintains all the session
data. But we need to serialize the data before storing it in StateServer
session mode.
As
shown in the above figure, when the client sends a request to the web
server, the web server stores the session data on the state server. The
StateServer may be the current system or a different system. But it will
be totally independent of IIS. The destination of the StateServer will
depend on the web.config stateConnectionString setting. If we set
it to 127.0.0.1:42424, it will store data in the local system itself.
For changing the StateServer destination, we need to change the IP, and
make sure aspnet_state.exe is up and running on that system. Otherwise you will get the following exception while trying to store data on session.
When we are storing an object on session, it should be serialized. That data will be stored in the StateServer system using the State Provider. And at the time of retrieving the data, the State Provider will return the data. The complete flow is given in the picture below:
Example of StateServer Session Mode
Here is a simple example of using the StateServer session mode. I have created this sample web application directly on IIS so that we can easily understand its usage.
Step 1: Open Visual Studio > File > New > Web Sites. Choose Location as HTTP and create the web application.
Now if you open IIS, you will see a virtual directory created with the name of your web application, in my case it is StateServer.
Step 2: Create s simple UI that will take the roll number and the name of a student. We will store the name and roll number in a state server session. I have also created a class StudentInfo. This class is listed below:
Collapse | Copy Code
[Serializable]
public class StudentInfo
{
//Default Constructor
public StudentInfo()
{
}
/// <summary>
/// Create object of student Class
/// </summary>
/// <param name="intRoll">Int RollNumber</param>
/// <param name="strName">String Name</param>
public StudentInfo(int intRoll, string strName)
{
this.Roll = intRoll;
this.Name = strName;
}
private int intRoll;
private string strName;
public int Roll
{
get
{
return intRoll;
}
set
{
intRoll = value;
}
}
public string Name
{
get
{
return strName;
}
set
{
strName = value;
}
}
}
Now have a look at the code-behind. I have added two buttons: one for storing session and another for retrieving session.
Collapse | Copy Code
protected void btnSubmit_Click(object sender, EventArgs e)
{
StudentInfo _objStudentInfo =
new StudentInfo(Int32.Parse( txtRoll.Text) ,txtUserName.Text);
Session["objStudentInfo"] = _objStudentInfo;
ResetField();
}
protected void btnRestore_Click(object sender, EventArgs e)
{
StudentInfo _objStudentInfo = (StudentInfo) Session["objStudentInfo"];
txtRoll.Text = _objStudentInfo.Roll.ToString();
txtUserName.Text = _objStudentInfo.Name;
}
Step 3: Configure your web.config for state server as I have already explained. And please make sure aspnet_state.exe is up and running on the configured server.
Step 4: Run the application.
Enter the data, click on Submit.
There are the following tests that I have made which will totally explain how exactly StateServer is useful.
First: Remove the [Serializable ] keyword from the StudentInfo class and try to run the application. When you click on the Submit button, you will get the following error:
Which clearly says that you have to serialize the object before storing it.
Second: Run the application, store data by clicking on the Submit button. Restart IIS.
In the case of InProc, you will have already lost your session data, but with StateServer, click on Restore Session and you will get your original data, because StateServer data does not depend on IIS. It keeps it separately.
Third: Stop aspnet_state.exe from the Windows Services MMC and submit the data. You will get the following error:
because your State Server process is not running. So please keep in mind these three points when using StateServer mode.
Advantages and Disadvantages
Based on the above discussion:
Advantages:
· It keeps data separate from IIS so any issues with IIS will not hamper session data.
· It is useful in web farm and web garden scenarios.
Disadvantages:
· Process is slow due to serialization and de-serialization.
· State Server always needs to be up and running.
I am stopping here on StateServer, you will find some more interesting points on it in the Load Balancer, Web Farm, and Web Garden section.
References:
· State Server Session Mode
· ASP.NET Session State
SQLServer Session Mode
Overview of SQL Server Session Mode
This session mode provide us more secure and reliable session management in ASP.NET. In this session mode, session data is serialized and stored in A SQL Server database. The main disadvantage of this session storage method is the overhead related with data serialization and de-serialization. It is the best option for using in web farms though.
To setup SQL Server, we need these SQL scripts:
· For installing: InstallSqlState.sql
· For uninstalling: UninstallSQLState.sql
The easiest way to configure SQL Server is using the aspnet_regsql command.
I have explained in detail the use of these files in the configuration section. This is the most useful state management in web farm scenarios.
When should we use SQLServer Session Mode?
· SQL Server session mode is a more reliable and secure session state management.
· It keeps data in a centralized location (database).
· We should use the SQLServer session mode when we need to implement session with more security.
· If there happens to be frequent server restarts, this is an ideal choice.
· This is the perfect mode for web farm and web garden scenarios (I have explained this in detail later).
· We can use SQLServer session mode when we need to share session between two different applications.
Configuration for SQLServer Session Mode
In SQLServer session mode, we store session data in SQL Server, so we need to first provide the database connection string in web.config. The sqlConnectionString attribute is used for this.
After we setup the connection string, we need to configure the SQL Server. I will now explain how to configure your your SQL Server using the aspnet_regsql command.
Step 1: From command prompt, go to your Framework version directory. E.g.: c:\windows\microsoft.net\framework\<version>.
Step 2: Run the aspnet_regsql command with the following parameters:
Have a look at the parameters and their uses:
Parameters | Description |
-ssadd | Add support for SQLServer mode session state. |
-sstype p | P stands for Persisted. It persists the session data on the server. |
-S | Server name. |
-U | User name. |
-P | Password. |
That's all.
Step 3: Open SQL Server Management Studio, check if a new database ASPState has been created, and there should be two tables:
· ASPStateTempApplications
· ASPStateTempSessions
Change the configuration string of the StateServer example and run the same sample application.
Just store the roll number and user name and click on the Submit button. Open the ASPStateTempSessions table from SQL Server Management Studio.. here is your session data:
Now do the following test that I have already explained in the StateServer mode section:
1. Remove the Serialize keyword from the StydentInfo class
2. Reset IIS and click on Restore Session
3. Stop SQL Server Services
I think I have explained the SQLServer session mode well.
Advantages and Disadvantages
Advantages:
· Session data not affected if we restart IIS.
· The most reliable and secure session management.
· It keeps data located centrally, is easily accessible from other applications.
· Very useful in web farms and web garden scenarios.
Disadvantages:
· Processing is very slow in nature.
· Object serialization and de-serialization creates overhead for the application.
· As the session data is handled in a different server, we have to take care of SQL Server. It should be always up and running.
References:
· Read more about SQLServer mode
Custom Session Mode
Commonly
we use the InProc, StateServer, or SQLServer session modes for our
application, but we also need to know the fundamentals of the Custom
session mode. This session mode is quite interesting, because Custom
session gives full control to us to create everything, even the session
ID. You can write your own algorithm to generate session IDs.
You
can implement custom providers that store session data in other storage
mechanisms simply by deriving from the SessionStateStoreProviderBase
class. You can also generate a new session ID by implementing
ISessionIDManager.
These are the methods called during the implementation of Custom session:
In
the Initialize method, we can set a custom provider. This will
initialize the connection with that provider. SetItemExpireCallback is
used to set SessionTimeOut. We can register a method that will be called
at the time of session expiration. InitializeRequest is called on every
request and CreateNewStoreData is used to create a new instance of
SessionStateStoreData.
We can use Custom session mode in the following cases:
· We want to store session data in a place other than SQL Server.
· When we have to use an existing table to store session data.
· When we need to create our own session ID.
We need to configure our web.config like this:
If you want to explore this more, please check the References section.
Advantages and Disadvantages
Advantages:
· We can use an existing table for storing session data. This is useful when we have to use an existing database.
· It's not dependent on IIS, so restarting the web server does not have any effect on session data.
· We can crate our own algorithm for generating session ID.
Disadvantages:
· Processing of data is very slow.
· Creating a custom state provider is a low-level task that needs to be handled carefully to ensure security.
It is always recommended to use a third party provider rather than create your own.
References:
Overview of production deployment
Production
environments are where we deploy our applications on a live production
server. It is a major and big challenge for web developers to deploy
their applications on a live server, because in a big production
environment, there are a large number of users and it is hard to handle
the load for so many users with a single server. Here comes in the
concepts of Web Farm, Load Balancer, Web Garden, etc.
Just
a few months back, I deployed a web application in a live production
environment which is accessed by millions of user and there were more
than 10 Active Directory instances, more than 10 web servers over a Load
Balancer, and several database server, Exchange Server, LCS Server,
etc. The major risk involved in multiple servers is session management.
The following picture shows a general diagram of production
environments:
I will try to explain the different scenarios that you need to keep in mind while deploying your application.
Application Pool
This
is one of the most important things you should create for your
applications in a production environment. Application pools are used to
separate sets of IIS worker processes that share the same configuration.
Application pools enable us to isolate our web application for better
security, reliability, and availability. The worker process serves as
the process boundary that separates each application pool so that when
one worker process or application has an issue or is recycled, other
applications or worker processes are not affected.
Identity of Application Pool
Application
pool identity configuration is an important aspect of security in IIS
6.0 and IIS 7.0, because it determines the identity of the worker
process when the process is accessing a resource. In IIS 7.0, there are
three predefined identities that are the same as in IIS 6.0.
Application Pool Identity | Description |
LocalSystem | Built-in account that has administrative privileges on the server. It can access both local and remote resources. For any kind accessing of server files or resources, we have to set the identity of the application pool to LocalSystem. |
LocalServices | Built-in account has privileges of an authenticated local user account. It does not have any network access permission. |
NetworkServices | This is the default identity of Application Pool. NetworkServices has the privileges of an authenticated local user account. |
Open IIS Console, right click on Application Pool Folder > Create New.
Give the Application Pool ID and click OK.
Now,
right click on the Virtual Directory (I am using StateServer web sites)
and assign StateServerAppPool to the StateServer Virtual Directory.
So
this StateServer web site will run independently with
StateServerAppPool. Any problem related with other applications will not
affect this application. This is the main advantage of creating
application pools separately.
Web Garden
By default, each application pool runs with a single worker process (W3Wp.exe).
We can assign multiple worker processes with a single application pool.
An application pool with multiple worker processes is called a Web
Garden. Many worker processes with the same Application Pool can
sometimes provide better throughput performance and application response
time. And each worker process should have its own Thread and memory
space.
As
shown in the picture, in IIS, there may be multiple application pools
and each application pool will have at least one worker process. A Web
Garden should contain multiple worker processes.
There
are certain restrictions in using a Web Garden with your web
application. If we use the InProc session mode, our application will not
work correctly because the session will be handled by a different
worker process. To avoid this problem, we should use the OutProc session
mode and we can use a session state server or SQL-Server session state.
Main advantage:
The worker processes in a Web Garden share the requests that arrive for
that particular application pool. If a worker process fails, another
worker process can continue processing the requests.
Right click on Application Pool > Go to Performance tab > Check Web Garden section (highlighted in picture):
By default, it would be 1. Just change it to more than one.
I
have already explained that InProc is handled by a worker process. It
keeps data inside its memory object. Now if we have multiple worker
processes, then it would be very difficult to handle the session because
each and every worker process has its own memory, so if my first
request goes to WP1 and it keeps my session data and the second request
goes to WP2, I am trying to retrieve session data and it will not be
available, which will throw an error. So please avoid Web Gardens in
InProc session mode.
We
can use StateServer or SQLServer session modes in Web Gardens because as
I have already explained, these two session modes do not depend on
worker processes. In my example, I have also explained that if you
restart IIS, you are still able to access your session data.
In short:
Session Mode | Recommended |
InProc | No |
StateServer | Yes |
SQLServer | Yes |
Web Farm and Load Balancer
This
is the most common terms that are used in production deployments. These
terms come in when we are using multiple web servers for deploying our
applications. The main reason for using these is we have to distribute
the load over multiple servers. A Load Balancer is used to distribute
the load on multiple servers.
If
we take a look at the above diagram, the client request the URL and it
will hit a Load Balancer, which decides which server to access. The load
balancer will distribute the traffic over all the different web
servers.
Now how does this affect Session?
Handling session is one of the most challenging jobs in a web farm.
InProc:
In InProc session mode, session data is stored in an in-memory object
of the worker process. Each server will have its own worker process and
will keep session data inside its memory.
If
one server is down, and if the request goes to a different server, the
user is not able to get session data. So it is not recommended to use
InProc in Web Farms.
StateServer:
I have already explained what a state server is and how to configure a
state server, etc. For web farm scenarios, you can easily understand how
much this is important because all session data will be stored in a
single location.
Remember,
in a web farm, you have to make sure you have the same
<machinekey> in all your web servers. Other things are the same as
I have describe earlier. All web.config files will have the same configuration (stateConnectionString) for session state.
SQL Server:
This is another approach, the best that we can use in a web farm. We
need to configure the database first. The required steps have been
explained covered.
As
shown in the above picture, all web server session data will be stored
in a single SQL Server database. And it is easily accessible. Keep one
thing in mind, you should serialize objects in both StateServer and
SQLServer modes. If one of the web servers go down, the load balancer
will distribute the load to other servers and the user will still be
able to read session data from the server, because data is stored in a
centralized database server.
In summary, we can use either StateServer or SQLServer session mode in a web farm. We should avoid InProc.
Session and Cookies
Clients
use cookies to work with session. Because clients need to present the
appropriate session ID with each request. We can do this in the
following ways:
Using cookies
ASP.NET
creates a special cookie named ASP.NET_SessionId automatically when a
session collection is used. This is the default. Session ID is
transmitted through that cookie.
cookie is a small bit of text that accompanies requests and pages as
they go between the Web server and browser. The cookie contains
information the Web application can read whenever the user visits the
site.
For example, if a
user requests a page from your site and your application sends not just a
page, but also a cookie containing the date and time, when the user's
browser gets the page, the browser also gets the cookie, which it stores
in a folder on the user's hard disk.
Later,
if user requests a page from your site again, when the user enters the
URL the browser looks on the local hard disk for a cookie associated
with the URL. If the cookie exists, the browser sends the cookie to your
site along with the page request. Your application can then determine
the date and time that the user last visited the site. You might use the
information to display a message to the user or check an expiration
date.
Cookies are
associated with a Web site, not with a specific page, so the browser and
server will exchange cookie information no matter what page the user
requests from your site. As the user visits different sites, each site
might send a cookie to the user's browser as well; the browser stores
all the cookies separately.
Cookies
help Web sites store information about visitors. More generally,
cookies are one way of maintaining continuity in a Web application—that
is, of performing state management. Except for the brief time when they
are actually exchanging information, the browser and Web server are
disconnected. Each request a user makes to a Web server is treated
independently of any other request. Many times, however, it's useful for
the Web server to recognize users when they request a page. For
example, the Web server on a shopping site keeps track of individual
shoppers so the site can manage shopping carts and other user-specific
information. A cookie therefore acts as a kind of calling card,
presenting pertinent identification that helps an application know how
to proceed.
Cookies are
used for many purposes, all relating to helping the Web site remember
users. For example, a site conducting a poll might use a cookie simply
as a Boolean value to indicate whether a user's browser has already
participated in voting so that the user cannot vote twice. A site that
asks a user to log on might use a cookie to record that the user already
logged on so that the user does not have to keep entering credentials.
Cookie Limitations
Most
browsers support cookies of up to 4096 bytes. Because of this small
limit, cookies are best used to store small amounts of data, or better
yet, an identifier such as a user ID. The user ID can then be used to
identify the user and read user information from a database or other
data store. (See the section "Cookies and Security" below for
information about security implications of storing user information.)
Browsers
also impose limitations on how many cookies your site can store on the
user's computer. Most browsers allow only 20 cookies per site; if you
try to store more, the oldest cookies are discarded. Some browsers also
put an absolute limit, usually 300, on the number of cookies they will
accept from all sites combined.
A
cookie limitation that you might encounter is that users can set their
browser to refuse cookies. If you define a P3P privacy policy and place
it in the root of your Web site, more browsers will accept cookies from
your site. However, you might have to avoid cookies altogether and use a
different mechanism to store user-specific information. A common method
for storing user information is session state, but session state
depends on cookies, as explained later in the section "Cookies and
Session State."
Writing Cookies
The browser is responsible for managing cookies on a user system. Cookies are sent to the browser via the HttpResponse object that exposes a collection called Cookies. You can access the HttpResponse object as the Response property of your Page
class. Any cookies that you want to send to the browser must be added
to this collection. When creating a cookie, you specify a Name and Value.
Each cookie must have a unique name so that it can be identified later
when reading it from the browser. Because cookies are stored by name,
naming two cookies the same will cause one to be overwritten.
You
can also set a cookie's date and time expiration. Expired cookies are
deleted by the browser when a user visits the site that wrote the
cookies. The expiration of a cookie should be set for as long as your
application considers the cookie value to be valid. For a cookie to
effectively never expire, you can set the expiration date to be 50 years
from now.
Cookies with More Than One Value
You
can store one value in a cookie, such as user name and last visit. You
can also store multiple name-value pairs in a single cookie. The
name-value pairs are referred to as subkeys. (Subkeys are laid out much
like a query string in a URL.) For example, instead of creating two
separate cookies named userName and lastVisit, you can create a single
cookie named userInfo that has the subkeys userName and lastVisit.
You
might use subkeys for several reasons. First, it is convenient to put
related or similar information into a single cookie. In addition,
because all the information is in a single cookie, cookie attributes
such as expiration apply to all the information. (Conversely, if you
want to assign different expiration dates to different types of
information, you should store the information in separate cookies.)
Reading Cookies
When
a browser makes a request to the server, it sends the cookies for that
server along with the request. In your ASP.NET applications, you can
read the cookies using the HttpRequest object, which is available as the Request property of your Page class. The structure of the HttpRequest object is essentially the same as that of the HttpResponse object, so you can read cookies out of the HttpRequest object much the same way you wrote cookies into the HttpResponse object. The following code example shows two ways to get the value of a cookie named username and display its value in a Label control:
Cookie munging
Some
older browsers do not support cookies or the user may disable cookies
in the browser, in that case, ASP.NET transmits session ID in a
specially modified (or “munged”) URL.
When
the user requests for a page on a server, the server encoded the
session ID and adds it with every HREF link in the page. When the user
clicks on a link, ASP.NET decodes that session ID and passes it to the
page that the user is requesting. Now the requesting page can retrieve
session variables. This all happens automatically if ASP.NET detects
that the user's browser does not support cookies.
For this, we have to make our session state cookie-less.
Ex: <SesstionState Cookieless=”true”></SesstionState>
Removing Session
Following are the list of methods that are used to remove Session:
Method | Description |
Session.Remove(strSessionName); | Removes an item from the session state collection. |
Session.RemoveAll() | Removes all items from the session collection. |
Session.Clear() | Remove all items from session collection. Note: There is no difference between Clear and RemoveAll. RemoveAll() calls Clear() internally. |
Session.Abandon() | Cancels the current session. |
Enabling and disabling Session
For
performance optimization, we can enable or disable session because each
and every page read and write access of the page involves some
performance overhead. So it is always better to enable and disable
session based on requirements rather than enable it always. We can
enable and disable session state in two ways:
· Page level
· Application level
Page level
We can disable session state in page level using the EnableSessionState attribute in the Page directive.
This will disable the session activities for that particular page.
The same way, we can make it read-only also. This will permit to access session data but will not allow writing data on session.
Application level
Session state can be disabled for the entire web application using the EnableSessionState property in Web.Config.
Generally we use page level because some pages may not require any session data or may only read session data.
Introduction
This article is a beginner's tutorial on ASP.NET caching mechanism. We will try to see different types of caching available in ASP.NET and which caching technique is right for which scenario. We will also try to see how can we customize the caching behaviour so that it suits our needs.Background
As
ASP.NET web developers, we are mostly involved in developing web pages
that are dynamic, i.e., contents coming from databases, Server
directories, XML files or getting pulled from some other websites.
Caching means to store something in memory that is being used frequently
to provide better performance. Now can we think of the usability of
caching in ASP.NET.
Let us
imagine a scenario when the contents of a web page are being pulled
from a database. The user asks for contents depending on some criteria.
Now if the database is getting changed very frequently that even between
two requests of same user, we anticipate database change, then we can
in no way cache the data that the user is requesting. But if the
database is not getting changed that frequently, we can have some
caching in place so that if the user is requesting the same data very
frequently, we don't hit the database every time (since we know contents
are not changed).
The two
keys terms here are frequency and criteria. Frequency is the number of
times we are anticipating the user requests for a particular page and
criteria is what governs the uniqueness of result that is being
displayed on the page.
Frequency
is important because we need to figure out the interval in which
database is changing and compare it with the frequency of user requests
so that we can have caching in place and also make sure that user is not
viewing out dated data.
Criteria
is important because we need to make sure that we have caching
implemented for the page on every unique criteria. It should not be the
case that user is requesting contents based on
criteria01
and we are showing him the cached results of criteria00
(cached earlier for him).
So
with all this theory in mind, let's go ahead and see how ASP.NET
provides caching features without us writing a lot of code to manage the
same.
Types of Caching
There are two types of caching available in ASP.NET:1. Page Output Caching
2. Application Caching
Page Output Caching
Page
output caching refer to the ability of the web server to cache a
certain webpage after user request in its memory so that further
requests for the same page will check for the cached page's validity and
will not result in resource usage (DB access or file access) and the
page will be returned to user from cache.
Now
the question is how can we ensure that the user is not viewing the out
dated data. ASP.NET provides us various configuration options which will
let us program in such a way that we can ensure that the user never
gets stale data.
Let us
have a simple web page with a textbox, button and a label. Right now,
the caching is not enabled for this page so everytime the postback
occurs, the request to the web server is made. We can verify this by
displaying the current time in the label.
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
}
Now let us go ahead and enable caching for this page by adding the following declaration to the page:
<%@ OutputCache Duration="30" VaryByParam="none" %>
Here we are saying that this page should be cached for 30 seconds, We can verify this by pressing the button. The time string will not change for 30 seconds and the second property
VaryByParam
specifies that caching doesn't depend on anything doing so can lead to a
situation where user can see stale data, like in our case for 30
seconds if we write something in textbox and do a postback, it will keep
reverting to the old data that was in the textbox at the time page was
cached. So it's a good idea to say that the cached page is not valid if the data in textbox is changed so let's do that now:
<%@ OutputCache Duration="30" VaryByParam="TextBox1" %>
So now we can see that the page output will be cached as long as the contents of the
textbox
are not changed. If we change the contents of the textbox
, then the server processes the page again and then caches it again. So what we saw is that we can specify the
Duration
the page should be cached which is related to the talk about frequency we did earlier. The Duration
should be chosen so that during that time we are not expecting any change in data and for the criteria, we saw how we can use VaryByCustom
to make sure that the output for every different criteria is generated and the cached copy is not just presented to the user.
Let us look as some other parameters that we can use to customize caching behavior.
·VaryByParam
: List ofstring
s that are sent to server viaPOST
that are checked to validate cache
·VaryByControl
: List of controls whose value will determine the validity of cache
·SqlDependency
: Defines the Database-tablename pair on which the validity of cache depends
·VaryByCustom
: Used for custom output cache requirements
·VaryByHeader
: HTTPs header that determines the cache validity
If we need different output pages based on query
string
, then we can specify the list of querystring
parameters here or we can simply say VaryByParam ="*"
to do the same for all querystring
parameters. Now let us just have a quick look at what we need to do if we need to change the cached page based on query string
parameter. <%@ OutputCache Duration="30" VaryByParam="name" %>
protected void Button2_Click(object sender, EventArgs e)
{
int name;
if (Request.QueryString["name"] == null)
{
name = 1;
}
else
{
name = Convert.ToInt32(Request.QueryString["name"]) + 1;
}
Response.Redirect("varybyqs.aspx?name=" + name.ToString());
}
In order to cache a page's output, we need to specify an
@OutputCache
directive at the top of the page. The syntax is as shown below:
<%@ OutputCache Duration=5 VaryByParam="None" %>
As you can see, there are two attributes to this directive. They are:
Duration
- The time in seconds of how long the output should be cached. After the specified duration has elapsed, the cached output will be removed and page content generated for the next request. That output will again be cached for 10 seconds and the process repeats.VaryByParam
- This attribute is compulsory and specifies the querystring parameters to vary the cache.
In the above snippet, we have specified theVaryByParam
attribute asNone
which means the page content to be served is the same regardless of the parameters passed through the querystring [see Example 1 in the sample download].
If there are two requests to the same page with varying querystring parameters, e.g.: .../PageCachingByParam.aspx?id=12 and .../PageCachingByParam.aspx?id=15] and separate page content is generated for each of them, the directive should be:
<%@ OutputCache Duration=5 VaryByParam="id" %>
The page content for the two requests will each be cached for the time specified by theDuration
attribute [see Example 2 in the sample download].
To specify multiple parameters, use semicolon to separate the parameter names. If we specify theVaryByParam
attribute as*
, the cached content is varied for all parameters passed through the querystring.
Some pages generate different content for different browsers. In such cases, there is provision to vary the cached output for different browsers. The
@OutputCache
directive has to be modified to: <%@ OutputCache Duration=5 VaryByParam="id" VaryByCustom="browser" %>
This will vary the cached output not only for the browser but also its major version. I.e., IE5, IE 6, Netscape 4, Netscape 6 will all get different cached versions of the output.
Partial Page Caching (or) Fragment Caching
Sometimes we might want to cache just portions of a page. For example, we might have a header for our page which will have the same content for all users. There might be some text/image in the header which might change everyday. In that case, we will want to cache this header for a duration of a day.
The solution
is to put the header contents into a user control and then specify that
the user control content should be cached. This technique is called fragment caching.
To specify that a user control should be cached, we use the
@OutputCache
directive just like we used it for the page.
<%@ OutputCache Duration=10 VaryByParam="None" %>
With the above directive, the user control content will be cached for the time specified by the
Similar
to output caching, partial page caching allows you to cache certain
blocks of your website. You can, for example, only cache the center of
the page. Partial page caching is achieved with the caching of user
controls. You can build your ASP.NET pages consisting of numerous user
controls and then apply output caching on the user controls you select.
This will cache only parts of the page that you want, leaving other
parts of the page outside the reach of caching. This is a very nice
feature, and if done correctly, it can lead to pages that perform
better. Duration
attribute [10 secs]. Regardless of the querystring parameters and
browser type and/or version, the same cached output is served. [See
Example 3 in the download for a demonstration]. Note: Typically, UserControls are placed on multiple pages to maximize reuse. However, when these UserControls (ASCX files) are cached with the
@OutputCache
directive, they are cached on a per page basis. That means even if a User Control outputs identical HTML when placed on pageA.aspx as it does when placed on pageB.aspx, its output is cached twice. You can prevent this happening by adding Shared = true
in the output cache directive.
<%@ OutputCache Duration="300" VaryByParam="*" Shared="true" %>
By putting the
Shared
attributed, the memory savings can be surprisingly large. If you have an ASCX User control using the OutputCache
directive, remember that the User Control exists only for the first request. Also, if we have a requirement for partial page caching (Fragment caching), we can simply use the controls that require caching and put them in a user control. We can then use the same above mentioned technique to enable caching behaviour in the custom control and we have partial page caching in place. (See the code for implementation.)
Note: The above mentioned approaches enabled us to use caching by using declarations on the page. We can also control caching programmatically.
Application Data Caching
Output caching and partial page caching is useful if you want to cache the output of a page. However, if you like to cache a
DataSet
object or any collection object, you can use data caching to implement that.
ASP.NET has a class called
Cache
to cache specific data items for later use on a particular page or group of pages. The Cache
enables you to store everything from simple name/value pairs to more complex objects like datasets and entire aspx pages.
To store data into the cache, you can use the code below:
C#
Cache["MyDataSet"] = myDataSet;
To retrieve data from the cache, you can use the code below:
C#
DataSet ds = new DataSet();
ds = (DataSet) Cache["MyDataSet"];
Application data caching is a mechanism for storing the
Data
objects on cache. It has nothing to do with the page caching. ASP.NET allows us to store the object in a Key
-Value
based cache. We can use this to store the data that need to cached. Let us work on the same example and try to store the DateTime
object in the Application Cache now. protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
Cache["time"] = DateTime.Now;
}
Label1.Text = ((DateTime)Cache["time"]).ToLongTimeString();
}
What this code will do is that it will store the
DateTime
object in application cache and will keep displaying the time of initial request by using the object from the cache.
There are various parameters associated with application data caching that can be used to control its behavior.
·Dependencies
: Any file or item in cache that invalidates this cache item
·absoluteExpiration
: Absolute time when this object should be removed from cache
·slidingExpiration
: Relative time when this object should be removed from the cache
·priority
: Defines the priority of the item. This is useful when server runs out of memory as in that case it start removing items from cache with lowest priority first
·onRemoveCallBack
: This is the event handler that will be called when the object is removed from cache. It gives us a place to take further actions.
Understanding Asp.net Cache Sliding Expiration and Absolute Expiration
Asp .Net provides two different ways to expire the cache on the basis of time. Here are two approaches:-
- Sliding Expiration
- Absolute Expiration
1. Absolute Expiration
Absolute expiration means that your data will be removed from cache after fixed amount of time either it is accessed or not. Generally we use it when we are displaying data which is changing but we can afford to display outdated data in our pages. Mostly I put all of my dropdown values in cache with Absolute Expiration. Here is how you can code:-
DataTable dt = GetDataFromDatabase();
Cache.Insert("AbsoluteCacheKey", dt, null,
DateTime.Now.AddMinutes(1), //Data will expire after 1 minute
System.Web.Caching.Cache.NoSlidingExpiration);
2. Sliding Expiration
Sliding expiration means that your data will be removed from cache if that is not accessed for certain amount of time. Generally we store that data in this cache mode which is accessed many time on certain occasions. For example if you go in account settings section of a site, then you will be frequently accessing account information in that section. But most of the time you wont be using account setting's related data so there is no point of storing that data in cache. In such scenarios sliding expiration should be used. here is how you can save data in cache with sliding expiration:-
DataTable dt = GetDataFromDatabase();
Cache.Insert("SlidingExpiration", data, null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
TimeSpan.FromMinutes(1));//Data will be cached for 1 mins
What is state management?
Web is
Stateless
. It means a new instance of the web page class is re-created each time the page is posted to the server. As we all know HTTP
is a stateless protocol, its can't holds the client information on
page. As for example , if we enter a text and client on submit button,
text does not appear after post back , only because of page is recreated
on its round trip.
As
given in above pages, page is recreated before its comes to clients and
happened for each and every request. So it is a big issue to maintain
the state of the page and information for a web application. That is the
reason to start concept of
State Management
. To overcome this problem ASP.NET 2.0 Provides some features like View State, Cookies, Session, Application objects
etc. to manage the state of page.
There
are some few selection criteria to selected proper way to maintain the
state, as there are many way to do that. Those criteria are:
· How much information do you need to store?
· Does the client accept persistent or in-memory cookies?
· Do you want to store the information on the client or on the server?
· Is the information sensitive?
· What performance and bandwidth criteria do you have for your application?
· What are the capabilities of the browsers and devices that you are targeting?
· Do you need to store information per user?
· How long do you need to store the information?
·
Do you have a Web farm (multiple servers), a Web garden (multiple
processes on one machine), or a single process that serves the
application?
So,
when ever you start to think about state management, you should think
about above criteria. based on that you can choose the best approaches
for manages state for your web application.
Different types of state management?
There are two different types of state management:
1. Client Side State Management
oView State
oHidden Field
oCookies
oControl State
2. Server Side State Management
oSession
oApplication Object
oCaching
oDatabase
Client
Side state management does not use any server resource , it store
information using client side option. Server Side state management use
server side resource for store data. Selection of client side and server
side state management should be based on your requirements and the
selection criteria that are already given.
What is view state?
View State
is one of the most important and useful client side state management mechanism. It can store the page value at the time of post back (Sending and Receiving information from Server)
of
your page. ASP.NET pages provide the ViewState property as a built-in
structure for automatically storing values between multiple requests for
the same page. Example:If you want to add one variable in View State,ViewState["Var"]=Count;For Retrieving information from View Statestring Test=ViewState["TestVal"];
Sometimes
you may need to typecast ViewState Value to retreive. As I give an
Example to strore and retreive object in view state in the last of
this article.
Advantages of view state?
This are the main advantage of using View State:
· Easy to implement
· No server resources are required
· Enhanced security features ,like it can be encoded and compressed.
Disadvantages of view state?
This are the main disadvantages of using View State:
· It can be performance overhead if we are going to store larger amount of data , because it is associated with page only.
· Its stored in a hidden filed in hashed format (which I have discussed later) still it can be easily trapped.
· It does not have any support on mobile devices.
When we should use view state?
I
already describe the criteria of selecting State management. A few
point you should remember when you select view state for maintain your
page state.
·
Size of data should be small , because data are bind with page controls
, so for larger amount of data it can be cause of performance overhead.
· Try to avoid storing secure data in view state
When we should avoid view state?
You won't need view state for a control for following cases,
· The control never change
· The control is repopulated on every postback
· The control is an input control and it changes only of user actions.
Where is view state stored?
View
State stored the value of page controls as a string which is hashed and
encoded in some hashing and encoding technology. It only contain
information about page and its controls. Its does not have any
interaction with server. It stays along with the page in the Client
Browser. View State use
Hidden
field to store its information in a encoding format.
Suppose you have written a simple code , to store a value of control:
ViewState["Value"] = MyControl.Text;
Now, Run you application, In Browser,
RighClick
> View
Source
, You will get the following section of code
Fig : View state stored in hidden field
Now
, look at the value. looks likes a encrypted string, This is Base64
Encoded string, this is not a encoded string. So it can easily be
decoded. Base64 makes a string suitable for HTTP transfer plus it makes
it a little hard to read . Read More about Base64 Encoding . Any body can decode that string and read the original value. so be careful about that. There is a
security lack
of view state. How to store object in view state?
We
can store an object easily as we can store string or integer type
variable. But what we need ? we need to convert it into stream of byte.
because as I already said , view state store information in hidden filed
in the page. So we need to use
Serialization
. If object which we are trying to store in view state ,are not serializable , then we will get a error message .
Just take as example,
//Create a simple class and make it as Serializable
[Serializable]
public class student
{
public int Roll;
public string Name;
public void AddStudent(int intRoll,int strName)
{
this.Roll=intRoll;
this.Name=strName;
}
}
Now we will try to store object of "Student
" Class in a view state.
//Store Student Class in View State
student _objStudent = new student();
_objStudent.AddStudent(2, "Abhijit");
ViewState["StudentObject"] = _objStudent;
//Retrieve Student information view state
student _objStudent;
_objStudent = (student)ViewState["StudentObject"];
How to trace your view state information?
If you want to trace your view state information, by just enable "
Trace
" option of Page Directive
Now Run your web application, You can view the details of View State Size along with control ID in
Control Tree
Section. Don't worry about "Render Size Byte
" , this only the size of rendered control.
Fig : View State Details
Enabling and Disabling View State
You
can enable and disable View state for a single control as well as at
page level also. To turnoff view state for a single control , set
Enable
ViewState Property of that control to false. e.g.:
TextBox1.EnableViewState =false;
To turnoff the view state of entire page, we need to set
Enable
ViewState to false of Page Directive as shown bellow.
Even
you disable view state for the entire page , you will see the hidden
view state tag with a small amount of information, ASP.NET always store
the controls hierarchy for the page at minimum , even if view state is
disabled.
For enabling the same, you have to use the same property just set them as True
as for example, for a single control we can enabled view state in following way,
TextBox1.EnableViewState =true;
and for a page level,
How to make view state secure?
As I already discuss View state information is stored in a hidden filed in a form of
Base64 Encoding
String, and it looks like:
Fig : View state stored in hidden field
Many of ASP.NET Programmers assume that this is an
Encrypted format
, but I am saying it again, that this is not a encrypted string. It can be break easily. To make your view state secure, There are two option for that,
· First, you can make sure that the view state information is tamper-proof by using
"hash code"
. You can do this by adding "Enable
ViewStateMAC=true
" with your page directive. MAC Stands for "Message Authentication Code"
A
hash code
, is a cryptographically strong checksum
,
which is calculated by ASP.NET and its added with the view state
content and stored in hidden filed. At the time of next post back, the
checksum data again verified , if there are some mismatch, Post back
will be rejected. we can set this property to web.config file also.
· Second option is to set ViewState
EncryptionMode="Always"
with your page directives, which will encrypt the view state data. You can add this in following way
It ViewState
EncryptionMode
has three different options to set:
· Always
· Auto
· Never
Always
, mean encrypt the view state always, Never
means, Never encrypt the view state data and Auto
Says , encrypt if any control request specially for encryption. For auto , control must call Page.RegisterRequires
ViewStateEncryption()
method for request encryption.
we can set the Setting for "
Enable
ViewStateMAC"
and ViewStateEncryptionMode"
in web.config also. Note :
Try to avoid View State Encryption if not necessary , because it cause the performance issue ASP.NET Page Life Cycle with State Management objects
Introducing Viewstate Outside the ASP.NET Context
In its very basic form, Viewstate is nothing more than a property which has a key/value pair indexer:
Viewstate[“mystringvariable”] = “myvalue”;
Viewstate[“myintegervariable”] = 1;
As you can see, the indexer accepts a string as a key and an object as the value. The ViewState property is defined in the “
System.Web.UI.Control
”
class. Since all ASP.NET pages and controls derive from this class,
they all have access to the ViewState property. The type of the
ViewState property is “System.Web.UI.StateBag
”.
The very special thing about the
StateBag
class is the ability to “track changes”. Tracking is, by nature, off; it can be turned on by calling the “Track
ViewState()
” method. Once tracking is on, it cannot be turned off. Only when tracking is on, any change to the StateBag
value will cause that item to be marked as “Dirty
”.Info: In case you are wondering (and you should be) about the reason behind this “tracking” behavior of the StateBag , do not worry; this will be explained in detail along with examples about how tracking works, in the next sections. |
Introducing Viewstate Inside the ASP.NET Context
When
dealt within the context of ASP.NET, the Viewstate can be defined as
the technique used by an ASP.NET web page to remember the change of
state spanning multiple requests. As you know, ASP.NET is a stateless
technology; meaning that two different requests (two postbacks) to the
same web page are considered completely unrelated. This raises the need
of a mechanism to track the change of state for this web page between
the first and the second request.
The Viewstate of an ASP.NET page is created during the page life cycle, and saved into the rendered HTML using in the “
__
VIEWSTATE” hidden HTML field. The value stored in the “__
VIEWSTATE” hidden field is the result of serialization of two types of data:
1. Any programmatic change of state of the ASP.NET page and its controls. (Tracking and “
Dirty
” items come into play here. This will be detailed later.)
2. Any data stored by the developer using the Viewstate property described previously.
This value is loaded during postbacks, and is used to preserve the state of the web page.
Info: The process of creating and loading the Viewstate during the page life cycle will be explained in detail later. Moreover, what type of information is saved in the Viewstate is also to be deeply discussed. |
One
final thing to be explained here is the fact that ASP.NET server
controls use Viewstate to store the values of their properties. What
does this mean? Well, if you take a look at the source code of the
TextBox
server control, for example, you will find that the “Text
” property is defined like this: public string Text
{
get { return (string)ViewState["Text"]; }
set { ViewState["Text"] = value; }
}
You should apply this rule when developing your own server controls. Now, this does not mean that the value of the “
Text
” property set at design time is saved in the rendered serialized ViewState field. For example, if you add the following TextBox
to your ASP.NET page:
<asp:TextBox runat="server" ID="txt" Text="sometext" />
According to the fact that the “
Text
” property uses Viewstate to store its value, you might think that the value is actually serialized in the __
VIEWSTATE hidden field. This is wrong because the data serialized in the hidden __
VIEWSTATE consists only of state changes done programmatically. Design time data is not serialized into the __
VIEWSTATE (more on this later). For now, just know that the above declaration of the “Text
” property means that it is utilizing Viewstate in its basic form: an indexed property to store values much like the Hashtable
collection does.Generating the compiled class
The first step (actually, step 0 as explained in the info block below) of the life cycle is to generate the compiled class that represents the requested page. As you know, the ASPX page consists of a combination of HTML and Server controls. A dynamic compiled class is generated that represents this ASPX page. This compiled class is then stored in the “Temporary ASP.NET Files” folder. As long as the ASPX page is not modified (or the application itself is restarted, in which case the request will actually be the first request and then the generation of the class will occur again), then future requests to the ASPX page will be served by the same compiled class.
Info: If you have read my previous article about request processing, you will likely recall that the last step of the request handling is to find a suitable HTTP Handler to handle the request. Back then, I explained how the HTTP Handler Factory will either locate a compiled class that represents the requested page or will compile the class in the case of the first request. Well, do you see the link? This is the compiled class discussed here. So, as you may have concluded, this step of generating the compiled class actually occurs during the ASP.NET request handling architecture. You can think of this step as the intersection between where the ASP.NET request handling architecture stops and the ASP.NET page life cycle starts. |
This
compiled class will actually contain the programmatic definition of the
controls defined in the aspx page. In order to fully understand the
process of dynamic generation, let us consider the following example of a
simple ASPX page for collecting the username and the password:
Now, upon the first request for the above page, the generated class is created and stored in the following location:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\
<application name>\< folder identifier1>\< file identifier1>.cs
The compiled class “DLL” is also created in the same location with the same file identifier, as follows:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\
<application name>\< folder identifier1>\< file identifier1>.dll
As
you can see, the generated class and its corresponding DLL are created,
and will serve any new request for the ASPX page until one of the
following conditions occur:
· The ASPX file is modified
· The application is restarted, for example, as a result of IIS reset or app domain restart
The
following code is extracted from the compiled class. Note that the code
is reformatted and “cleaned up” for presentation purposes.
OK, so now is the really interesting part. Start examining the code above, and you will be able to notice the following:
· The class – unsurprisingly – inherits from the “
System.Web.IHttpHandler
”. As explained earlier, this makes it eligible for acting as an HTTP Handler for the request.
· All the controls – both HTML and Web Controls – are defined in the class. Notice how the static properties (such as “
Text
” and “TextMode
”)
are set inside the class. This is very important to remember because
this is a vital point when discussing the Viewstate later in this
article.
· The “
BuildControlTree
”
is called to create the control hierarchy. As you may know, controls
inside an ASPX page are built into a tree hierarchy. For example, in the
above example, the hierarchy would be as follows: The root parent is
the page class itself, under which the direct child controls are the
HTML Literal (the "b
" tag) and the HTML Form. The HTML Form, in its turn, has two direct child controls which are the HTML Literal (the "div
"
tag) and the HTML Table. The HTML Table, in its turn, has child
controls such as the Web Control for the username label and the Web
Control for the password label, and so on until the complete hierarchy
is built. Again, this is a very important point to remember because it
will be revisited when discussing the Viewstate. PreInit (New to ASP.NET 2.0)
The entry point of the page life cycle is the pre-initialization phase called “PreInit
”.
This is the only event where programmatic access to master pages and
themes is allowed. Note that this event is not recursive, meaning that
it is accessible only for the page itself and not for any of its child
controls.
Init (Recursive)
Next is the initialization phase called “
Init
”. The “Init
”
event is fired reclusively for the page itself and for all the child
controls in the hierarchy (which is created during the creation of the
compiled class, as explained earlier). Note that against many
developers’ beliefs, the event is fired in a bottom to up manner and not
an up to bottom within the hierarchy. This means that following up with
our previous example, the “Init
” event is fired first for
the most bottom control in the hierarchy, and then fired up the
hierarchy until it is fired for the page itself. You can test this
behavior yourself by adding a custom or user control to the page.
Override the “OnInit
” event handler in both the page and
the custom (or user) control, and add break points to both event
handlers. Issue a request against the page, and you will notice that the
event handler for the control will be fired up before that of the page. InitComplete (New to ASP.NET 2.0)
The initialization complete event called “
InitComplete
”
signals the end of the initialization phase. It is at the start of this
event that tracking of the ASP.NET Viewstate is turned on. Recall that
the StateBag
class (the Type of Viewstate) has a tracking ability which is off by default, and is turned on by calling the “Track
ViewState()
” method. Also recall that, only when tracking is enabled will any change to a Viewstate key mark the item as “Dirty
”. Well, it is at the start of “InitComplete
” where “Page.Track
ViewState()
” is called, enabling tracking for the page Viewstate.Info: Later, I will give detailed samples of how the Viewstate works within each of the events of the life cycle. These examples will hopefully aid in understanding the inner workings of the Viewstate.LoadViewState |
This event happens only at postbacks. This is a recursive event, much like the “
Init
” event. In this event, the Viewstate which has been saved in the __
VIEWSTATE during the previous page visit (via the Save
ViewState event) is loaded and then populated into the control hierarchy. LoadPostbackdata (Recursive)
This event happens only at postbacks. This is a recursive event much like the “
Init
”
event. During this event, the posted form data is loaded into the
appropriate controls. For example, assume that, on your form, you had a TextBox
server control, and you entered some text inside the TextBox
and posted the form. The text you have entered is what is called postback data. This text is loaded during the LoadPostbackdata
event and handed to the TextBox
.
This is why when you post a form, you find that the posted data is
loaded again into the appropriate controls. This behavior applies to
most controls like the selected item of a drop down list or the
“checked” state of a check box, etc…
A
very common conceptual error is the thought that Viewstate is
responsible for preserving posted data. This is absolutely false;
Viewstate has nothing to do with it. If you want a proof, disable the
Viewstate on your
TextBox
control or even on the entire page, and you will find that the posted data is still preserved. This is the virtue of the LoadPostbackdata
event. PreLoad (New to ASP.NET 2.0)
This event indicates the end of system level initialization.
Load (Recursive)
This event is recursive much like the “
Init
”
event. The important thing to note about this event is the fact that by
now, the page has been restored to its previous state in case of
postbacks. That is because the Load
ViewState and the LoadPostbackdata
events are fired, which means that the page Viewstate and postback data are now handed to the page controls. RaisePostbackEvent
This
event is fired only at postbacks. What this event does is inspect all
child controls of the page and determine if they need to fire any
postback events. If it finds such controls, then these controls fire
their events. For example, if you have a page with a
Button
server control and you click this button causing a postback, then the RaisePostbackEvent
inspects the page and finds that the Button
control has actually raised a postback event – in this case, the Button
's Click
event. The Button
's Click
event is fired at this stage. LoadComplete (New to ASP.NET 2.0)
This event signals the end of
Load
. Prerender (New to ASP.NET 2.0)
This event allows for last updates before the page is rendered.
PrerenderComplete (New to ASP.NET 2.0)
This event signals the end of “
Prerender
”. SaveViewstate (Recursive)
This event is recursive, much like the “
Init
” event. During this event, the Viewstate of the page is constructed and serialized into the __
VIEWSTATE hidden field.Info: Again, what exactly goes into the __ VIEWSTATE field will be discussed later. |
SaveStateControl (New to ASP.NET 2.0)
State
Control is a new feature of ASP.NET 2.0. In ASP.NET 1.1, Viewstate was
used to store two kinds of state information for a control:
· Functionality state
· UI state
This resulted in a fairly large
__
VIEWSTATE field. A very good example is the DataGrid
server control. In ASP.NET 1.1, DataGrid
uses the Viewstate to store its UI state such as sorting and paging. So, even if you wanted to disable Viewstate on the DataGrid
and rebind the data source on each postback, you simply cannot do that if your DataGrid
was using sorting or paging. The result was that the DataGrid
ended up using Viewstate to store both its bounded data and its UI state such as sorting and paging.
ASP.NET 2.0 solved this problem by partitioning the Viewstate into two:
· The Viewstate we are discussing here
· The Control State
The Control State is used to store the UI state of a control such as the sorting and paging of a
DataGrid
. In this case, you can safely disable the DataGrid
Viewstate (provided, of course, that you rebind the data source at each
postback), and the sorting and paging will still work simply because
they are saved in the Control State.
The Control State is also serialized and stored in the same
__
VIEWSTATE hidden field. The Control State cannot be set off. Render (Recursive)
This is a recursive event much like the “
Init
” event. During this event, the HTML that is returned to the client requesting the page is generated. Unload (Recursive)
This is a recursive event much like the “
Init
” event. This event unloads the page from memory, and releases any used resources. Role of Viewstate in the Page Life Cycle
Viewstate in the “Init” event
The important thing to note in the “
Init
” event is that Viewstate tracking is not yet enabled. In order to demonstrate this, let us take the following example:
protected override void OnInit(EventArgs e)
(
bool ret;
ret = ViewState.IsItemDirty("item");//returns false
ViewSTate["item"] = "1";
ret = ViewState.IsItemDirty("item");returns false
base.OnInit(e);
}
Note that in the above example, the item is still not marked as “
Dirty
” even after it is being set. This is due to the fact that at this stage, the “Track
ViewState()
” method is not called yet. It will be called in the “InitComplete
” event.Info: You can force the tracking of Viewstate at any stage that you want. For example, you can call the “ Page.Track ViewState() ” method at the start of the “Init ” event and thus enabling tracking. In this case, the “Init ” event will behave exactly like the “InitComplete ” event, to be discussed next. |
Viewstate in the “InitComplete” event
In the “
InitComplete
” event, the Viewstate tracking is enabled. If we take the same example:
protected override void OnInitComplete(EventArgs e)
(
bool ret;
ret = ViewState.IsItemDirty("item");//returns false
ViewSTate["item"] = "1";
ret = ViewState.IsItemDirty("item");//returns true
base.OnInitComplete(e);
}
This time, note that first, the item is not marked as “
Dirty
”. However, once it is set, then it is marked as “Dirty
”. This is due to the fact that at the start of this event, the “Track
ViewState()
” method is called. Viewstate in the “LoadViewState”and “SaveViewState” events
To
better understand the role of Viewstate in these events, let us take an
example. Say that you have a simple ASPX page that consists of the
following:
· A
Label
server control with its “Text
” property set to “statictext”
· A
Button
server control just to postback the page
· The “
Load
” event of the page has a statement that sets the “Text
” property of the Label
control to “dynamictext”. This statement is wrapped inside a “!IsPostback
” condition
When the page first loads, the following will happen:
· During the “
Load
” event, the “dynamictext” value will be assigned to the “Text
” property of the Label
· Later in the life cycle, the “
SaveViewSatte
” event is fired, and it stores the new assigned value “dynamictext” in the __
VIEWSTATE serialized field (in the next sections, you will see how tracking came into play here)
Now, when you click the
Button
control, the following will happen:
· The “
Load
ViewState” event is fired. The __
VIEWSTATE value saved in the previous page visit is loaded. The “dynamictext” value is extracted and assigned back to the “Text
” property of the Label
.
· The “
Load
” event is fired, but nothing happens there because the code is wrapped inside a “!IsPostback
” condition.
See
how that because of the Viewstate, the “dynamictext” value is persisted
across page postback. Without Viewstate and with the “!IsPostback”
condition inside the “Load” event, the value “dynamictext” would have
been lost after the postback.
Viewstate Walkthroughs
OK,
so by now, you should have a solid understanding about the page life
cycle, the Viewstate, and the role of the Viewstate in the page life
cycle. However, we are yet to discuss the cases that tests whether you
are an advanced Viewstate user or not. In the next walkthroughs, you
shall tackle most of these cases. By the end of this section, you can
safely call yourself an advanced Viewstate user.
Walkthrough 1: Viewstate of an empty or Viewstate-disabled page
So, let us start by a very simple question. Will you have a value stored in the
__
VIEWSTATE
field if you have a blank ASP.NET page or a page with Viewstate
completely disabled? The answer is yes. As a test, create a blank
ASP.NET page and run it. Open the View Source page and note the __
VIEWSTATE
field. You will notice that it contains a small serialized value. The
reason is that the page itself saves 20 or so bytes of information into
the __
VIEWSTATE field, which it uses to distribute postback
data and Viewstate values to the correct controls upon postback. So,
even for a blank page or a page with disabled Viewstate, you will see a
few remaining bytes in the __
VIEWSTATE field. Walkthrough 2: What is stored in the Viewstate?
As mentioned previously, the data stored in the
__
VIEWSTATE field consists of the following:
· Data stored by developers using the Viewstate[“”]
indexer
· Programmatic change to the Control State
While the former is pretty much clear, the latter is to be explained thoroughly.
OK, so let us assume that you have a web page with only a
Label
control on it. Now, let us say that at design time, you set the “Text
” property of the Label
to “statictext”. Now, load the page and open the View Source page. You will see the __
VIEWSTATE
field. Do you think “statictext” is saved there? The answer is, for
sure, not. Recall from our discussion about generating the compiled
class of the page, that static properties of controls are assigned at
the generated class? So, when the page is requested, the values stored
in the generated class are displayed. As such, static properties that
are set at design time are never stored in the __
VIEWSTATE field. However, they are stored in the generated compiled class, and thus they show up when rendering the page.
Now, let us say that you did some changes to your page such that it consists of the following:
· ALabel
control with the value “statictext” assigned to its “Text
” property
· AButton
control to postback the page
· Inside the “
Page_Load
” event handler of the page, add code to change the value of the Label
’s “Text
” property to “dynamictext”. Wrap this code inside a “!IsPostback
” condition.
Load the page and open the View Source page. This time, you will notice that the
__
VIEWSTATE field is larger. This is because at runtime, you changed the value of the “Text
” property. And, since you have done this inside the “Load
” event, where, at this time, tracking of Viewstate is enabled (remember, tracking is enabled in the “InitComplete
” event), the “Text
” property is marked as “Dirty
”, and thus the “Save
Viewstate” event stores its new value in the __
VIEWSTATE field. Interesting!!
As a proof that the “dynamictext” value is stored in the
__
VIEWSTATE field (apart from the fact that it is larger), click the Button
control causing a postback. You will find that the “dynamictext” value is retained in the Label
even though the code in the “Load
” event is wrapped inside the “!IsPostback
” condition. This is due to the fact that upon postback, the “Load
Viewstate” event extracted the value “dynamictext” which was saved by the “Save
ViewState” event during the previous page visit and then assigned it back to the Label
’s “Text
” property.
Let
us now go one step further. Repeat the exact same scenario, with one
exception: instead of adding the code that will change the value of the “
Text
” property at the “Page_Load
” event handler, override the “OnPreInit
” event handler and add the code there. Now, first load the page, and you will see the new text displayed in the Label
. But, do you think this time it is stored in the __
VIEWSTATE field? The answer is no. The reason is that during the “PreInit
” event, Viewstate tracking is not yet enabled, so the change done to the “Text
” property is not tracked and thus not saved during the “Save
ViewState” event. As a proof, click the Button
causing a postback. You will see that the value displayed inside the Label
is the design time value “statictext”.
Let us even go one step further. If you have been following this long article carefully, you will recall that during the “
Init
” event, tracking of Viewstate is not yet enabled. You have even seen an example in the section Viewstate in the “Init” event
of how an item keeps being not dirty even after it is being set. Now,
going back to our current example, you will most probably be tempted to
consider that if we add the code that changes the value of the “Text
” property inside the “OnInit
” event handler, you will get the same result as when you put it inside the “OnPreInit
”
event handler; after all, tracking of Viewstate is not enabled yet
during either event. Well, if you think so, then you are mistaken.
Reason: if you have been following this article carefully, you will
recall that the “InitComplete
” event (where tracking of
Viewstate is enabled) is not a recursive event; it is called only for
the page itself, but not for its child controls. This means that, for
the child controls, there is no “InitComplete
” event; so, where does the tracking of Viewstate start? The answer is at the start of the “Init
” event. So, this means that for the page itself, tracking of Viewstate is enabled at the “InitComplete
” event; that is why during the “OnInit
” event handler, the item was still marked as not being “Dirty
” even after modification. However, for child controls, there is no “InitComplete
” event, so the Viewstate tracking is enabled as early as the “Init
” event. And, since – again as was explained earlier – the “Init
” event is called recursively for the page and its controls in a bottom to up manner, by the time the “Init
” event of the page itself is fired, the “Init
”
event of the child controls is already being fired, and thus Viewstate
tracking for child controls is on by that time. As such, adding the code
that changes the value of the “Text
” property inside the “OnInit
” event handler will have the same effect as putting it inside the “Page_Load
” event handler. Walkthorugh 3: What is the larger Viewstate?
Consider the following example: you have two ASP.NET pages: page1.aspx and page2.aspx. Both pages contain only a single
Label
control. However, in page1, the Label
is declared at design time with its “Text
” property set to a small string (say 10 characters); in page2, the Label
is declared at design time with its “Text
”
property set to a lengthy string (say 1000 characters). Now, load both
pages at the same time, and examine the View Source for both pages.
Compare the two __
VIEWSTATE fields, what do you find? You will find that both fields are of the same size even though one Label
has its “Text
” property storing 10 characters while the other has its “Text
”
property storing 1000 characters. If you have read walkthroughs 1 and
2, you will for sure know the reason: design time property values are
not stored in the Viewstate. The __
VIEWSTATE value for both pages is simply the bytes emitted by the page itself. Walkthrough 4: Complete page life cycle scenario
In
this walkthrough, we will go through each of the relevant page life
cycle events and see what role Viewstate has in each of these events. In
this example, we have as ASP.NET page with the following
characteristics:
· It contains a singleLabel
control (lbl
) with its “Text
” property set to “statictext”
· It contains aButton
control (btnA
) with code in its event handler that sets the “Text
” property of “lbl
” to “dynamictext”
· It contains aButton
control (btn
B) whose purpose is to cause a page postback
Now, let us examine what will happen during the page life cycle.
1. The page is first loaded
1. The compiled class of the page is generated and “statictext” is assigned to “lbl.Text
”
2. Tracking for Viewstate is enabled in the “InitComplete
” event
3. “Load
ViewState” is not fired because there is no postback
4. “Save
Viewstate” is fired, but nothing happens because no change of state is recorded
5. The page is rendered with the value “statictext” inside “lbl
”
2.btnA
is clicked
1. The previously generated compiled class is handed the request; “lbl.Text
” is set to “statictext”
2. Tracking for Viewstate is enabled
3. “Load
ViewState” is fired, but nothing happens because no change of state was recorded in the previous page visit
4. “RaisePostbackEvent
” event is executed and “btnA
” click event handler is fired; “lbl.Text
” is set to “dynamictext”; since tracking is enabled at this stage, this item is tracked (marked as “Dirty
”).
5. “Save
ViewState” is fired; “dynamictext” is serialized and stored in the__
VIEWSTATE field
6. The page is rendered with the value “dynamictext” inside “lbl
”
3.btnB
is clicked
1. The previously generated compiled class is handed the request; “lbl.Text” is set to “statictext”
2. Tracking for Viewstate is enabled
3. “Load
ViewState” is fired; since a change of state was recorded from the previous page visit,__
VIEWSTATE is loaded and the value “dynamictext” is extracted; this value is then assigned to “lbl
”
4. “RaisePostbackEvent
” event is executed; nothing happens here because “btnB
” has no event handler for its “Click
” event
5. “Save
ViewState” is fired, but nothing happens because no change of state is recorded
6. The page is rendered with the value “dynamictext” inside “lbl
”
Walkthrough 5: Reducing Viewstate size – Disabling Viewstate
Disabling
Viewstate would obviously reduce Viewstate size; but, it surely kills
the functionality along the way. So, a little more planning is required…
Consider the case where you have a page with a drop down list that should display the countries of the world. On the “
Page_Load
”
event handler, you bind the drop down list to a data source that
contains the countries of the world; the code that does the binding is
wrapped inside a “!IsPostback
” condition. Finally, on the
page, you have a button that when clicked should read the selected
country from the drop down list. With the setup described above, you
will end up with a large __
VIEWSTATE field. This is due to
the fact that data bound controls (like the drop down list) store their
state inside the Viewstate. You want to reduce Viewstate; what options
do you have?
1. Option 1: Simply disable the Viewstate on the drop down list
2. Option 2: Disable the Viewstate on the drop down list, and remove the “
!IsPostback
” condition
3. Option 3: Disable the Viewstate on the drop down list, and move the binding code without the “
!IsPostback
” condition to the “OnInit
” or “OnPreInit
” event handlers
If
you implement Option 1, you will reduce the Viewstate alright, but with
it, you will also lose the list of countries on the first postback of
the page. When the page first loads, the code in the “
Page_Load
”
event handler is executed and the list of countries is bound to the
list. However, because Viewstate is disabled on the list, this change of
state is not saved during the “Save
ViewState” event. When the button on the page is clicked causing a postback, since the binding code is wrapped inside a “!IsPostback
” condition, the “Load
ViewState” event has nothing saved from the previous page visit and the drop down list is empty.
If
you implement Option 2, you will reduce the Viewstate size and you will
not lose the list of countries on postback. However, another problem
arises: because the binding code is now executed at each “
Page_Load
”,
the postback data is lost upon postback, and every time, the first item
of the list will be selected. This is true because in the page life
cycle, the “LoadPostbackdata
” event occurs before the “Load
” event.
Option 3 is the correct option. In this option, you have done the following:
· Disabled Viewstate on the drop down list
· Removed the “
!IsPostback
” condition from the binding code
· Moved the binding code to the “
OnInit
” event handler (or the “OnPreInit
” event handler)
Since the “
Init
” event occurs before the “LoadPostbackdata
”
in the page life cycle, the postback data is preserved upon postbacks,
and the selected item from the list is correctly preserved.
Now,
remember that in Option 3, you have successfully reduced the Viewstate
size and kept the functionality working; but, this actually comes at the
cost of rebinding the drop down list at each postback. The performance
hit of revisiting the data source at each postback is nothing when
compared with the performance boost gained from saving a huge amount of
bytes being rendered at the client’s
__
VIEWSTATE
field. This is especially true with the fact that most clients are
connected to the Internet via low speed dial up connections. Walkthrough 6: Viewstate and Dynamic Controls
The
first fact that you should know about dynamic controls is that they
should be added to the page at each and every page execution. Never wrap
the code that initializes and adds the dynamic control to the page
inside a “
!IsPostback
” condition. The
reason is that since the control is dynamic, it is not included in the
compiled class generated for the page. So, the control should be added
at every page execution for it to be available in the final control
tree. The second fact is that dynamic controls play “catch-up” with the
page life cycle once they are added. Say, you did the following:
Label lbl = new Label();
Page.Controls.Add(lbl);
Once the control is added to the “
Controls
”
collection, it plays “catch-up” with the page life cycle, and all the
events that it missed are fired. This leads to a very important
conclusion: you can add dynamic controls at any time during the page
life cycle until the “PreRender
” event. Even when you add the dynamic control in the “PreRender
” event, once the control is added to the “Controls
” collection, the “Init
”, “Load
ViewState”, “LoadPostbackdata
”, “Load
”, and “Save
Viewstate”
are fired for this control. This is called “catch-up”. Note though that
it is recommended that you add your dynamic controls during the “PreInit
” or “Init
”
events. This is because it is best to add controls to the control tree
before tracking of the Viewstate of other controls is enabled…
Finally, what is the best practice for adding dynamic controls regarding Viewstate? Let us say that you want to add a
Label
at runtime and assign a value to its “Text
” property. What is the best practice to do so? If you are thinking the below, then you are mistaken:
Label lbl = new Label();
Page.Controls.Add(lbl);
lbl.Text = "bad idea";
You are mistaken because using the above technique you are actually storing the value of the “
Text
” property in the Vewstate. Why? Because, recall that once a dynamic control is added to the “Controls
” collection, a “catch-up” happens and the tracking for the Viewstate starts. So, setting the value of the “Text
” property will cause the value to be stored in the Viewstate.
However, if you do the below, then you are thinking the right way, because you are setting the “
Text
” property before adding the control to the “Controls
” collection. In this case, the value of the “Text
” property is added with the control to the control tree and not persisted in Viewstate. Label lbl = new Label();
lbl.Text = "good idea";
Page.Controls.Add(lbl);
No comments:
Post a Comment