page life cycle in asp.net.......
Asp.net application and pagelifecycle
Introduction
In this article, we will try to understand what the different events are which take place right from the time the user sends a request, until the time the request is rendered on the browser. So we will first try to understand the two broader steps of an ASP.NET request and then we will move into different events emitted from ‘HttpHandler’, ‘HttpModule’ and ASP.NET page object. As we move in this event journey, we will try to understand what kind of logic should go in each and every one of these events.
This is a small Ebook for all my .NET friends which covers topics like WCF, WPF, WWF, Ajax, Core .NET, SQL, etc. You can download the same from here or else you can catch me on my daily free training here.
The Two Step Process
From 30,000 feet level, ASP.NET request processing is a 2 step process as shown below. User sends a request to the IIS:
In the coming sections, we will understand both these main steps in more detail.
Creation of ASP.NET Environment
Step 1: The user sends a request to IIS. IIS first checks which ISAPI extension can serve this request. Depending on file extension the request is processed. For instance, if the page is an ‘.ASPX page’, then it will be passed to ‘aspnet_isapi.dll’ for processing.
Step 2: If this is the first request to the website, then a class called as ‘ApplicationManager’ creates an application domain where the website can run. As we all know, the application domain creates isolation between two web applications hosted on the same IIS. So in case there is an issue in one app domain, it does not affect the other app domain.
Step 3: The newly created application domain creates hosting environment, i.e. the ‘HttpRuntime’ object. Once the hosting environment is created, the necessary core ASP.NET objects like ‘HttpContext’ , ‘HttpRequest’ and ‘HttpResponse’ objects are created.
Step 4: Once all the core ASP.NET objects are created, ‘HttpApplication’ object is created to serve the request. In case you have a ‘global.asax’ file in your system, then the object of the ‘global.asax’ file will be created. Please note global.asax file inherits from ‘HttpApplication’ class.Note: The first time an ASP.NET page is attached to an application, a new instance of ‘HttpApplication’ is created. Said and done to maximize performance, HttpApplication instances might be reused for multiple requests.
Step 5: The HttpApplication object is then assigned to the core ASP.NET objects to process the page.
Step 6: HttpApplication then starts processing the request by HTTP module events, handlers and page events. It fires the MHPM event for request processing.Note: For more details, read this.
The below image explains how the internal object model looks like for an ASP.NET request. At the top level is the ASP.NET runtime which creates an ‘Appdomain’ which in turn has ‘HttpRuntime’ with ‘request’, ‘response’ and ‘context’ objects.
Process Request using MHPM Events Fired
Once ‘HttpApplication’ is created, it starts processing requests. It goes through 3 different sections ‘HttpModule’ , ‘Page’ and ‘HttpHandler’. As it moves through these sections, it invokes different events which the developer can extend and add customize logic to the same.
Before we move ahead, let's understand what are ‘HttpModule’ and ‘HttpHandlers’. They help us to inject custom logic before and after the ASP.NET page is processed. The main differences between both of them are:
You can read more about the differences from here.
Below is the logical flow of how the request is processed. There are 4 important steps MHPM as explained below:
Step 1(M: HttpModule): Client request processing starts. Before the ASP.NET engine goes and creates the ASP.NET HttpModule emits events which can be used to inject customized logic. There are 6 important events which you can utilize before your page object is created BeginRequest, AuthenticateRequest, AuthorizeRequest, ResolveRequestCache, AcquireRequestState and PreRequestHandlerExecute.
Step 2 (H: ‘HttpHandler’): Once the above 6 events are fired, ASP.NET engine will invoke ProcessRequest event if you have implemented HttpHandler in your project.
Step 3 (P: ASP.NET page): Once the HttpHandler logic executes, the ASP.NET page object is created. While the ASP.NET page object is created, many events are fired which can help us to write our custom logic inside those page events. There are 6 important events which provides us placeholder to write logic inside ASP.NET pages Init, Load, validate, event, render and unload. You can remember the word SILVER to remember the events S – Start (does not signify anything as such just forms the word) , I – (Init) , L (Load) , V (Validate), E (Event) and R (Render).
Step4 (M: HttpModule): Once the page object is executed and unloaded from memory, HttpModule provides post page execution events which can be used to inject custom post-processing logic. There are 4 important post-processing events PostRequestHandlerExecute, ReleaserequestState, UpdateRequestCache and EndRequest.
The below figure shows the same in a pictorial format.
In What Event Should We Do What?
The million dollar question is in which events should we do what? Below is the table which shows in which event what kind of logic or code can go.
A Sample Code for Demonstration
With this article, we have attached a sample code which shows how the events actually fire. In this code, we have created a ‘HttpModule’ and ‘Httphandler’ in this project and we have displayed a simple response write in all events, below is how the output looks like.
Below is the class for ‘HttpModule’ which tracks all events and adds it to a global collection.Collapse | Copy Code
Collapse | Copy Code
public class clsHttpModule : IHttpModule
{
......
void OnUpdateRequestCache(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnUpdateRequestCache");
}
void OnReleaseRequestState(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnReleaseRequestState");
}
void OnPostRequestHandlerExecute(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnPostRequestHandlerExecute");
}
void OnPreRequestHandlerExecute(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnPreRequestHandlerExecute");
}
void OnAcquireRequestState(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnAcquireRequestState");
}
void OnResolveRequestCache(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnResolveRequestCache");
}
void OnAuthorization(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnAuthorization");
}
void OnAuthentication(object sender, EventArgs a)
{
objArrayList.Add("httpModule:AuthenticateRequest");
}
void OnBeginrequest(object sender, EventArgs a)
{
objArrayList.Add("httpModule:BeginRequest");
}
void OnEndRequest(object sender, EventArgs a)
{
objArrayList.Add("httpModule:EndRequest");
objArrayList.Add("<hr>");
foreach (string str in objArrayList)
{
httpApp.Context.Response.Write(str + "<br>") ;
}
}
}
Below is the code snippet for ‘HttpHandler’ which tracks ‘ProcessRequest’ event.Collapse | Copy Code
Collapse | Copy Code
public class clsHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
clsHttpModule.objArrayList.Add("HttpHandler:ProcessRequest");
context.Response.Redirect("Default.aspx");
}
}
We are also tracking all the events from the ASP.NET page.Collapse | Copy Code
Collapse | Copy Code
public partial class _Default : System.Web.UI.Page
{
protected void Page_init(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:Init");
}
protected void Page_Load(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:Load");
}
public override void Validate()
{
clsHttpModule.objArrayList.Add("Page:Validate");
}
protected void Button1_Click(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:Event");
}
protected override void Render(HtmlTextWriter output)
{
clsHttpModule.objArrayList.Add("Page:Render");
base.Render(output);
}
protected void Page_Unload(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:UnLoad");
}}
Below is how the display looks like with all events as per the sequence discussed in the previous section.
Zooming ASP.NET Page Events
In the above section, we have seen the overall flow of events for an ASP.NET page request. One of the most important sections is the ASP.NET page, we have not discussed the same in detail. So let’s take some luxury to describe the ASP.NET page events in more detail in this section.
Any ASP.NET page has 2 parts, one is the page which is displayed on the browser which has HTML tags, hidden values in form of viewstate and data on the HTML inputs. When the page is posted, these HTML tags are created in to ASP.NET controls with viewstate and form data tied up together on the server. Once you get these full server controls on the behind code, you can execute and write your own login on the same and render the page back to the browser.
Now between these HTML controls coming live on the server as ASP.NET controls, the ASP.NET page emits out lot of events which can be consumed to inject logic. Depending on what task / logic you want to perform, we need to put this logic appropriately in those events.Note: Most of the developers directly use the page_load method for everything, which is not a good thought. So it’s either populating the controls, setting view state, applying themes, etc., everything happens on the page load. So if we can put logic in proper events as per the nature of the logic, that would really make your code clean.
*
Other Versions
51 out of 72 rated this helpful - Rate this topic
A new instance of the Web page class is created each time the page is posted to the server. In traditional Web programming, this would typically mean that all information associated with the page and the controls on the page would be lost with each round trip. For example, if a user enters information into a text box, that information would be lost in the round trip from the browser or client device to the server.
To overcome this inherent limitation of traditional Web programming, ASP.NET includes several options that help you preserve data on both a per-page basis and an application-wide basis. These features are as follows:
The following sections describe options for state management that involve storing information either in the page or on the client computer. For these options, no information is maintained on the server between round trips.
When the page is processed, the current state of the page and controls is hashed into a string and saved in the page as a hidden field, or multiple hidden fields if the amount of data stored in the ViewState property exceeds the specified value in the MaxPageStateFieldLength property. When the page is posted back to the server, the page parses the view-state string at page initialization and restores property information in the page.
You can store values in view state as well. For more information on using View State, see ASP.NET View State Overview. For recommendations about when you should use view state, see ASP.NET State Management Recommendations.
The ControlState property allows you to persist property information that is specific to a control and cannot be turned off like the ViewState property.
A HiddenField control stores a single variable in its Value property and must be explicitly added to the page. For more information, see HiddenField Web Server Control Overview.
In order for hidden-field values to be available during page processing, you must submit the page using an HTTP POST command. If you use hidden fields and a page is processed in response to a link or an HTTP GET command, the hidden fields will not be available. For usage recommendations, see ASP.NET State Management Recommendations.
You can use cookies to store information about a particular client, session, or application. The cookies are saved on the client device, and when the browser requests a page, the client sends the information in the cookie along with the request information. The server can read the cookie and extract its value. A typical use is to store a token (perhaps encrypted) indicating that the user has already been authenticated in your application.
For more information about using cookies, see Cookies and ASP.NET State Management Recommendations.
http://www.contoso.com/listwidgets.aspx?category=basic&price=100
In the URL path above, the query string starts with a question mark (?) and includes two attribute/value pairs, one called "category" and the other called "price."
Query strings provide a simple but limited way to maintain state information. For example, they are an easy way to pass information from one page to another, such as passing a product number from one page to another page where it will be processed. However, some browsers and client devices impose a 2083-character limit on the length of the URL.
In order for query string values to be available during page processing, you must submit the page using an HTTP GET command. That is, you cannot take advantage of a query string if a page is processed in response to an HTTP POST command. For usage recommendations, see ASP.NET State Management Recommendations.Server-Based State Management Options
ASP.NET offers you a variety of ways to maintain state information on the server, rather than persisting information on the client. With server-based state management, you can decrease the amount of information sent to the client in order to preserve state, however it can use costly resources on the server. The following sections describe three server-based state management features: application state, session state, and profile properties.
Application state is stored in a key/value dictionary that is created during each request to a specific URL. You can add your application-specific information to this structure to store it between page requests.
Once you add your application-specific information to application state, the server manages it. For usage recommendations, see ASP.NET State Management Recommendations.
Session state is similar to application state, except that it is scoped to the current browser session. If different users are using your application, each user session will have a different session state. In addition, if a user leaves your application and then returns later, the second user session will have a different session state from the first.
Session state is structured as a key/value dictionary for storing session-specific information that needs to be maintained between server round trips and between requests for pages. For more information, see ASP.NET Session State Overview.
You can use session state to accomplish the following tasks:
To use profile properties, you must configure a profile provider. ASP.NET includes a SqlProfileProvider class that allows you to store profile data in a SQL database, but you can also create your own profile provider class that stores profile data in a custom format and to a custom storage mechanism such as an XML file, or even to a web service.
Because data that is placed in profile properties is not stored in application memory, it is preserved through Internet Information Services (IIS) restarts and worker-process restarts without losing data. Additionally, profile properties can be persisted across multiple processes such as in a Web farm or a Web garden. For more information,
Other Versions
2 out of 3 rated this helpful - Rate this topic
Directives specify settings that are used by the page and user-control compilers when the compilers process ASP.NET Web Forms pages (.aspx files) and user control (.ascx) files.
ASP.NET treats any directive block (<%@ %>) that does not contain an explicit directive name as an @ Page directive (for a page) or as an @ Control directive (for a user control).
For syntax information and descriptions of the attributes that are available for each directive, use the links that are listed in the following table.
*
patterns & practices Developer Center
J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Chaitanya Bijwe
Microsoft Corporation
November 2005
Overview
IIS Authentication
ASP.NET Forms Authentication
Cookieless Forms Authentication
Membership and Login Controls
Web Farm Scenarios
Additional Resources
If the user requests a page that requires authenticated access and that user has not previously logged on to the site, then the user is redirected to a configured logon page. The logon page prompts the user to supply credentials, typically a user name and password. These credentials are then passed to the server and validated against a user store, such as a SQL Server database. In ASP.NET 2.0, user-store access can be handled by a membership provider. After the user's credentials are authenticated, the user is redirected to the originally requested page.
Forms authentication processing is handled by the FormsAuthenticationModule class, which is an HTTP module that participates in the regular ASP.NET page-processing cycle. This document explains how forms authentication works in ASP.NET 2.0.
Second, ASP.NET performs its own authentication. The authentication method used is specified by the mode attribute of the authentication element. The following authentication configuration specifies that ASP.NET uses the FormsAuthenticationModule class:
<authentication mode="Forms" />
Note Because forms authentication does not rely on IIS authentication, you should configure anonymous access for your application in IIS if you intend to use forms authentication in your ASP.NET application.
<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx"
protection="All"
timeout="30"
name=".ASPXAUTH"
path="/"
requireSSL="false"
slidingExpiration="true"
defaultUrl="default.aspx"
cookieless="UseDeviceProfile"
enableCrossAppRedirects="false" />
</authentication>
</system.web>
The default attribute values are described below:
You can configure UrlAuthorizationModule by using the authorization element as shown in the following example.
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
With this setting, all unauthenticated users are denied access to any page in your application. If an unauthenticated user tries to access a page, the forms authentication module redirects the user to the logon page specified by the loginUrl attribute of the forms element.
Figure 1. Forms authentication control flow
<httpModules>
...
<add name="WindowsAuthentication"
type="System.Web.Security.WindowsAuthenticationModule" />
<add name="FormsAuthentication"
type="System.Web.Security.FormsAuthenticationModule" />
<add name="PassportAuthentication"
type="System.Web.Security.PassportAuthenticationModule" />
...
</httpModules>
Only one authentication module is used for each request. The authentication module that is used depends on which authentication mode has been specified by the authentication element, usually in the Web.config file in the application's virtual directory.
The FormsAuthenticationModule class is activated when the following element is in the Web.config file.
<authentication mode="Forms" />
The FormsAuthenticationModule class constructs a GenericPrincipal object and stores it in the HTTP context. The GenericPrincipal object holds a reference to a FormsIdentity instance that represents the currently authenticated user. You should allow forms authentication to manage these tasks for you. If your applications have specific requirements, such as setting the User property to a custom class that implements the IPrincipal interface, your application should handle the PostAuthenticate event. The PostAuthenticate event occurs after the FormsAuthenticationModule has verified the forms authentication cookie and created the GenericPrincipal and FormsIdentity objects. Within this code, you can construct a custom IPrincipal object that wraps the FormsIdentity object, and then store it in the HttpContext. User property.
Note If you do this, you will also need to set the IPrincipal reference on the Thread.CurrentPrincipal property to ensure that the HttpContext object and the thread point to the same authentication information.
The following properties are included in a typical forms authentication cookie:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
"userName",
DateTime.Now,
DateTime.Now.AddMinutes(30), // value of time out property
false, // Value of IsPersistent property
String.Empty,
FormsAuthentication.FormsCookiePath);
Next, forms authentication uses the Encrypt method for encrypting and signing the forms authentication ticket, if the protection attribute of the forms element is set to All or Encryption.
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
The following text shows the process used when the protection attribute is set to All:
Each time a subsequent request is received after authentication, the FormsAuthenticationModule class retrieves the authentication ticket from the authentication cookie, decrypts it, computes the hash value, and compares the MAC value to help ensure that the cookie has not been tampered with. Finally, the expiration time contained inside of the forms authentication ticket is verified.
Note ASP.NET does not depend on the expiration date of the cookie because this date could be easily forged.
http://localhost/CookielessFormsAuthTest/(F(-k9DcsrIY4CAW81Rbju8KRnJ5o_gOQe0I1E_jNJLYm74izyOJK8GWdfoebgePJTEws0Pci7fHgTOUFTJe9jvgA2))/Test.aspx
The section of the URL that is in parentheses contains the data that the cookie would usually contain. This data is removed by ASP.NET during request processing. This step is performed by the ASP.NET ISAPI filter and not in an HttpModule class. If you read the Request.Path property from an .aspx page, you won't see any of the extra information in the URL. If you redirect the request, the URL will be rewritten automatically.
Note It is not possible to secure authentication tickets contained in URLs. When security is paramount, you should use cookies to store authentication tickets.
Membership provides credential storage and management for application users. It also provides a membership API that simplifies the task of validating user credentials when used with forms authentication. The membership feature is built on top of a provider model. This model allows implementing and configuring different providers pointing to different user stores. ASP.NET 2.0 includes the following membership providers:
ASP.NET login controls automatically use membership and forms authentication and encapsulate the logic required to prompt users for credentials, validate users, recover or replace passwords, and so on. In effect, the ASP.NET login controls provide a layer of abstraction over forms authentication and membership, and they replace most, or all of, the work you would normally have to do to use forms authentication.
For more information about using the membership feature and login controls, see How To: Use Membership in ASP.NET 2.0.
The validationKey and decryptionKey attributes in the machineKey element are used for hashing and encryption of the forms authentication ticket. The default value for these attributes is AutoGenerate.IsolateApps. The keys are auto-generated for each application, and they are different on each server. Therefore, authentication tickets that are encrypted on one computer cannot be decrypted and verified on another computer in a Web farm, or in another application on the same Web server.
Other Versions
11 out of 24 rated this helpful - Rate this topic
An ASP.NET HTTP handler is the process (frequently referred to as the "endpoint") that runs in response to a request made to an ASP.NET Web application. The most common handler is an ASP.NET page handler that processes .aspx files. When users request an .aspx file, the request is processed by the page through the page handler. You can create your own HTTP handlers that render custom output to the browser.
An HTTP module is an assembly that is called on every request that is made to your application. HTTP modules are called as part of the ASP.NET request pipeline and have access to life-cycle events throughout the request. HTTP modules let you examine incoming and outgoing requests and take action based on the request.
This topic contains:
Typical uses for custom HTTP handlers include the following:
HTTP handler and module features include the following:
The ASP.NET page handler is only one type of handler. ASP.NET includes several other built-in handlers such as the Web service handler for .asmx files.
The ProcessRequest method is responsible for processing individual HTTP requests. In this method, you write the code that produces the output for the handler.
HTTP handlers have access to the application context. This includes the requesting user's identity (if known), application state, and session information. When an HTTP handler is requested, ASP.NET calls the ProcessRequest method of the appropriate handler. The code that you write in the handler's ProcessRequest method creates a response, which is sent back to the requesting browser.
By default, ASP.NET maps the file name extension .ashx to an HTTP handler. If you add the @ WebHandler directive to a class file, ASP.NET automatically maps the .ashx file name extension to the default HTTP handler. This is similar to the way ASP.NET maps the .aspx file name extension to the ASP.NET page handler when the @ Page directive is used. Therefore, if you create an HTTP handler class that has the file name extension .ashx, the handler is automatically registered with IIS and ASP.NET.
If you want to create a custom file name extension for a handler, you must explicitly register the extension with IIS and ASP.NET. The advantage of not using the .ashx file name extension is that the handler is then reusable for different extension mappings. For example, in one application the custom handler might respond to requests that end in .rss. In another application, it might respond to requests that end in .feed. As another example, the handler might be mapped to both file name extensions in the same application, but might create different responses based on the extension.
The process for registering a handler's custom file name extension is different in IIS 7.0 and in earlier versions of IIS. For more information, see How to: Register HTTP Handlers and How to: Configure an HTTP Handler Extension in IIS.
Asynchronous HTTP handlers enable you to start an external process, such as a method call to a remote server. The handler can then continue processing without waiting for the external process to finish. While an asynchronous HTTP handler is processing, ASP.NET puts the thread that would ordinarily be used for the external process back into the thread pool until the handler receives a callback from the external process. This can prevent thread blocking and can improve performance because only a limited number of threads can execute at the same time. If many users request synchronous HTTP handlers that rely on external processes, the operating system can run out of threads, because many threads are blocked and are waiting for an external process.
When you create an asynchronous handler, you must implement the IHttpAsyncHandler interface. You must also implement the BeginProcessRequest method in order to initiate an asynchronous call that processes individual HTTP requests. In addition, you must implement the EndProcessRequest method to run cleanup code when the process ends.
To register a custom extension for a handler factory, follow the steps for registering a custom extension for a handler. For an example of creating and registering a handler factory, see Walkthrough: Creating and Registering HTTP Handler Factories.
In IIS 6.0, the ASP.NET request pipeline is separate from the Web server request pipeline. In IIS 7.0, the ASP.NET request pipeline and the Web server request pipeline can be integrated into a common request pipeline. In IIS 7.0, this is referred to as Integrated mode. The unified pipeline has several benefits for ASP.NET developers. For example, it lets managed-code modules receive pipeline notifications for all requests, even if the requests are not for ASP.NET resources. However, if you want, you can run IIS 7.0 in Classic mode, which emulates ASP.NET running in IIS 6.0. For more information, see ASP.NET Application Life Cycle Overview for IIS 7.0.
ASP.NET HTTP modules are like ISAPI filters because they are invoked for all requests. However, they are written in managed code and are fully integrated with the life cycle of an ASP.NET application. You can put custom module source code in the App_Code folder of your application, or you can put compiled custom modules as assemblies in the Bin folder of an application.
ASP.NET uses modules to implement various application features, which includes forms authentication, caching, session state, and client script services. In each case, when those services are enabled, the module is called as part of a request and performs tasks that are outside the scope of any single page request. Modules can consume application events and can raise events that can be handled in the Global.asax file. For more information about application events, see ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0 and ASP.NET Application Life Cycle Overview for IIS 7.0.
When ASP.NET creates an instance of the HttpApplication class that represents your application, instances of any modules that have been registered are created. When a module is created, its Init method is called and the module initializes itself. For more information, see ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0 and ASP.NET ASP.NET Application Life Cycle Overview for IIS 7.0.
In a module's Init method, you can subscribe to various application events such as BeginRequest or EndRequest by binding the events to methods in the module.
When application events are raised, the appropriate method in your module is called. The method can perform whatever logic is required, such as checking authentication or logging request information. During event handling, the module has access to the Context property of the current request. This enables you to redirect the request to an alternative page, modify the request, or perform any other request manipulation. For example, if the module checks authentication, the module might redirect to a login or error page if the credentials are not correct. Otherwise, when the module's event handler has finished running, ASP.NET calls the next process in the pipeline. This might be another module or might be the appropriate HTTP handler (such as an .aspx file) for the request.
The advantage of using the Global.asax file is that you can handle other registered events such as Session_Start and Session_End. In addition, the Global.asax file enables you to instantiate global objects that are available throughout the application.
You should use a module whenever you must create code that depends on application events, and when the following conditions are true:
The guidelines in this topic list techniques that you can use to help maximize the throughput of ASP.NET Web applications. The guidelines are divided into the following sections:
Page and Server Control Processing
The following guidelines suggest ways to work with ASP.NET pages and controls efficiently.
The following guidelines suggest ways to make state management efficient.
Introduction
In this article, we will try to understand what the different events are which take place right from the time the user sends a request, until the time the request is rendered on the browser. So we will first try to understand the two broader steps of an ASP.NET request and then we will move into different events emitted from ‘HttpHandler’, ‘HttpModule’ and ASP.NET page object. As we move in this event journey, we will try to understand what kind of logic should go in each and every one of these events.
This is a small Ebook for all my .NET friends which covers topics like WCF, WPF, WWF, Ajax, Core .NET, SQL, etc. You can download the same from here or else you can catch me on my daily free training here.
The Two Step Process
From 30,000 feet level, ASP.NET request processing is a 2 step process as shown below. User sends a request to the IIS:
- ASP.NET creates an environment which can process the request. In other words, it creates the application object, request, response and context objects to process the request.
- Once the environment is created, the request is processed through a series of events which is processed by using modules, handlers and page objects. To keep it short, let's name this step as MHPM (Module, handler, page and Module event), we will come to details later.
In the coming sections, we will understand both these main steps in more detail.
Creation of ASP.NET Environment
Step 1: The user sends a request to IIS. IIS first checks which ISAPI extension can serve this request. Depending on file extension the request is processed. For instance, if the page is an ‘.ASPX page’, then it will be passed to ‘aspnet_isapi.dll’ for processing.
Step 2: If this is the first request to the website, then a class called as ‘ApplicationManager’ creates an application domain where the website can run. As we all know, the application domain creates isolation between two web applications hosted on the same IIS. So in case there is an issue in one app domain, it does not affect the other app domain.
Step 3: The newly created application domain creates hosting environment, i.e. the ‘HttpRuntime’ object. Once the hosting environment is created, the necessary core ASP.NET objects like ‘HttpContext’ , ‘HttpRequest’ and ‘HttpResponse’ objects are created.
Step 4: Once all the core ASP.NET objects are created, ‘HttpApplication’ object is created to serve the request. In case you have a ‘global.asax’ file in your system, then the object of the ‘global.asax’ file will be created. Please note global.asax file inherits from ‘HttpApplication’ class.Note: The first time an ASP.NET page is attached to an application, a new instance of ‘HttpApplication’ is created. Said and done to maximize performance, HttpApplication instances might be reused for multiple requests.
Step 5: The HttpApplication object is then assigned to the core ASP.NET objects to process the page.
Step 6: HttpApplication then starts processing the request by HTTP module events, handlers and page events. It fires the MHPM event for request processing.Note: For more details, read this.
The below image explains how the internal object model looks like for an ASP.NET request. At the top level is the ASP.NET runtime which creates an ‘Appdomain’ which in turn has ‘HttpRuntime’ with ‘request’, ‘response’ and ‘context’ objects.
Process Request using MHPM Events Fired
Once ‘HttpApplication’ is created, it starts processing requests. It goes through 3 different sections ‘HttpModule’ , ‘Page’ and ‘HttpHandler’. As it moves through these sections, it invokes different events which the developer can extend and add customize logic to the same.
Before we move ahead, let's understand what are ‘HttpModule’ and ‘HttpHandlers’. They help us to inject custom logic before and after the ASP.NET page is processed. The main differences between both of them are:
- If you want to inject logic based in file extensions like ‘.ASPX’, ‘.HTML’, then you use ‘HttpHandler’. In other words, ‘HttpHandler’ is an extension based processor.
- If you want to inject logic in the events of ASP.NET pipleline, then you use ‘HttpModule’. ASP.NET. In other words, ‘HttpModule’ is an event based processor.
You can read more about the differences from here.
Below is the logical flow of how the request is processed. There are 4 important steps MHPM as explained below:
Step 1(M: HttpModule): Client request processing starts. Before the ASP.NET engine goes and creates the ASP.NET HttpModule emits events which can be used to inject customized logic. There are 6 important events which you can utilize before your page object is created BeginRequest, AuthenticateRequest, AuthorizeRequest, ResolveRequestCache, AcquireRequestState and PreRequestHandlerExecute.
Step 2 (H: ‘HttpHandler’): Once the above 6 events are fired, ASP.NET engine will invoke ProcessRequest event if you have implemented HttpHandler in your project.
Step 3 (P: ASP.NET page): Once the HttpHandler logic executes, the ASP.NET page object is created. While the ASP.NET page object is created, many events are fired which can help us to write our custom logic inside those page events. There are 6 important events which provides us placeholder to write logic inside ASP.NET pages Init, Load, validate, event, render and unload. You can remember the word SILVER to remember the events S – Start (does not signify anything as such just forms the word) , I – (Init) , L (Load) , V (Validate), E (Event) and R (Render).
Step4 (M: HttpModule): Once the page object is executed and unloaded from memory, HttpModule provides post page execution events which can be used to inject custom post-processing logic. There are 4 important post-processing events PostRequestHandlerExecute, ReleaserequestState, UpdateRequestCache and EndRequest.
The below figure shows the same in a pictorial format.
In What Event Should We Do What?
The million dollar question is in which events should we do what? Below is the table which shows in which event what kind of logic or code can go.
Section | Event | Description |
HttpModule | BeginRequest | This event signals a new request; it is guaranteed to be raised on each request. |
HttpModule | AuthenticateRequest | This event signals that ASP.NET runtime is ready to authenticate the user. Any authentication code can be injected here. |
HttpModule | AuthorizeRequest | This event signals that ASP.NET runtime is ready to authorize the user. Any authorization code can be injected here. |
HttpModule | ResolveRequestCache | In ASP.NET, we normally use outputcache directive to do caching. In this event, ASP.NET runtime determines if the page can be served from the cache rather than loading the patch from scratch. Any caching specific activity can be injected here. |
HttpModule | AcquireRequestState | This event signals that ASP.NET runtime is ready to acquire session variables. Any processing you would like to do on session variables. |
HttpModule | PreRequestHandlerExecute | This event is raised just prior to handling control to the HttpHandler. Before you want the control to be handed over to the handler any pre-processing you would like to do. |
HttpHandler | ProcessRequest | Httphandler logic is executed. In this section, we will write logic which needs to be executed as per page extensions. |
Page | Init | This event happens in the ASP.NET page and can be used for:
|
Page | Load | In this section, the ASP.NET controls are fully loaded and you write UI manipulation logic or any other logic over here. |
Page | Validate | If you have valuators on your page, you would like to check the same here. |
Render | It’s now time to send the output to the browser. If you would like to make some changes to the final HTML which is going out to the browser, you can enter your HTML logic here. | |
Page | Unload | Page object is unloaded from the memory. |
HttpModule | PostRequestHandlerExecute | Any logic you would like to inject after the handlers are executed. |
HttpModule | ReleaserequestState | If you would like to save update some state variables like session variables. |
HttpModule | UpdateRequestCache | Before you end, if you want to update your cache. |
HttpModule | EndRequest | This is the last stage before your output is sent to the client browser. |
A Sample Code for Demonstration
With this article, we have attached a sample code which shows how the events actually fire. In this code, we have created a ‘HttpModule’ and ‘Httphandler’ in this project and we have displayed a simple response write in all events, below is how the output looks like.
Below is the class for ‘HttpModule’ which tracks all events and adds it to a global collection.Collapse | Copy Code
Collapse | Copy Code
public class clsHttpModule : IHttpModule
{
......
void OnUpdateRequestCache(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnUpdateRequestCache");
}
void OnReleaseRequestState(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnReleaseRequestState");
}
void OnPostRequestHandlerExecute(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnPostRequestHandlerExecute");
}
void OnPreRequestHandlerExecute(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnPreRequestHandlerExecute");
}
void OnAcquireRequestState(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnAcquireRequestState");
}
void OnResolveRequestCache(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnResolveRequestCache");
}
void OnAuthorization(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnAuthorization");
}
void OnAuthentication(object sender, EventArgs a)
{
objArrayList.Add("httpModule:AuthenticateRequest");
}
void OnBeginrequest(object sender, EventArgs a)
{
objArrayList.Add("httpModule:BeginRequest");
}
void OnEndRequest(object sender, EventArgs a)
{
objArrayList.Add("httpModule:EndRequest");
objArrayList.Add("<hr>");
foreach (string str in objArrayList)
{
httpApp.Context.Response.Write(str + "<br>") ;
}
}
}
Below is the code snippet for ‘HttpHandler’ which tracks ‘ProcessRequest’ event.Collapse | Copy Code
Collapse | Copy Code
public class clsHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
clsHttpModule.objArrayList.Add("HttpHandler:ProcessRequest");
context.Response.Redirect("Default.aspx");
}
}
We are also tracking all the events from the ASP.NET page.Collapse | Copy Code
Collapse | Copy Code
public partial class _Default : System.Web.UI.Page
{
protected void Page_init(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:Init");
}
protected void Page_Load(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:Load");
}
public override void Validate()
{
clsHttpModule.objArrayList.Add("Page:Validate");
}
protected void Button1_Click(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:Event");
}
protected override void Render(HtmlTextWriter output)
{
clsHttpModule.objArrayList.Add("Page:Render");
base.Render(output);
}
protected void Page_Unload(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:UnLoad");
}}
Below is how the display looks like with all events as per the sequence discussed in the previous section.
Zooming ASP.NET Page Events
In the above section, we have seen the overall flow of events for an ASP.NET page request. One of the most important sections is the ASP.NET page, we have not discussed the same in detail. So let’s take some luxury to describe the ASP.NET page events in more detail in this section.
Any ASP.NET page has 2 parts, one is the page which is displayed on the browser which has HTML tags, hidden values in form of viewstate and data on the HTML inputs. When the page is posted, these HTML tags are created in to ASP.NET controls with viewstate and form data tied up together on the server. Once you get these full server controls on the behind code, you can execute and write your own login on the same and render the page back to the browser.
Now between these HTML controls coming live on the server as ASP.NET controls, the ASP.NET page emits out lot of events which can be consumed to inject logic. Depending on what task / logic you want to perform, we need to put this logic appropriately in those events.Note: Most of the developers directly use the page_load method for everything, which is not a good thought. So it’s either populating the controls, setting view state, applying themes, etc., everything happens on the page load. So if we can put logic in proper events as per the nature of the logic, that would really make your code clean.
Seq | Events | Controls Initialized | View state Available | Form data Available | What Logic can be written here? |
1 | Init | No | No | No | Note: You can access form data etc. by using ASP.NET request objects but not by Server controls.Creating controls dynamically, in case you have controls to be created on runtime. Any setting initialization.Master pages and them settings. In this section, we do not have access to viewstate , posted values and neither the controls are initialized. |
2 | Load view state | Not guaranteed | Yes | Not guaranteed | You can access view state and any synch logic where you want viewstate to be pushed to behind code variables can be done here. |
3 | PostBackdata | Not guaranteed | Yes | Yes | You can access form data. Any logic where you want the form data to be pushed to behind code variables can be done here. |
4 | Load | Yes | Yes | Yes | This is the place where you will put any logic you want to operate on the controls. Like flourishing a combobox from the database, sorting data on a grid, etc. In this event, we get access to all controls, viewstate and their posted values. |
5 | Validate | Yes | Yes | Yes | If your page has validators or you want to execute validation for your page, this is the right place to the same. |
6 | Event | Yes | Yes | Yes | If this is a post back by a button click or a dropdown change, then the relative events will be fired. Any kind of logic which is related to that event can be executed here. |
7 | Pre-render | Yes | Yes | Yes | If you want to make final changes to the UI objects like changing tree structure or property values, before these controls are saved in to view state. |
8 | Save view state | Yes | Yes | Yes | Once all changes to server controls are done, this event can be an opportunity to save control data in to view state. |
9 | Render | Yes | Yes | Yes | If you want to add some custom HTML to the output this is the place you can. |
10 | Unload | Yes | Yes | Yes | Any kind of clean up you would like to do here. |
ASP.NET State Management Overview
.NET Framework 4Other Versions
51 out of 72 rated this helpful - Rate this topic
A new instance of the Web page class is created each time the page is posted to the server. In traditional Web programming, this would typically mean that all information associated with the page and the controls on the page would be lost with each round trip. For example, if a user enters information into a text box, that information would be lost in the round trip from the browser or client device to the server.
To overcome this inherent limitation of traditional Web programming, ASP.NET includes several options that help you preserve data on both a per-page basis and an application-wide basis. These features are as follows:
- View state
- Control state
- Hidden fields
- Cookies
- Query strings
- Application state
- Session state
- Profile Properties
The following sections describe options for state management that involve storing information either in the page or on the client computer. For these options, no information is maintained on the server between round trips.
View State
The ViewState property provides a dictionary object for retaining values between multiple requests for the same page. This is the default method that the page uses to preserve page and control property values between round trips.When the page is processed, the current state of the page and controls is hashed into a string and saved in the page as a hidden field, or multiple hidden fields if the amount of data stored in the ViewState property exceeds the specified value in the MaxPageStateFieldLength property. When the page is posted back to the server, the page parses the view-state string at page initialization and restores property information in the page.
You can store values in view state as well. For more information on using View State, see ASP.NET View State Overview. For recommendations about when you should use view state, see ASP.NET State Management Recommendations.
Control State
Sometimes you need to store control-state data in order for a control to work properly. For example, if you have written a custom control that has different tabs that show different information, in order for that control to work as expected, the control needs to know which tab is selected between round trips. The ViewState property can be used for this purpose, but view state can be turned off at a page level by developers, effectively breaking your control. To solve this, the ASP.NET page framework exposes a feature in ASP.NET called control state.The ControlState property allows you to persist property information that is specific to a control and cannot be turned off like the ViewState property.
Hidden Fields
ASP.NET allows you to store information in a HiddenField control, which renders as a standard HTML hidden field. A hidden field does not render visibly in the browser, but you can set its properties just as you can with a standard control. When a page is submitted to the server, the content of a hidden field is sent in the HTTP form collection along with the values of other controls. A hidden field acts as a repository for any page-specific information that you want to store directly in the page.*Security Note |
It is easy for a malicious user to see and modify the contents of a hidden field. Do not store any information in a hidden field that is sensitive or that your application relies on to work properly. For more information, see ASP.NET State Management Recommendations. |
A HiddenField control stores a single variable in its Value property and must be explicitly added to the page. For more information, see HiddenField Web Server Control Overview.
In order for hidden-field values to be available during page processing, you must submit the page using an HTTP POST command. If you use hidden fields and a page is processed in response to a link or an HTTP GET command, the hidden fields will not be available. For usage recommendations, see ASP.NET State Management Recommendations.
Cookies
A cookie is a small amount of data that is stored either in a text file on the client file system or in-memory in the client browser session. It contains site-specific information that the server sends to the client along with page output. Cookies can be temporary (with specific expiration times and dates) or persistent.You can use cookies to store information about a particular client, session, or application. The cookies are saved on the client device, and when the browser requests a page, the client sends the information in the cookie along with the request information. The server can read the cookie and extract its value. A typical use is to store a token (perhaps encrypted) indicating that the user has already been authenticated in your application.
*Security Note |
The browser can only send the data back to the server that originally created the cookie. However, malicious users have ways to access cookies and read their contents. It is recommended that you do not store sensitive information, such as a user name or password, in a cookie. Instead, store a token in the cookie that identifies the user, and then use the token to look up the sensitive information on the server. |
For more information about using cookies, see Cookies and ASP.NET State Management Recommendations.
Query Strings
A query string is information that is appended to the end of a page URL. A typical query string might look like the following example:http://www.contoso.com/listwidgets.aspx?category=basic&price=100
In the URL path above, the query string starts with a question mark (?) and includes two attribute/value pairs, one called "category" and the other called "price."
Query strings provide a simple but limited way to maintain state information. For example, they are an easy way to pass information from one page to another, such as passing a product number from one page to another page where it will be processed. However, some browsers and client devices impose a 2083-character limit on the length of the URL.
*Security Note |
Information that is passed in a query string can be tampered with by a malicious user. Do not rely on query strings to convey important or sensitive data. Additionally, a user can bookmark the URL or send the URL to other users, thereby passing that information along with it. For more information, see ASP.NET State Management Recommendations and How to: Protect Against Script Exploits in a Web Application by Applying HTML Encoding to Strings. |
In order for query string values to be available during page processing, you must submit the page using an HTTP GET command. That is, you cannot take advantage of a query string if a page is processed in response to an HTTP POST command. For usage recommendations, see ASP.NET State Management Recommendations.Server-Based State Management Options
ASP.NET offers you a variety of ways to maintain state information on the server, rather than persisting information on the client. With server-based state management, you can decrease the amount of information sent to the client in order to preserve state, however it can use costly resources on the server. The following sections describe three server-based state management features: application state, session state, and profile properties.
Application State
ASP.NET allows you to save values using application state — which is an instance of the HttpApplicationState class — for each active Web application. Application state is a global storage mechanism that is accessible from all pages in the Web application. Thus, application state is useful for storing information that needs to be maintained between server round trips and between requests for pages. For more information, see ASP.NET Application State Overview.Application state is stored in a key/value dictionary that is created during each request to a specific URL. You can add your application-specific information to this structure to store it between page requests.
Once you add your application-specific information to application state, the server manages it. For usage recommendations, see ASP.NET State Management Recommendations.
Session State
ASP.NET allows you to save values by using session state — which is an instance of the HttpSessionState class — for each active Web-application session. For an overview, see ASP.NET Session State Overview.Session state is similar to application state, except that it is scoped to the current browser session. If different users are using your application, each user session will have a different session state. In addition, if a user leaves your application and then returns later, the second user session will have a different session state from the first.
Session state is structured as a key/value dictionary for storing session-specific information that needs to be maintained between server round trips and between requests for pages. For more information, see ASP.NET Session State Overview.
You can use session state to accomplish the following tasks:
- Uniquely identify browser or client-device requests and map them to an individual session instance on the server.
- Store session-specific data on the server for use across multiple browser or client-device requests within the same session.
- Raise appropriate session management events. In addition, you can write application code leveraging these events.
Profile Properties
ASP.NET provides a feature called profile properties, which allows you to store user-specific data. This feature is similar to session state, except that the profile data is not lost when a user's session expires. The profile-properties feature uses an ASP.NET profile, which is stored in a persistent format and associated with an individual user. The ASP.NET profile allows you to easily manage user information without requiring you to create and maintain your own database. In addition, the profile makes the user information available using a strongly typed API that you can access from anywhere in your application. You can store objects of any type in the profile. The ASP.NET profile feature provides a generic storage system that allows you to define and maintain almost any kind of data while still making the data available in a type-safe manner.To use profile properties, you must configure a profile provider. ASP.NET includes a SqlProfileProvider class that allows you to store profile data in a SQL database, but you can also create your own profile provider class that stores profile data in a custom format and to a custom storage mechanism such as an XML file, or even to a web service.
Because data that is placed in profile properties is not stored in application memory, it is preserved through Internet Information Services (IIS) restarts and worker-process restarts without losing data. Additionally, profile properties can be persisted across multiple processes such as in a Web farm or a Web garden. For more information,
Directives for ASP.NET Web Pages
.NET Framework 4Other Versions
2 out of 3 rated this helpful - Rate this topic
Directives specify settings that are used by the page and user-control compilers when the compilers process ASP.NET Web Forms pages (.aspx files) and user control (.ascx) files.
ASP.NET treats any directive block (<%@ %>) that does not contain an explicit directive name as an @ Page directive (for a page) or as an @ Control directive (for a user control).
For syntax information and descriptions of the attributes that are available for each directive, use the links that are listed in the following table.
Directive
|
Description
|
@ Assembly | Links an assembly to the current page or user control declaratively. |
@ Control | Defines control-specific attributes used by the ASP.NET page parser and compiler and can be included only in .ascx files (user controls). |
@ Implements | Indicates that a page or user control implements a specified .NET Framework interface declaratively. |
@ Import | Imports a namespace into a page or user control explicitly. |
@ Master | Identifies a page as a master page and defines attributes used by the ASP.NET page parser and compiler and can be included only in .master files. |
@ MasterType | Defines the class or virtual path used to type the Master property of a page. |
@ OutputCache | Controls the output caching policies of a page or user control declaratively. |
@ Page | Defines page-specific attributes used by the ASP.NET page parser and compiler and can be included only in .aspx files. |
@ PreviousPageType | Creates a strongly typed reference to the source page from the target of a cross-page posting. |
@ Reference | Links a page, user control, or COM control to the current page or user control declaratively. |
@ Register | Associates aliases with namespaces and classes, which allow user controls and custom server controls to be rendered when included in a requested page or user control. |
Explained: Forms Authentication in ASP.NET 2.0
23 out of 37 rated this helpful - Rate this topic
Retired Content
|
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. |
patterns & practices Developer Center
J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Chaitanya Bijwe
Microsoft Corporation
November 2005
Applies To
ASP.NET version 2.0Summary
This module explains how forms authentication works in ASP.NET version 2.0. It explains how IIS and ASP.NET authentication work together, and it explains the role and operation of the FormsAuthenticationModule class.Contents
ObjectivesOverview
IIS Authentication
ASP.NET Forms Authentication
Cookieless Forms Authentication
Membership and Login Controls
Web Farm Scenarios
Additional Resources
Objectives
- Learn how forms authentication works in ASP.NET version 2.0.
- Understand how forms authentication configuration affects the generation of the forms authentication ticket.
- See what's stored in a forms authentication ticket.
- Learn how cookieless forms authentication works.
- Identify Web farm considerations for forms authentication.
Overview
Forms authentication uses an authentication ticket that is created when a user logs on to a site, and then it tracks the user throughout the site. The forms authentication ticket is usually contained inside a cookie. However, ASP.NET version 2.0 supports cookieless forms authentication, which results in the ticket being passed in a query string.If the user requests a page that requires authenticated access and that user has not previously logged on to the site, then the user is redirected to a configured logon page. The logon page prompts the user to supply credentials, typically a user name and password. These credentials are then passed to the server and validated against a user store, such as a SQL Server database. In ASP.NET 2.0, user-store access can be handled by a membership provider. After the user's credentials are authenticated, the user is redirected to the originally requested page.
Forms authentication processing is handled by the FormsAuthenticationModule class, which is an HTTP module that participates in the regular ASP.NET page-processing cycle. This document explains how forms authentication works in ASP.NET 2.0.
IIS Authentication
ASP.NET authentication is a two-step process. First, Internet Information Services (IIS) authenticates the user and creates a Windows token to represent the user. IIS determines the authentication mode that it should use for a particular application by looking at IIS metabase settings. If IIS is configured to use anonymous authentication, a token for the IUSR_MACHINE account is generated and used to represent the anonymous user. IIS-then passes the token to ASP.NET.Second, ASP.NET performs its own authentication. The authentication method used is specified by the mode attribute of the authentication element. The following authentication configuration specifies that ASP.NET uses the FormsAuthenticationModule class:
<authentication mode="Forms" />
Note Because forms authentication does not rely on IIS authentication, you should configure anonymous access for your application in IIS if you intend to use forms authentication in your ASP.NET application.
ASP.NET Forms Authentication
ASP.NET forms authentication occurs after IIS authentication is completed. You can configure forms authentication with the forms element.Forms Authentication Configuration
The default attribute values for forms authentication are shown in the following configuration-file fragment.<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx"
protection="All"
timeout="30"
name=".ASPXAUTH"
path="/"
requireSSL="false"
slidingExpiration="true"
defaultUrl="default.aspx"
cookieless="UseDeviceProfile"
enableCrossAppRedirects="false" />
</authentication>
</system.web>
The default attribute values are described below:
- loginUrl points to your application's custom logon page. You should place the logon page in a folder that requires Secure Sockets Layer (SSL). This helps ensure the integrity of the credentials when they are passed from the browser to the Web server.
- protection is set to All to specify privacy and integrity for the forms authentication ticket. This causes the authentication ticket to be encrypted using the algorithm specified on the machineKey element, and to be signed using the hashing algorithm that is also specified on the machineKey element.
- timeout is used to specify a limited lifetime for the forms authentication session. The default value is 30 minutes. If a persistent forms authentication cookie is issued, the timeout attribute is also used to set the lifetime of the persistent cookie.
- name and path are set to the values defined in the application's configuration file.
- requireSSL is set to false. This configuration means that authentication cookies can be transmitted over channels that are not SSL-encrypted. If you are concerned about session hijacking, you should consider setting requireSSL to true.
- slidingExpiration is set to true to enforce a sliding session lifetime. This means that the session timeout is periodically reset as long as a user stays active on the site.
- defaultUrl is set to the Default.aspx page for the application.
- cookieless is set to UseDeviceProfile to specify that the application use cookies for all browsers that support cookies. If a browser that does not support cookies accesses the site, then forms authentication packages the authentication ticket on the URL.
- enableCrossAppRedirects is set to false to indicate that forms authentication does not support automatic processing of tickets that are passed between applications on the query string or as part of a form POST.
Authorization Configuration
In IIS, anonymous access is enabled for all applications that use forms authentication. The UrlAuthorizationModule class is used to help ensure that only authenticated users can access a page.You can configure UrlAuthorizationModule by using the authorization element as shown in the following example.
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
With this setting, all unauthenticated users are denied access to any page in your application. If an unauthenticated user tries to access a page, the forms authentication module redirects the user to the logon page specified by the loginUrl attribute of the forms element.
Forms Authentication Control Flow
Figure 1 shows the sequence of events that occur during forms authentication.Figure 1. Forms authentication control flow
- The user requests the Default.aspx file from your application's virtual directory. IIS allows the request because anonymous access is enabled in the IIS metabase. ASP.NET confirms that the authorization element includes a <deny users="?" /> tag.
- The server looks for an authentication cookie. If it fails to find the authentication cookie, the user is redirected to the configured logon page (Login.aspx), as specified by the LoginUrl attribute of the forms element. The user supplies and submits credentials through this form. Information about the originating page is placed in the query string using RETURNURL as the key. The server HTTP reply is as follows:
- 302 Found Location:
- http://localhost/FormsAuthTest/login.aspx?RETURNURL=%2fFormAuthTest%2fDefault.aspx
- The browser requests the Login.aspx page and includes the RETURNURL parameter in the query string.
- The server returns the logon page and the 200 OK HTTP status code.
- The user enters credentials on the logon page and posts the page, including the RETURNURL parameter from the query string, back to the server.
- The server validates user credentials against a store, such as a SQL Server database or an Active Directory user store. Code in the logon page creates a cookie that contains a forms authentication ticket that is set for the session.
In ASP.NET 2.0, the validation of user credentials can be performed by the membership system. The Membership class provides the ValidateUser method for this purpose as shown here:
if (Membership.ValidateUser(userName.Text, password.Text))
{
if (Request.QueryString["ReturnUrl"] != null)
{
FormsAuthentication.RedirectFromLoginPage(userName.Text, false);
}
else
{
FormsAuthentication.SetAuthCookie(userName.Text, false);
}
}
else
{
Response.Write("Invalid UserID and Password");
}
Note When using the Login Web server control, it automatically performs the following steps for you. The preceding code is provided for context.
- For the authenticated user, the server redirects the browser to the original URL that was specified in the query string by the RETURNURL parameter. The server HTTP reply is as follows:
- 302 Found Location:
- http://localhost/TestSample/default.aspx
- Following the redirection, the browser requests the Default.aspx page again. This request includes the forms authentication cookie.
- The FormsAuthenticationModule class detects the forms authentication cookie and authenticates the user. After successful authentication, the FormsAuthenticationModule class populates the current User property, which is exposed by the HttpContext object, with information about the authenticated user.
- Since the server has verified the authentication cookie, it grants access and returns the Default.aspx page.
FormsAuthenticationModule
ASP.NET 2.0 defines a set of HTTP modules in the machine-level Web.config file. These include a number of authentication modules as shown here:<httpModules>
...
<add name="WindowsAuthentication"
type="System.Web.Security.WindowsAuthenticationModule" />
<add name="FormsAuthentication"
type="System.Web.Security.FormsAuthenticationModule" />
<add name="PassportAuthentication"
type="System.Web.Security.PassportAuthenticationModule" />
...
</httpModules>
Only one authentication module is used for each request. The authentication module that is used depends on which authentication mode has been specified by the authentication element, usually in the Web.config file in the application's virtual directory.
The FormsAuthenticationModule class is activated when the following element is in the Web.config file.
<authentication mode="Forms" />
The FormsAuthenticationModule class constructs a GenericPrincipal object and stores it in the HTTP context. The GenericPrincipal object holds a reference to a FormsIdentity instance that represents the currently authenticated user. You should allow forms authentication to manage these tasks for you. If your applications have specific requirements, such as setting the User property to a custom class that implements the IPrincipal interface, your application should handle the PostAuthenticate event. The PostAuthenticate event occurs after the FormsAuthenticationModule has verified the forms authentication cookie and created the GenericPrincipal and FormsIdentity objects. Within this code, you can construct a custom IPrincipal object that wraps the FormsIdentity object, and then store it in the HttpContext. User property.
Note If you do this, you will also need to set the IPrincipal reference on the Thread.CurrentPrincipal property to ensure that the HttpContext object and the thread point to the same authentication information.
Forms Authentication Cookies
The FormsAuthentication class creates the authentication cookie automatically when the FormsAuthentication.SetAuthCookie or FormsAuthentication.RedirectFromLoginPage methods are called.The following properties are included in a typical forms authentication cookie:
- Name. This property specifies the name of the cookie.
- Value. This property specifies value of the cookie.
- Expires. This property specifies the expiration date and time for the cookie. Forms authentication only sets this value if your code indicates that a persistent forms-authentication cookie should be issued.
- Domain. This property specifies the domain with which the cookie is associated. The default value is null.
- HasKeys. This property indicates whether the cookie has subkeys.
- HttpOnly. This property specifies whether the cookie can be accessed by client script. In ASP.NET 2.0, this value is always set to true. Internet Explorer 6 Service Pack 1 supports this cookie attribute, which prevents client-side script from accessing the cookie from the document.cookie property. If an attempt is made to access the cookie from client-side script, an empty string is returned. The cookie is still sent to the server whenever the user browses to a Web site in the current domain.
Note Web browsers that do not support the HttpOnly cookie attribute either ignore the cookie or ignore the attribute, which means that the session is still subject to cross-site scripting attacks.
- Path. This property specifies the virtual path for the cookie. The default value is "/", indicating root directory.
- Secure. This property specifies whether the cookie should only be transmitted over an HTTPS connection. The Secure property should be set to true so that the cookie is protected by SSL encryption.
- Version. This property specifies the version number of the cookie.
Creating the Forms Authentication Cookie
The forms authentication cookie is created by the FormsAuthentication class as follows. Once the user is validated, the FormsAuthentication class internally creates a FormsAuthenticationTicket object by specifying the cookie name; the version of the cookie; the directory path; the issue date of the cookie; the expiration date of the cookie; whether the cookie should be persisted; and, optionally, user-defined data.FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
"userName",
DateTime.Now,
DateTime.Now.AddMinutes(30), // value of time out property
false, // Value of IsPersistent property
String.Empty,
FormsAuthentication.FormsCookiePath);
Next, forms authentication uses the Encrypt method for encrypting and signing the forms authentication ticket, if the protection attribute of the forms element is set to All or Encryption.
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
The following text shows the process used when the protection attribute is set to All:
- Create a serialized forms authentication ticket. A byte array representation of the ticket is created.
- Sign the forms authentication ticket. The message authentication code (MAC) value for the byte array is computed by using the algorithm and key specified by the validation and validationKey attributes of the machineKey element. By default, the SHA1 algorithm is used.
- Encrypt forms authentication ticket. The second byte array that has been created is encrypted by using the Encrypt method of the FormsAuthentication class. The Encrypt method internally uses the algorithm and key specified by the decryption and decryptionKey attributes on the machineKey element. ASP.NET version 1.1 uses the 3DES algorithm by default. ASP.NET version 2.0 uses the Rinjdael (AES) algorithm by default.
- Create HTTP cookie or query string as appropriate. The encrypted authentication ticket is then added to an HttpCookie object or query string if forms authentication is configured for cookieless authentication. The cookie object is created using the following code:
- HttpCookie authCookie = new HttpCookie(
- FormsAuthentication.FormsCookieName,
- encryptedTicket);
- Set forms authentication cookie as secure. If the forms authentication ticket is configured to use SSL, the HttpCookie. Secure property is set to true. This instructs browsers to only send the cookie over HTTPS connections.
- authCookie.Secure = true;
- Set the HttpOnly bit. In ASP.NET 2.0, this bit is always set.
- Set appropriate cookie attributes. If needed, set the path, domain and expires attributes of the cookie.
- Add the cookie to the cookie collection. The authentication cookie is added to the cookie collection to be returned to the client browser.
- Response.Cookies.Add(authCookie);
Note ASP.NET does not depend on the expiration date of the cookie because this date could be easily forged.
Role Authorization
In ASP.NET 2.0, role authorization has been simplified. You no longer need to retrieve role information when the user is authenticated or add role details to the authentication cookie. The .NET Framework 2.0 includes a role management API that enables you to create and delete roles, and add users to and remove users from roles. The role management API stores its data in an underlying data store that it accesses through an appropriate role provider for that data store. The following role providers are included with the .NET Framework 2.0 and can be used with forms authentication:- SQL Server. This is the default provider and it stores role information in a SQL Server database.
- Authorization Manager (AzMan). This provider uses an AzMan policy store in an XML file, in Active Directory, or in Active Directory Application Mode (ADAM) as its role store. It is typically used in an intranet or extranet scenario where Windows authentication and Active Directory are used for authentication.
Cookieless Forms Authentication
ASP.NET 2.0 supports cookieless forms authentication. This feature is controlled by the cookieless attribute of the forms element. This attribute can be set to one of the following four values:- UseCookies. This value forces the FormsAuthenticationModule class to use cookies for transmitting the authentication ticket.
- UseUri. This value directs the FormsAuthenticationModule class to rewrite the URL for transmitting the authentication ticket.
- UseDeviceProfile. This value directs the FormsAuthenticationModule class to look at the browser capabilities. If the browser supports cookies, then cookies are used; otherwise, the URL is rewritten.
- AutoDetect. This value directs the FormsAuthenticationModule class to detect whether the browser supports cookies through a dynamic detection mechanism. If the detection logic indicates that cookies are not supported, then the URL is rewritten.
http://localhost/CookielessFormsAuthTest/(F(-k9DcsrIY4CAW81Rbju8KRnJ5o_gOQe0I1E_jNJLYm74izyOJK8GWdfoebgePJTEws0Pci7fHgTOUFTJe9jvgA2))/Test.aspx
The section of the URL that is in parentheses contains the data that the cookie would usually contain. This data is removed by ASP.NET during request processing. This step is performed by the ASP.NET ISAPI filter and not in an HttpModule class. If you read the Request.Path property from an .aspx page, you won't see any of the extra information in the URL. If you redirect the request, the URL will be rewritten automatically.
Note It is not possible to secure authentication tickets contained in URLs. When security is paramount, you should use cookies to store authentication tickets.
Membership and Login Controls
ASP.NET 2.0 introduces a membership feature and set of login Web server controls that simplify the implementation of applications that use forms authentication.Membership provides credential storage and management for application users. It also provides a membership API that simplifies the task of validating user credentials when used with forms authentication. The membership feature is built on top of a provider model. This model allows implementing and configuring different providers pointing to different user stores. ASP.NET 2.0 includes the following membership providers:
- Active Directory membership provider. This provider uses either an Active Directory or Active Directory Application Mode (ADAM) user store.
- SQL Server membership provider. This provider uses a SQL Server user store.
ASP.NET login controls automatically use membership and forms authentication and encapsulate the logic required to prompt users for credentials, validate users, recover or replace passwords, and so on. In effect, the ASP.NET login controls provide a layer of abstraction over forms authentication and membership, and they replace most, or all of, the work you would normally have to do to use forms authentication.
For more information about using the membership feature and login controls, see How To: Use Membership in ASP.NET 2.0.
Web Farm Scenarios
In a Web farm, you cannot guarantee which server will handle successive requests. If a user is authenticated on one server and the next request goes to another server, the authentication ticket will fail the validation and require the user to re-authenticate.The validationKey and decryptionKey attributes in the machineKey element are used for hashing and encryption of the forms authentication ticket. The default value for these attributes is AutoGenerate.IsolateApps. The keys are auto-generated for each application, and they are different on each server. Therefore, authentication tickets that are encrypted on one computer cannot be decrypted and verified on another computer in a Web farm, or in another application on the same Web server.
HTTP Handlers and HTTP Modules Overview
.NET Framework 4Other Versions
11 out of 24 rated this helpful - Rate this topic
An ASP.NET HTTP handler is the process (frequently referred to as the "endpoint") that runs in response to a request made to an ASP.NET Web application. The most common handler is an ASP.NET page handler that processes .aspx files. When users request an .aspx file, the request is processed by the page through the page handler. You can create your own HTTP handlers that render custom output to the browser.
An HTTP module is an assembly that is called on every request that is made to your application. HTTP modules are called as part of the ASP.NET request pipeline and have access to life-cycle events throughout the request. HTTP modules let you examine incoming and outgoing requests and take action based on the request.
This topic contains:
Typical uses for custom HTTP handlers include the following:
- RSS feeds To create an RSS feed for a Web site, you can create a handler that emits RSS-formatted XML. You can then bind a file name extension such as .rss to the custom handler. When users send a request to your site that ends in .rss, ASP.NET calls your handler to process the request.
- Image server If you want a Web application to serve images in a variety of sizes, you can write a custom handler to resize images and then send them to the user as the handler's response.
- Security Because you can examine incoming requests, an HTTP module can perform custom authentication or other security checks before the requested page, XML Web service, or handler is called. In Internet Information Services (IIS) 7.0 running in Integrated mode, you can extend forms authentication to all content types in an application.
- Statistics and logging Because HTTP modules are called on every request, you can gather request statistics and log information in a centralized module, instead of in individual pages.
- Custom headers or footers Because you can modify the outgoing response, you can insert content such as custom header information into every page or XML Web service response.
HTTP handler and module features include the following:
- The IHttpHandler and IHttpModule interfaces are the starting point for developing handlers and modules.
- The IHttpAsyncHandler interface is the starting point for developing asynchronous handlers.
- Custom handler and module source code can be put in the App_Code folder of an application, or it can be compiled and put in the Bin folder of an application.
- Handlers and modules developed for use in IIS 6.0 can be used in IIS 7.0 with little or no change. For more information, see Moving an ASP.NET Application from IIS 6.0 to IIS 7.0.
- Modules can subscribe to a variety of request-pipeline notifications. Modules can receive notification of events of the HttpApplication object.
- In IIS 7.0, the request pipeline is integrated with the Web server request pipeline. HTTP modules can be used for any request to the Web server, not just ASP.NET requests.
HTTP Handlers
An ASP.NET HTTP handler is the process that runs in response to a request that is made to an ASP.NET Web application. The most common handler is an ASP.NET page handler that processes .aspx files. When users request an .aspx file, the request is processed by the page handler.The ASP.NET page handler is only one type of handler. ASP.NET includes several other built-in handlers such as the Web service handler for .asmx files.
Built-in HTTP Handlers in ASP.NET
ASP.NET maps HTTP requests to HTTP handlers based on a file name extension. Each HTTP handler can process individual HTTP URLs or groups of URL extensions in an application. ASP.NET includes several built-in HTTP handlers, as listed in the following table.
Handler
|
Description
|
ASP.NET page handler (*.aspx) | The default HTTP handler for all ASP.NET pages. |
Web service handler (*.asmx) | The default HTTP handler for Web service pages created as .asmx files in ASP.NET. |
Generic Web handler (*.ashx) | The default HTTP handler for all Web handlers that do not have a UI and that include the @ WebHandler directive. |
Trace handler (trace.axd) | A handler that displays current page trace information. For details, see How to: View ASP.NET Trace Information with the Trace Viewer. |
Creating a Custom HTTP Handler
To create a custom HTTP handler, you create a class that implements the IHttpHandler interface to create a synchronous handler. Alternatively, you can implement IHttpAsyncHandler to create an asynchronous handler. Both handler interfaces require that you implement the IsReusable property and the ProcessRequest method. The IsReusable property specifies whether the IHttpHandlerFactory object (the object that actually calls the appropriate handler) can put the handler in a pool and reuse it to increase performance. If the handler cannot be pooled, the factory must create a new instance of the handler every time that the handler is needed.The ProcessRequest method is responsible for processing individual HTTP requests. In this method, you write the code that produces the output for the handler.
HTTP handlers have access to the application context. This includes the requesting user's identity (if known), application state, and session information. When an HTTP handler is requested, ASP.NET calls the ProcessRequest method of the appropriate handler. The code that you write in the handler's ProcessRequest method creates a response, which is sent back to the requesting browser.
Mapping a File Name Extension
When you create a class file as your HTTP handler, the handler can respond to any file name extension that is not already mapped in IIS and in ASP.NET. For example, if you are creating an HTTP handler for generating an RSS feed, you can map your handler to the .rss file name extension. In order for ASP.NET to know which handler to use for your custom file name extension, in IIS you must map the extension to ASP.NET. Then in the application, you must map the extension to the custom handler.By default, ASP.NET maps the file name extension .ashx to an HTTP handler. If you add the @ WebHandler directive to a class file, ASP.NET automatically maps the .ashx file name extension to the default HTTP handler. This is similar to the way ASP.NET maps the .aspx file name extension to the ASP.NET page handler when the @ Page directive is used. Therefore, if you create an HTTP handler class that has the file name extension .ashx, the handler is automatically registered with IIS and ASP.NET.
If you want to create a custom file name extension for a handler, you must explicitly register the extension with IIS and ASP.NET. The advantage of not using the .ashx file name extension is that the handler is then reusable for different extension mappings. For example, in one application the custom handler might respond to requests that end in .rss. In another application, it might respond to requests that end in .feed. As another example, the handler might be mapped to both file name extensions in the same application, but might create different responses based on the extension.
The process for registering a handler's custom file name extension is different in IIS 7.0 and in earlier versions of IIS. For more information, see How to: Register HTTP Handlers and How to: Configure an HTTP Handler Extension in IIS.
Asynchronous and Synchronous HTTP Handlers
An HTTP handler can be either synchronous or asynchronous. A synchronous handler does not return until it finishes processing the HTTP request for which it is called. An asynchronous handler runs a process independently of sending a response to the user. Asynchronous handlers are useful when you must start an application process that might be lengthy and the user does not have to wait until it finishes before receiving a response from the server.Asynchronous HTTP handlers enable you to start an external process, such as a method call to a remote server. The handler can then continue processing without waiting for the external process to finish. While an asynchronous HTTP handler is processing, ASP.NET puts the thread that would ordinarily be used for the external process back into the thread pool until the handler receives a callback from the external process. This can prevent thread blocking and can improve performance because only a limited number of threads can execute at the same time. If many users request synchronous HTTP handlers that rely on external processes, the operating system can run out of threads, because many threads are blocked and are waiting for an external process.
When you create an asynchronous handler, you must implement the IHttpAsyncHandler interface. You must also implement the BeginProcessRequest method in order to initiate an asynchronous call that processes individual HTTP requests. In addition, you must implement the EndProcessRequest method to run cleanup code when the process ends.
Custom IHttpHandlerFactory Classes
The IHttpHandlerFactory class receives requests and is responsible for forwarding a request to the appropriate HTTP handler. You can create a custom HTTP handler factory by creating a class that implements the IHttpHandlerFactory interface. A custom handler factory can give you finer control over how HTTP requests are processed by creating different handlers based on run-time conditions. For example, with a custom HTTP handler factory, you can instantiate one HTTP handler for a file type if the HTTP request method is PUT, and another if the method is GET.To register a custom extension for a handler factory, follow the steps for registering a custom extension for a handler. For an example of creating and registering a handler factory, see Walkthrough: Creating and Registering HTTP Handler Factories.
HTTP Modules
An HTTP module is an assembly that is called on every request that is made to your application. HTTP modules are called as part of the request pipeline and have access to life-cycle events throughout the request. HTTP modules therefore let you examine incoming requests and take action based on the request. They also let you examine the outgoing response and modify it.In IIS 6.0, the ASP.NET request pipeline is separate from the Web server request pipeline. In IIS 7.0, the ASP.NET request pipeline and the Web server request pipeline can be integrated into a common request pipeline. In IIS 7.0, this is referred to as Integrated mode. The unified pipeline has several benefits for ASP.NET developers. For example, it lets managed-code modules receive pipeline notifications for all requests, even if the requests are not for ASP.NET resources. However, if you want, you can run IIS 7.0 in Classic mode, which emulates ASP.NET running in IIS 6.0. For more information, see ASP.NET Application Life Cycle Overview for IIS 7.0.
ASP.NET HTTP modules are like ISAPI filters because they are invoked for all requests. However, they are written in managed code and are fully integrated with the life cycle of an ASP.NET application. You can put custom module source code in the App_Code folder of your application, or you can put compiled custom modules as assemblies in the Bin folder of an application.
ASP.NET uses modules to implement various application features, which includes forms authentication, caching, session state, and client script services. In each case, when those services are enabled, the module is called as part of a request and performs tasks that are outside the scope of any single page request. Modules can consume application events and can raise events that can be handled in the Global.asax file. For more information about application events, see ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0 and ASP.NET Application Life Cycle Overview for IIS 7.0.
*Note |
HTTP modules differ from HTTP handlers. An HTTP handler returns a response to a request that is identified by a file name extension or family of file name extensions. In contrast, an HTTP module is invoked for all requests and responses. It subscribes to event notifications in the request pipeline and lets you run code in registered event handlers. The tasks that a module is used for are general to an application and to all requests for resources in the application. |
How HTTP Modules Work
Modules must be registered to receive notifications from the request pipeline. The most common way to register an HTTP module is in the application's Web.config file. In IIS 7.0, the unified request pipeline also enables you to register a module in other ways, which includes through IIS Manager and through the Appcmd.exe command-line tool. For more information, see Configuring Handler Mappings in IIS 7.0 and Start Appcmd.exe.When ASP.NET creates an instance of the HttpApplication class that represents your application, instances of any modules that have been registered are created. When a module is created, its Init method is called and the module initializes itself. For more information, see ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0 and ASP.NET ASP.NET Application Life Cycle Overview for IIS 7.0.
In a module's Init method, you can subscribe to various application events such as BeginRequest or EndRequest by binding the events to methods in the module.
*Note |
For modules that operate in the IIS 7.0 integrated pipeline, you should register event handlers in the Init method. |
When application events are raised, the appropriate method in your module is called. The method can perform whatever logic is required, such as checking authentication or logging request information. During event handling, the module has access to the Context property of the current request. This enables you to redirect the request to an alternative page, modify the request, or perform any other request manipulation. For example, if the module checks authentication, the module might redirect to a login or error page if the credentials are not correct. Otherwise, when the module's event handler has finished running, ASP.NET calls the next process in the pipeline. This might be another module or might be the appropriate HTTP handler (such as an .aspx file) for the request.
HTTP Modules versus Global.asax Files
You can implement much of the functionality of a module in the application's Global.asax file, which enables you to respond to application events. However, modules have an advantage over the Global.asax file because they are encapsulated and can be created one time and used in many different applications. By adding them to the global assembly cache and registering them in the Machine.config file, you can reuse them across applications. For more information, see Global Assembly Cache.*Note |
In IIS 7.0, the integrated pipeline enables managed modules to subscribe to pipeline notifications for all requests, not just requests for ASP.NET resources. Event handlers in the Global.asax file are invoked only for notifications during requests for resources in the application. Custom modules in Integrated mode can be explicitly scoped to receive event notifications only for requests to the application. Otherwise, custom modules receive event notification for all requests to the application. If the precondition attribute of the add element of the modules section is set to "managedHandler", the module is scoped to the application. |
The advantage of using the Global.asax file is that you can handle other registered events such as Session_Start and Session_End. In addition, the Global.asax file enables you to instantiate global objects that are available throughout the application.
You should use a module whenever you must create code that depends on application events, and when the following conditions are true:
- You want to re-use the module in other applications.
- You want to avoid putting complex code in the Global.asax file.
- The module applies to all requests in the pipeline (IIS 7.0 Integrated mode only).
Creating an HTTP Module
The general process for writing an HTTP module is as follows:- Create a class that implements the IHttpModule interface.
- Write a handler for the Init method. The initialization method should initialize your module and subscribe to any application events you need. For example, if you want to append something to responses, you might subscribe to the EndRequest event. If you want to perform custom authentication logic, you might subscribe to the AuthenticateRequest event. For more information about application events, see ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0.
- Write code for the events that you have subscribed to.
- Optionally implement the Dispose method if the module requires cleanup.
The guidelines in this topic list techniques that you can use to help maximize the throughput of ASP.NET Web applications. The guidelines are divided into the following sections:
Page and Server Control Processing
The following guidelines suggest ways to work with ASP.NET pages and controls efficiently.
- Avoid unnecessary round trips to the server There are circumstances in which using ASP.NET server controls and performing postback event handling are unnecessary. For example, validating user input in ASP.NET Web pages can often take place on the client before that data is submitted to the server. In general, if you do not need to relay information to the server to be verified or written to a data store, you can improve the page's performance and user experience by avoiding code that causes a round trip to the server. You can also use client callbacks to read data from the server instead of performing a full round trip. For details, see Implementing Client Callbacks Without Postbacks in ASP.NET Web Pages.
If you develop custom server controls, consider having them render client-side code for browsers that support ECMAScript (JavaScript). By using server controls in this way, you can dramatically reduce the number of times information is sent to the Web server. For more information, see Developing Custom ASP.NET Server Controls.
- Use the Page object's IsPostBack property to avoid performing unnecessary processing on a round trip If you write code that handles server control postback processing, you will sometimes want code to execute only the first time the page is requested rather than on each postback. Use the IsPostBack property to conditionally execute code depending on whether the page is generated in response to a server control event.
- Save server control view state only when necessary Automatic view state management enables server controls to repopulate their property values on a round trip without your having to write any code. However, this feature affects performance because a server control's view state is passed to and from the server in a hidden form field. It is helpful to understand when view state helps you and when it hinders your page's performance. For example, if you are binding a server control to data on every round trip, saved view state is not useful, because the control's values are replaced with new values during data binding. In that case, disabling view state saves processing time and reduces the size of the page.
View state is enabled for all server controls by default. To disable it, set the control's EnableViewState property to false, as in the following DataGrid server control example:
<asp:datagrid EnableViewState="false" datasource="..."
runat="server"/>
You can also disable view state for an entire page by using the @ Page directive. This is useful when you do not post back to the server from a page:
<%@ Page EnableViewState="false" %>
*Note |
The EnableViewState attribute is also supported in the @ Control directive to specify whether view state is enabled for a user control. |
To analyze the size of view state used by the server controls on your page, enable tracing for the page by including the trace="true" attribute in the @ Page directive. In the trace output, look at the Viewstate column of the Control Hierarchy table. For information about tracing and how to enable it, see ASP.NET Tracing.
- Leave buffering on unless you have a specific reason to turn it off There is a significant performance cost for disabling buffering of ASP.NET Web pages. For more information, see the Buffer property.
- Use the Transfer method of the Server object or cross-page posting to redirect between ASP.NET pages in the same application For details, see Redirecting Users to Another Page.
The following guidelines suggest ways to make state management efficient.
- Disable session state when you are not using it Not all applications or pages require per-user session state; you should disable session state if it is not needed. To disable session state for a page, set the EnableSessionState attribute in the @ Page directive to false, as in the following example:
- <%@ Page EnableSessionState="false" %>
*Note If a page requires access to session variables but will not create or modify them, set the EnableSessionState attribute in the @ Page directive to ReadOnly. - You can also disable session state for XML Web service methods. For more information, see XML Web Services Created Using ASP.NET and XML Web Service Clients.
- To disable session state for an application, set the Mode attribute to Off in the SessionState section of the application's Web.config file, as in the following example:
- <sessionState mode="Off" />
- Choose the appropriate session-state provider for your application needs ASP.NET provides multiple ways to store session data for your application: in-process session state, out-of-process session state as a Windows service, and out-of-process session state in a SQL Server database. (You can also create a custom session state provider to store session data in a data store of your choosing.) Each has its advantages, but in-process session state is by far the fastest solution. If you are storing only small amounts of volatile data in session state, it is recommended that you use the in-process provider. Out-of-process session state options are useful if you scale your application across multiple processors or multiple computers, or where you would like to retain session data if a server or process is restarted. For more information, see ASP.NET Session State.
The following guidelines suggest ways to make data access in your application efficient.- Use SQL Server and stored procedures for data access Of all the data access methods provided by the .NET Framework, using SQL Server for data access is the recommended choice for building high-performance, scalable Web applications. When using the managed SQL Server provider, you can get an additional performance boost by using compiled stored procedures wherever possible instead of SQL commands. For information about using SQL Server stored procedures, see Working with Command Parameters.
- Use the SqlDataReader class for a fast forward-only data cursor The SqlDataReader class provides a forward-only data stream retrieved from a SQL Server database. If you can use a read-only stream in your ASP.NET application, the SqlDataReader class offers higher performance than the DataSet class. The SqlDataReader class uses SQL Server's native network data-transfer format to read data directly from a database connection. For example, when binding to the SqlDataSource control, you will achieve better performance by setting the DataSourceMode property to DataReader. (Using a data reader incurs loss of some functionality.) Also, the SqlDataReader class implements the IEnumerable interface, which enables you to bind data to server controls as well. For more information, see the SqlDataReader class. For information about how ASP.NET accesses data, see Accessing Data with ASP.NET.
- Cache data and page output whenever possible ASP.NET provides mechanisms for caching page output or data when they do not need to be computed dynamically for every page request. In addition, designing pages and data requests to be cached, particularly in areas of your site where you expect heavy traffic, can optimize the performance of those pages. Using the cache appropriately can improve the performance of your site more than using any other feature of the .NET Framework.
When using ASP.NET caching, note the following. First, do not cache too many items. There is a memory cost for caching each item. Items that are easily recalculated or rarely used should not be cached. Second, do not assign cached items a short expiration time. Items that expire quickly cause unnecessary turnover in the cache and can cause extra work for cleanup code and for the garbage collector. You can monitor the turnover in the cache due to items expiring by using the Cache Total Turnover Rate performance counter associated with the ASP.NET Applications performance object. A high turnover rate can indicate a problem, especially when items are removed before they expire. (This situation is sometimes known as memory pressure.)- Use SQL cache dependency appropriately ASP.NET supports both table-based polling and query notification, depending on the version of SQL Server you are using. Table-based polling is supported by all versions of SQL Server. In table-based polling, if anything in a table changes, all listeners are invalidated. This can cause unnecessary churn in the application. Table-based polling is not recommended for tables that have many frequent changes. For example, table-based polling would be recommended on a catalog table that changes infrequently. It would not be recommended for an orders table, which would have more frequent updates. Query notification is supported by SQL Server 2005. Query notification supports specific queries, which reduces the number of notifications sent when a table is changed. While it can provide better performance than table-based polling, it does not scale to thousands of queries.
For more information on SQL cache dependency, see Walkthrough: Using ASP.NET Output Caching with SQL Server or Caching in ASP.NET with the SqlCacheDependency Class.- Use data source paging and sorting rather the UI (user interface) paging and sorting The UI paging feature of data controls such as DetailsView and GridView can be used with any data source object that supports the ICollection interface. For each paging operation, the data control queries the data source for the entire data collection and selects the row or rows to display, discarding the remaining data. If a data source implements DataSourceView and if the CanPage property returns true, the data control will use data source paging instead of UI paging. In that case, the data control will query for only the row needed for each paging operation. Thus, data source paging is more efficient than UI paging. Only the ObjectDataSource data source control supports data source paging. To enable data source paging on other data source controls, you must inherit from the data source control and modify its behavior.
- Balance the security benefit of event validation with its performance cost Controls that derive from the System.Web.UI.WebControls and System.Web.UI.HtmlControls classes can validate that an event originated from the user interface that was rendered by the control. This helps prevent the control from responding to spoofed event notification. For example, the DetailsView control can prevent processing of a Delete call (which is not inherently supported in the control) and being manipulated into deleting data. This validation has some performance cost. You can control this behavior using the EnableEventValidation configuration element and the RegisterForEventValidation method. The cost of validation depends on the number of controls on the page, and is in the range of a few percent.
*Security Note It is strongly recommended that you do not disable event validation. Before disabling event validation, you should be sure that no postback could be constructed that would have an unintended effect on your application. - Avoid using view state encryption unless necessary View state encryption prevents the users from being able to read the values in the hidden view state field. A typical scenario is a GridView control that carries an identifier field in the DataKeyNames property. The identifier field is needed to coordinate updates to records. Because you do not want the identifier visible to users, you can encrypt view state. However, encryption has a constant performance cost for initialization and an additional cost that depends on the size of view state being encrypted. The encryption is set up for each page load, so the same performance effect occurs on every page load.
- Use SqlDataSource caching, sorting, and filtering If the DataSourceMode property of the SqlDataSource control is set to DataSet, the SqlDataSource is able to cache the result set from a query. If data is cached in this way, the filtering and sorting operations of the control (configured with the FilterExpression and SortParameterName properties) use the cached data. In many cases your application will run faster if you cache the entire dataset, and use the FilterExpression and SortParameterName properties to sort and filter, rather than using SQL queries with "WHERE" and "SORT BY" clauses that access the database for each select action.
The following guidelines suggest ways to make your Web applications as a whole work efficiently.- Consider precompiling A Web application is batch-compiled on the first request for a resource such as an ASP.NET Web page. If no page in the application has been compiled, batch compilation compiles all pages in a directory in chunks to improve disk and memory usage. You can use the ASP.NET Compilation Tool (Aspnet_compiler.exe) to precompile a Web application. For in-place compilation, the compilation tool calls the ASP.NET runtime to compile the site in the same manner as when a user requests a page from the Web site. You can precompile a Web application so that the UI markup is preserved, or precompile the pages so that source code cannot be changed. For more information, see How to: Precompile ASP.NET Web SitesHow to: Precompile ASP.NET Web Sites.
- Run Web applications out-of-process on Internet Information Services 5.0 By default, ASP.NET on IIS 5.0 will service requests using an out-of-process worker process. This feature has been tuned for fast throughput. Because of its features and advantages, running ASP.NET in an out-of-process worker process is recommended for production sites.
- Recycle processes periodically You should recycle processes periodically, for both stability and performance. Over long periods of time, resources with memory leaks and bugs can affect Web server throughput, and recycling processes cleans up memory from these types of problems. However, you should balance the need to periodically recycle with recycling too often, because the cost of stopping the worker process, reloading pages, and re-obtaining resources and data can override the benefits of recycling.
ASP.NET Web applications running on Windows Server 2003, which uses IIS 6.0, do not need to have the process model setting adjusted because ASP.NET will use the IIS 6.0 process model settings.- Adjust the number of threads per worker process for your application if necessary The request architecture of ASP.NET tries to achieve a balance between the number of threads executing requests and available resources. The architecture allows only as many concurrently executing requests as there is CPU power available. This technique is known as thread gating. However, there are conditions in which the thread-gating algorithm does not work well. You can monitor thread gating in the Windows Performance monitor using the Pipeline Instance Count performance counter associated with the ASP.NET Applications performance object.
When an ASP.NET Web page calls an external resource, such as when performing database access or XML Web service requests, the page request generally stops until the external resource responds, freeing the CPU to process other threads. If another request is waiting to be processed and a thread is free in the thread pool, the waiting request begins processing. The result can be a high number of concurrently executing requests and many waiting threads in the ASP.NET worker process or application pool, which hinders the Web server's throughput, adversely affecting performance.To mitigate this, you can manually set the limit on the number of threads in the process by changing the MaxWorkerThreads and MaxIOThreads attributes in the processModel section of the Machine.config file.*Note Worker threads are for processing ASP.NET requests, while IO threads are used to service data from files, databases, or XML Web services. The values assigned to the process model attributes are the maximum number of each type of thread per CPU in the process. For a two-processor computer, the maximum number is twice the set value. For a four-processor computer, it is four times the set value. The defaults are good for one-processor or two- processor computers, but having 100 or 200 threads in the process for computers with more than two processors can be more detrimental than beneficial to performance. Too many threads in a process tend to slow down the server because of extra context switches, causing the operating system to spend CPU cycles on maintaining threads rather than processing requests. The appropriate number of threads is best determined through performance testing of your application.- For applications that rely extensively on external resources, consider enabling Web gardening on multiprocessor computers The ASP.NET process model helps enable scalability on multiprocessor computers by distributing work to several processes, one per CPU, each with processor affinity set to a CPU. This technique is called Web gardening. If your application uses a slow database server or calls COM objects that have external dependencies (to name only two possibilities), it can be beneficial to enable Web gardening for your application. However, you should test how well your application performs in a Web garden before you decide to enable it for a production Web site.
- Disable debug mode Always disable debug mode before deploying a production application or conducting any performance measurements. If debug mode is enabled, the performance of your application can suffer. For syntax information about setting debug mode, see Editing ASP.NET Configuration Files.
- Tune the configuration files for your Web server computer and for specific applications to suit your needs By default, ASP.NET configuration is set to enable the widest set of features and to try to accommodate the most common scenarios. Some default configuration settings can be changed to improve the performance of your applications, depending on what features you use. The following list includes configuration settings you should consider:
- Enable authentication only for applications that need it By default, the authentication mode for ASP.NET applications is Windows, or integrated NTLM. In most cases it is best to disable authentication in the Machine.config file and enable it in the Web.config files only for applications that need it.
- Configure your application to the appropriate request and response encoding settings The ASP.NET default encoding is UTF-8. If your application uses only ASCII characters, configure your application for ASCII for a slight performance improvement.
- Consider disabling AutoEventWireup for your application Setting the AutoEventWireup attribute to false in the Machine.config file means that the page will not bind page events to method based on a name match (for example, Page_Load). If you disable AutoEventWireup, your pages will get a slight performance boost by leaving the event wiring to you instead of performing it automatically.
If you want to handle page events, use one of two strategies. The first strategy is to override the methods in the base class. For example, you can override the OnLoad method of the Page object for the page load event instead of using a Page_Load method. (Be sure to call the base method to ensure all events are raised.) The second strategy is to bind to the events using the Handles keyword in Visual Basic or delegate wire-up in C#.- Remove unused modules from the request-processing pipeline By default, all features are left active in the HttpModules node in your server computer's Machine.config file. Depending on which features your application uses, you may be able to remove unused modules from the request pipeline to get a small performance boost. Review each module and its functionality and customize it to your needs. For example, if you do not use session state and output caching in your application, you can remove each from the HttpModules list so that requests do not have to invoke these modules without performing any other meaningful processing.
The following guidelines suggest ways to write efficient code.- Do not rely on exceptions in your code Exceptions can cause performance to suffer significantly, so you should avoid using them as a way to control normal program flow. If it is possible to detect in code a condition that would cause an exception, do so rather than catching the exception itself and handling the condition. Common scenarios to detect in code include checking for null, assigning a value to a String that will be parsed into a numeric value, or checking for specific values before applying math operations. The following example demonstrates code that could cause an exception and code that tests for a condition. Both produce the same result.
C#// This is not recommended.try {result = 100 / num;}catch (Exception e) {result = 0;}// This is preferred.if (num != 0)result = 100 / num;elseresult = 0;VB' This is not recommended.Tryresult = 100 / numCatch (e As Exception)result = 0End Try' This is preferred.If Not (num = 0)result = 100 / numElseresult = 0End If- Rewrite call-intensive COM components in managed code The .NET Framework provides an easy way to interoperate with traditional COM components. The benefit is that you can take advantage of the features of .NET while preserving your existing investments in COM components. However, there are some circumstances in which the performance cost of keeping your old components makes it worthwhile to migrate your components to managed code. Every situation is unique, and the best way to decide whether you need to port a component is to run performance measurements on your Web site. It is recommended that you investigate porting any COM component that is called often to managed code.
In many cases, it is not possible to migrate legacy components to managed code, particularly when initially migrating your Web applications. In such circumstances, one of the biggest performance impediments is marshaling data from unmanaged to managed environments. Therefore, when interoperating, perform as many tasks as possible on one side or the other and then make a single call rather than a series of smaller calls. For example, all strings in the common language runtime are in Unicode, so you should convert any strings to Unicode in your component before you make a call to managed code.Release any COM objects or native resources as soon as they have finished processing. This enables other requests to use them and minimizes the performance issues associated with requiring the garbage collector to release them later.- Avoid single-threaded apartment (STA) COM components By default, ASP.NET does not allow STA COM components to run in a page. To run them, you must include the ASPCompat=true attribute in the @ Page directive in the .aspx file. This switches the thread pool used for page execution to an STA thread pool, while also making the HttpContext and other built-in objects available to the COM object. Avoiding STA COM components is a performance optimization because it avoids any call marshaling from multithreaded apartment (MTA) to STA threads.
If you must use an STA COM component, avoid making numerous calls during an execution and try to send as much information as possible during each call. Also, avoid creating STA COM components during the construction of the page. For example, in the following code, the SampleSTAComponent would be instantiated at page construction time, which is created from a thread that is not the STA thread that runs the page. This can have an adverse performance impact, since it will require marshaling between MTA and STA threads to construct the page.<%@ Page Language="VB" ASPCompat="true" %><script runat=server>Dim myComp as new SampleSTAComponent()Public Sub Page_Load()myComp.Name = "Sample"End Sub</script><html><%Response.Write(Server.HtmlEncode(myComp.SayHello))%></html>The preferred mechanism is to delay object creation until the code is executing under an STA thread, as in the following example:<%@ Page Language="VB" ASPCompat="true" %><script runat=server>Dim myCompPublic Sub Page_Load()myComp = new SampleSTAComponent()myComp.Name = "Sample"End Sub</script><html><%Response.Write(Server.HtmlEncode(myComp.SayHello))%></html>
How to: Use the Namespace Alias Qualifier (C# Programming Guide)
The ability to access a member in the global namespace is useful when the member might be hidden by another entity of the same name.
For example, in the following code, Console resolves to TestApp.Console instead of to the Console type in the System namespace.
C#
using System;
C#
class TestApp
{
// Define a new class called 'System' to cause problems.
public class System { }
// Define a constant called 'Console' to cause more problems.
const int Console = 7;
const int number = 66;
static void Main()
{
// Error Accesses TestApp.Console
//Console.WriteLine(number);
}
}
Using System.Console still results in an error because the System namespace is hidden by the class TestApp.System:
C#
// Error Accesses TestApp.System
System.Console.WriteLine(number);
However, you can work around this error by using global::System.Console, like this:
C#
// OK
global::System.Console.WriteLine(number);
When the left identifier is global, the search for the right identifier starts at the global namespace. For example, the following declaration is referencing TestApp as a member of the global space.
C#
class TestClass : global::TestApp
Obviously, creating your own namespaces called System is not recommended, and it is unlikely you will encounter any code in which this has happened. However, in larger projects, it is a very real possibility that namespace duplication may occur in one form or another. In these situations, the global namespace qualifier is your guarantee that you can specify the root namespace.
Example
In this example, the namespace System is used to include the class TestClass therefore, global::System.Console must be used to reference the System.Console class, which is hidden by the System namespace. Also, the alias colAlias is used to refer to the namespace System.Collections; therefore, the instance of a System.Collections.Hashtable was created using this alias instead of the namespace.
C#
using colAlias = System.Collections;
namespace System
{
class TestClass
{
static void Main()
{
// Searching the alias:
colAlias::Hashtable test = new colAlias::Hashtable();
// Add items to the table.
test.Add("A", "1");
test.Add("B", "2");
test.Add("C", "3");
foreach (string name in test.Keys)
{
// Seaching the gloabal namespace:
global::System.Console.WriteLine(name + " " + test[name]);
}
}
}
}
Sample OutputA 1
B 2
C 3State Managemant …………….Introduction
Recently Code Project started a beginners walkthrough for web development, an initiative for organizing all the information required for web development under one article. I think it will be helpful for beginners to get guidelines for web development. This article is my contribution to the ASP.NET section where I describe the state management techniques and best practices used when developing with ASP.NET.HTTP Protocol and the Need for State Management Techniques
Hyper Text Transfer Protocol (HTTP) is a communication protocol which is implemented in the "World Wide Web(WWW)". It is a request/response style protocol. Clients (browsers, spider, etc) will request to a server (web server) and the server responds to these requests. HTTP uses TCP protocol for communication. It connects to a specific port (default is 80) to the server and communicates via that port. Once the response is received completely, client programs will be disconnected from the server. For each request, client programs have to acquire a connection with servers and do all the request cycles again.
ASP.NET files are just text files which will be placed in the server and served upon the request. When a request comes for a page, the server will locate the requested file and ask the ASP.NET engine to serve the request. The ASP.NET engine will process the server tags and generate HTML for it and return back to the client. HTTP is a stateless protocol and the server will abandon the connection once the request is served.
Since HTTP is stateless, managing state in web applications is challenging. State management techniques are used to maintain user state throughout the application. Managing state in a stand-alone application is trivial as they don't have a request/response nature. Information you want to maintain over the lifetime of a web applications depends on your context. It can be from simple numbers to very complex objects.
Understanding the state management techniques play a major role in creating efficient web applications. ASP.NET is very rich in state management techniques. The following are the commonly used state management techniques.- QueryString
- Cookies
- Cache
- ViewState
- Session state
- Application state
- Static variables
- Profiles
QueryString
This is the most simple and efficient way of maintaining information across requests. The information you want to maintain will be sent along with the URL. A typical URL with a query string looks like Collapse | Copy Code
www.somewebsite.com/search.aspx?query=foo
The URL part which comes after the ? symbol is called a QueryString. QueryString has two parts, a key and a value. In the above example, query is the key and foo is its value. You can send multiple values through querystring, separated by the & symbol. The following code shows sending multiple values to the foo.aspx page. Collapse | Copy Code
Response.Redirect("foo.aspx?id=1&name=foo");
The foo.aspx page will get the values like in the following table.Key Value id 1 name foo
The following code shows reading the QueryString values in foo.aspx Collapse | Copy Code
string id = Request.QueryString["id"];
string name = Request.QueryString["name"];
Request.QueryString has two overloaded indexers. One accepts the key name and another a zero-based index. The latter is useful when you don't know the query string names. If you try to get a value which is not in the QueryString collection, you will get a NULL reference.QueryString Encoding
The URL RFC [^] states that, a URL can have only ASCII characters. So all the other characters should be encoded when you pass through the URL. The .NET Framework provides the HttpServerUtility.UrlEncode class to encode the URL.
The following code shows how name and id is passed to foo.aspx page as encoded. Collapse | Copy Code
string id = "1";
string name = "foo#";
string url = string.Format("foo.aspx?{0}&{1}", Server.UrlEncode(id), Server.UrlEncode(name));
Response.Redirect(url);
// decoding can be done using it's counter part HttpServerUtility.UrlDecode()
string id = Server.UrlDecode(Request.QueryString["id"]);
string name = Server.UrlDecode(Request.QueryString["name"]);
Note: HttpServerUtility is available to your code in all webforms through the Page.Server property. Also you only need to encode those values which have non-ASCII characters, not all the values.Reading QueryString Safely
I have seen many people use code as shown below to read values from a QueryString collection Collapse | Copy Code
// Bad practice - Don't use!
Request.QueryString["id"].ToString();
This is hilarious. Request.QueryString[key] returns a string and has no need to convert it again to string. Another problem with the above code is, Request.QueryString[key] will return NULL if the specified key not found in the collection. In such cases, calling Request.QueryString[key].ToString() will lead to aNullReferenceException. The following code shows reading a QueryString value safely. Collapse | Copy Code
string queryStringValue = Request.QueryString["key"];
if (string.IsNullOrEmpty(queryStringValue)) {
// querystring not supplied. Do necessary action
}
else
// Querystring supplied. continue execution
Pros and Cons- You can pass information only as a string. If you need to pass objects in any case through QueryString, methods explained in this excellent article [^] will work. But it involves more effort.
- URL length has limitations. So you can't send much information through URL.
- Information passed is clearly visible to everyone and can be easily altered.
Producing Hackable URLs
URLs should be hackable, which means that, a user should be able to easily navigate from page to page by modifying the QueryString values. But you need to make sure that your website's security is not getting compromised by implementing this. A good example for hackable URLs is on MSDN. Consider the following Collapse | Copy Code
// System.Object classes documentation for .NET 1.1
http://msdn.microsoft.com/en-us/library/system.object(VS.71).aspx
// System.Object classes documentation for .NET 2.0. Just change the 71 to 80
http://msdn.microsoft.com/en-us/library/system.object(VS.80).aspx
This helps users to navigate between pages more easily.Securing QueryString
Since values in QueryString can be tampered easily, it is a programmer's job to ensure that it has valid values. You might be wondering, if QueryString is insecure, then why try to secure it instead of using some secure state management techniques? In some cases, you can't avoid using QueryString and you will be forced to send sensitive information through that. Consider a user email validation system. When user registers, the system will send a mail with a link to activate the user account. In this case, we have to pass some identification for the user account along with the URL. Since user account information is sensitive, we have to encrypt the QueryString value in the email validation link.
Consider a Edit.aspx?pid= page which allows to edit your personal details. You need to ensure the person id supplied has a valid type, integer in this case. The following code shows how this is done Collapse | Copy Code
string queryStringValue = Request.QueryString["pid"];
if (string.IsNullOrEmpty(queryStringValue)) {
// querystring not supplied. Do necessary action
}
else {
// Querystring supplied. continue execution
int personId;
if(!int.TryParse(queryStringValue,out personId))
// invalid type specified. Alert user
}
Then you may need to check whether the currently logged user is authorized to edit this record. Collapse | Copy Code
int personId;
if (int.TryParse(queryStringValue, out personId)) {
// check the edit permissions here
}
System.Security.Cryptography namespace has classes which help to encrypt strings. You can pass the encrypted string through the URL, so that it is tamperproof and secure up to a certain extent.Cookies
A cookie is a small file which is stored in the visitor's hard disk drive. This is helpful for storing small and trivial information. According to the RFC [^] , a cookie can have a maximum size of 4KB. The web server creates a cookie, attaches an additional HTTP header to the response, and sends it to the browser. The browser will then create this cookie in a visitor's computer and includes this cookie for all further requests made to the same domain. Servers can read the cookie value from the request and retain the state.
The server adds the following to the HTTP header for creating a cookie Collapse | Copy Code
Set-Cookie: key=value
The browser reads the above value and creates cookies at the user's end. It adds the cookie value to the request like Collapse | Copy Code
Cookie: key=value
Note: The location where the cookie is stored is completly controlled by the browser. Sometimes it may keep the cookie in its memory instead of creating a file.
Creating and using a cookie is trivial in ASP.NET. The HttpCookie class is a key/value collection which allows storing string values. The following code shows how to create a cookie and send it to the client. Cookies are added usingResponse property and retrieved using Request. Collapse | Copy Code
Response.Cookies["id"].Value = "10";
Since no expiry time specified, a cookie added like the above method will be cleared by the browser immediately when it is closed. If you would like to keep the cookie for a long time, you have to use the HttpCookie.Expiresproperty set with an expiration date. The following code shows how to do that. Collapse | Copy Code
// this cookie expires after one day from the date it is set
// browser will take care about removing the cookies after the expiry time
Response.Cookies["id"].Value = "10";
Response.Cookies["id"].Expires = DateTime.Now.AddDays(1);
Once you set the cookie, the browser will include it for every request. You read the cookie from theRequest.Cookies collection by specifying cookie name. Consider the following code Collapse | Copy Code
// for safety, always check for NULL as cookie may not exist
if (Request.Cookies["id"] != null) {
string userId = Request.Cookies["id"].Value;
Response.Write("User Id value" + userId);
}
Cookies are managed by the browser and will take care about removing expired cookies. If you need to remove a cookie before the expiry period, you have to create a cookie with the same name and with an expiry date that is already passed. This will make browser think that the cookie is expired and will be removed immediately. Here is how you do that Collapse | Copy Code
Response.Cookies["id"].Expires = DateTime.Now.AddDays(-1);
Some Useful Properties you Must Know Before Using CookiesProperty name Description Domain Specifies which domain is associated with this cookie. Default is the current domain. See security constraints later in this article Expires A DateTime value specifies the expiry time of the cookie HttpOnly Cookies can be accessed using java script. Setting this property prevents cookies being accessed from java script Secure Set this if cookies are transmitted over SSL Name Cookie name Value Cookie value (string) Multi-valued Cookies
RFC states that a browser should not store more than 20 cookies from a domain. Multi-Valued cookie is very handy when you have more items to keep in cookie. To create a multi-valued cookie, you instantiate the HttpCookieinstance and set it's values. Consider the following code Collapse | Copy Code
HttpCookie cookie = new HttpCookie("user");
cookie["name"] = "Foo";
cookie["age"] = "22";
cookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(cookie);
Here is how you read it Collapse | Copy Code
HttpCookie cookie = Request.Cookies["user"];
// for safety, always check for NULL. If cookie doesn't exist, it will be NULL
if (cookie != null) {
string name = cookie["name"];
string age = cookie["age"];
}
else
// Cookie not exist
A Practical Example- When the user checks the "Remember me next time" option, create a cookie with a value to identify the user (eg: user id).
- When the page loads, check for cookie existence. If it exists, read the cookie value.
- Authenticate the value and create a session.
Security Constraints
Since cookies are stored in the visitors computer, to prevent it from harming the system, browsers ensure some security constrains to cookies. THe following points explain the security constraints:- Cookies are specific to domains, which mean that a cookie set from "DomainA" is not accessible to "DomainB". Browsers store the domain with each cookie and will ensure it won't be sent to another domain.
- Other restriction is in size. Browsers will not allow storing cookies for more than 4KB from a domain.
- Browsers provides the option to disable cookies
While cookies are mostly used for storing account information, they are really not intended for such use. You should always take precautions to avoid hacks like the above by encrypting the values before keeping in cookie.Pros and Cons
A cookie is a very handy and easily usable state management technique. It is useful when you want to keep small information that is needed for long periods of time. The processing overhead of cookies is much less compared to sessions. However, it has the following disadvantages:- Cookies have a size limitation of 4KB. Storing huge information is not possible.
- Cookies can be easily tampered as they are kept in the client's machine. So additional security checking has to be done when using them.
- The user can disable cookies.
Session State
A cookie is very simple and is not suitable for sophisticated storage requirements. Session state is a workaround for this problem and it gives a method to keep more complex objects securely. ASP.NET allows programmers to keep any type of objects in session. Data stored in session will be kept in server memory and it is protected as it will never get transmitted to a client. Every client that uses the application will have separate sessions. Session state is ideal for storing user specific information.
The following code shows storing a string value in session. Collapse | Copy Code
Session["name"] = "Navaneeth";
Session accepts a System.Object type. So you need a type cast when reading. Reading values from session is like Collapse | Copy Code
string name = Session["name"] as string;
// null checking is needed as session may not exist
if(!string.IsNullOrEmpty(name))
// use the name here
Values stored in sessions can be removed by several methods. The following table shows different methods used.Method Description Session.Abandon() Cancels the session and fires end event. This is used when you are done with the session. Session.Clear() / Session.RemoveAll() Clears all contents of the session. This will not end the session Session.Remove(string) Removes the session name supplied. How Session Works?
ASP.NET maintains a unique id which is called as "session id" for each session. This id is generated using a custom algorithm and it is unique always. Session id will be sent to the client as a cookie and the browser resends this upon each request. ASP.NET uses this session id to identify the session object. The following code shows how to get the session id Collapse | Copy Code
string sessionId = Session.SessionID;
If you haven't stored anything in the session, ASP.NET will generate a different session id for each request. Once a session has contents, the session id will not change. Session id is the only information which is sent to the client about sessions. As said before, ASP.NET sends session id in a cookie named ASP.NET_SessionId. But this will not work if cookies are disabled by the visitor. In such cases, ASP.NET passes session id through the URL. This behaviour can be controlled by adding the following section to web.config file under the system.web section. Collapse | Copy Code
<sessionState
cookieless="UseUri" />
*
Note: ASP.NET AJAX extensions won't work as expected if this is enabled.Session Timeout
Each session will have a timeout value (default 20Mins). If the page is not getting any requests within the timeout limit specified, ASP.NET will assume that the user has left the application and it immediately terminates the session and fires the End event. This helps the server to cleanup unused sessions and gives room for new requests. Timeout value can be changed from web.config file or through code. Timeout value is specified in minutes. Collapse | Copy Code
<sessionState
timeout="60" />
or
Session.Timeout = 60;
Session Timing out Frequently- ASP.NET worker process recycles frequently. When this happens, it will clear all active sessions.
- When files like web.config or application assemblies are modified, ASP.NET will recyle the worker process.
Where Session is Stored?
ASP.NET allows three types of session storage which are described belowMode Configuration Storage location Description Pros/Cons InProc <sessionState mode="InProc" /> ASP.NET processes memory area This is the default session storage. Session data will be kept in the server memory. InProc mode is a high performant as it reads from the same processes memory and it allows you to keep all .NET types. If session mode is not specified, ASP.NET will use InProc as the default mode. As the InProcmode keeps data in same processes memory area, any impacts happened for the ASP.NET worker process will affect the session data. StateServer * Collapse | Copy Code
<sessionState<br />mode="StateServer"<br />stateConnectionString= "tcpip=Yourservername:42424" />
Server memory as a seprate process StateServer mode provides a basic level of isolation for the data storage. It runs as a separate windows service and keeps the session data out of ASP.NET process memory area. To access session, ASP.NET process has to communicate with this external process. It is less performant compared toInProc mode. But this helps you to avoid loosing session data when ASP.NET worker process restarts. SQL Server <sessionState mode="SQLServer" sqlConnectionString="..." /> In SQL server database If you still need more resillient storage, SQLServer mode is the choice. It allows to keep session data in SQLServer. This is helpful when your web application is hosted in a webfarm. - Slow data access
- Allows to store only serializable types
If any of the above discussed methods are not satisfying your storage requirements, ASP.NET allows to specify a custom storage provider. This [^] article shows how to do this.Usage and Best Practices
Incorrect usage of session will blow up your application. The most common error users make is the NULL reference exceptions when using sessions. Consider the following code Collapse | Copy Code
// bad code ! don't use
string name = Session["name"].ToString();
This code is problematic as session["name"] may not exist or may be NULL and ToString() will be called on that NULL reference which will throw the common "Object reference not set to an instance of the object" error.
Another problem with session is that it is not strongly typed. Session keeps System.Object type which means every .NET type can be kept in session. Consider the following code Collapse | Copy Code
Session["age"] = "I can store a value that is not number!";
Since it is not strongly typed, Session["age"] can contain any value and you will have problems when using this. Also, you may make typing mistakes when typing the session names. This will also lead to unexpected behaviours. The following section describes workarounds for these problems.Wrapping Session in a Strongly Typed Class
To workaround the above problems, we can create a strongly typed wrapper classes around the session and route all calls to session through this wrapper. Consider a simple scenario where you need to keep user details like name, age, email validated etc in a session. We create a class to represent all required fields. See the following code Collapse | Copy Code
public class PersonSession
{
// This key is used to identify object from session
const string KEY = "personDetails";
public PersonSession(int id,string name,int age,bool emailValidated)
{
this.Id = id;
this.Name = name;
this.Age = age;
this.HasEmailValidated = emailValidated;
}
public static PersonSession GetPersonSession() {
return HttpContext.Current.Session[KEY] as PersonSession;
}
public static void CreatePersonSession(PersonSession person) {
HttpContext.Current.Session[KEY] = person;
}
public int Id { get; private set; }
public string Name { get; private set; }
public int Age { get; private set; }
public bool HasEmailValidated { get; private set; }
}
The above given class abstracts the session access and provides a clear interface to access the session contents safely. The static methods CreatePersonSession and GetPersonSession can be used to create and get details of a person from session. The following code shows how to store person details into session. Collapse | Copy Code
PersonSession person = new PersonSession(int.Parse(txtPersonId.Text),
txtName.Text, int.Parse(txtAge.Text), chkEmailValidated.Checked);
PersonSession.CreatePersonSession(person);
To retrieve person details, you need to do Collapse | Copy Code
PersonSession person = PersonSession.GetPersonSession();
// if session not exist, this will return NULL
if (person != null) {
// person exist. Use person's properties to get values
}
*
Note: HttpContext.Current.Session is needed when accessing from a class that is not derived fromSystem.Web.UI.Page.Base Page Class Approach
Assume that you need to prevent users from seeing your page unless person details exists in session. You may end up doing the following code for all the pages that needs to be secured. Collapse | Copy Code
protected void Page_Load(object sender, EventArgs e)
{
PersonSession person = PersonSession.GetPersonSession();
// if session not exist, this will return NULL
if (person == null) {
// session not exist. Redirect user to login page
}
}
Writing the above code in all pages that needs session is redundant. It is very tough to make a change if something got changed in the session wrapper class-PersonSession. The recommended approach is to keep a base page class which is derived from System.Web.UI.Page and all your pages which need PersonSession should inherit from this base page class. This allows you to do the session checking in the base class and redirect the user if required. The following diagram shows this approach.
We create two classes NormalPage and SecuredPage both derived from System.Web.UI.Page. SecuredPageoverrides the OnInit method which looks like this: Collapse | Copy Code
protected override void OnInit(EventArgs e) {
base.OnInit(e);
// check the person details existance here
PersonSession person = PersonSession.GetPersonSession();
if (person == null) {
Response.Redirect("NotLogged.aspx");
}
else
this.Person = person;
}
If person details are not found in the session, it redirects to the NotLogged.aspx page and it sets the Personproperty if session exists. Classes which derive from this class can use this Person property to access the person details. Usage of this class is pretty straightforward. See the following code. Collapse | Copy Code
public partial class AuthenticatedPage : SecuredPage
{
protected void Page_Load(object sender, EventArgs e)
{
lblMessage.Text = "Session exist";
lblMessage.Text += string.Format("Person Id : {0}",Person.Id);
lblMessage.Text += string.Format("Person Name : {0}", Person.Name);
lblMessage.Text += string.Format("Person Age : {0}", Person.Age);
lblMessage.Text += string.Format("Email validated? : {0}", Person.HasEmailValidated);
}
}
Note: We are not using NormalPage here. If you have any particular behaviour common for all non-authenticated pages, this class is the best place to add that.
That's all about sessions. When using it, try not to abuse sessions. Overusing sessions may degrade your application performance.Application State
ASP.NET implements application state using the System.Web.HttpApplicationState class. It provides methods for storing information which can be accessed globally. Information stored on application state will be available for all the users using the website. Usage of application state is the same as sessions. The following code shows storing a value in an application variable and reading from it. Collapse | Copy Code
Application["pageTitle"] = "Welcome to my website - ";
// Reading the value from application variable
string pageTitle;
if (Application["pageTitle"] != null)
pageTitle = Application["pageTitle"].ToString();
Understanding Session and Application EventsEvent name Description Application_Start This event executes when application initializes. This will execute when ASP.NET worker process recycles and starts again. Application_End Executes when the application ends. Session_Start Executes when a new session starts. Session_End Executes when session ends. Note : this event will be fired only if you are using InProc as session mod. A Practical Example
The most common usage of application variables is to count the active number of visitors that are browsing currently. We can utilize session_start and session_end events to do this. The following code shows how this is done. Collapse | Copy Code
void Application_Start(object sender, EventArgs e)
{
// Application started - Initializing to 0
Application["activeVisitors"] = 0;
}
void Session_Start(object sender, EventArgs e)
{
if (Application["activeVisitors"] != null) {
Application.Lock();
int visitorCount = (int)Application["activeVisitors"];
Application["activeVisitors"] = visitorCount++;
Application.UnLock();
}
}
You might have noticed Application.Lock() and Application.UnLock() calls. ASP.NET is multithreaded and this is required to synchronize data when multiple visitors access the site at the same time.
Application state is not providing any timeout method like session. Application state will be available until the application ends. So one should be very careful when using application state. You should explicitly cleanup the values stored when you are finished using it.Keeping State in Static (shared in VB) Variables
Static variables will have a lifetime until the application domain where it is hosted ends. ASP.NET hosts each website in a separate application domain to provide isolation with other websites hosted on the same server.
Consider you have a page where all product details are displayed. Product details are fetched from the database and filled into custom collection and returned back to the page. To avoid fetching product details all time for each visitors, we can load it when it is requested for the first time and keep it in a static variable to serve for the next requests. Consider the following Product and ProductServices class. Collapse | Copy Code
class Product
{
public Product(int id,string name) {
this.Id = id;
this.Name = name;
}
public int Id { get; private set; }
public string Name { get; private set; }
}
class ProductService
{
static List<Product> products = null;
static readonly object locker = new object();
public static List<Product> GetAllProducts() {
// If product is NULL, loading all products and returning
if (products != null) {
lock (locker) {
if (products != null) {
// fill the products here
}
}
}
return products;
}
}
The above given code is self explanatory. The variable products will have a lifetime until the application domain unloads. When ProductService.GetAllProducts() is called for the first time, it fills the collection and return. For the further requests, it will just return the collection which is already filled.
Values kept in static variables are accessible to all visitors in the website. So you should take extra care when writing methods like the above. You need locking because multiple visitors may call the GetAllProducts method at the same time.
The above given example is an implementation of the " Singleton pattern [^] ".Profiles
Session data is lost when the visitor leaves the webpage. What if you need to persist all the user information for a long time? ASP.NET Profile is the answer. It provides a neat way to persist information for a long time. Creating a profile is trivial. You only need a few entries in the web.config file as seen below Collapse | Copy Code
<profile>
<properties>
<add name="Id" type="Int32"/>
<add name="Name"/>
<add name="Age" type="Int32"/>
</properties>
</profile>
ASP.NET generates a strongly typed class for accessing profile data. Data type for the properties are chosen depending upon the type value. Default type is string if no type is specified. Following code shows setting values and reading back from profile. Collapse | Copy Code
Profile.Name = txtName.Text;
Profile.Id = int.Parse(txtPersonId.Text);
Profile.Age = int.Parse(txtAge.Text);
// to read profile value, use
int age = Profile.Age;
string name = Profile.Name;
int id = Profile.Id;
ASP.NET keeps the profile data in SQLServer database. If no databases are available in the project, it creates a database file in the app_data directory when it is used for the first time. Profiles are implemented using the provider pattern. SQLProfileProvider is the default profile provider. Profiles use windows authentication by default. Profile object can be used with any authentication modes supported by ASP.NET.
Profile is very handy in many situations. However, it has the following drawbacks- It allows to keep only serializable types
- Reading data from profile requires database access which can potentially make your application less performant. If your website uses profiles heavily, you have to cache the results to avoid unncessary database calls.
Hacking ViewState
ViewState is already explained in the previous section [^] . Articles that talk about viewstate always say, it is less secure and not good for keeping secure information. Let us see how a viewstate value can be hacked.
Data kept in Viewstate is serialized using LosFormater, a less known class used for serialization. LosFormatter is helpful to serialize simple types and it produces ASCII string representation of the object graph. The following code shows using LosFormatter. Collapse | Copy Code
[Serializable]
class Customer
{
public Customer(int age,string name) {
this.Age = age;
this.Name = name;
}
public int Age { get; set; }
public string Name { get; set; }
}
string Serialize() {
// Creating customer object
Customer customer = new Customer(25,"Navaneeth");
// formatting
LosFormatter formatter = new LosFormatter();
using (StringWriter output = new StringWriter()) {
formatter.Serialize(output, customer);
return output.ToString();
}
}
The above code serializes the object graph and produces an ASCII string which can be transmitted over HTTP.
The following code shows decrypting viewstate values. Collapse | Copy Code
object HackViewstate(string viewStateValue) {
LosFormatter formatter = new LosFormatter();
return formatter.Deserialize(viewStateValue);
}
The following figure shows the contents of the object which is deserialized
This gives you a clear explanation of why secured data should not be kept on viewstate.
Comments
Post a Comment