Sunteți pe pagina 1din 38

Introduction

Understanding Page lifecycle is very crucial in order to develop ASP.NET applications. Most beginners tend to get confused while dealing with dynamic controls and face problems like losing values, state etc on postbacks. Since HTTP is stateless, the nature of web programming is inherently different from windows application development, and the Page lifecycle is one of the primary building blocks while learning ASP.NET. The sequence of events, especially while working with MasterPages in ASP.NET 2.0, has become slightly more complex and this article is aims to shed some light on these events by explaining the order and importance of each event.

Background
Whenever the user requests a particular .aspx page in an application, a lot of interesting things happen on the web server where the application is hosted. Understanding this sequence of events will help us to program and respond to events properly and also clear any confusion which generally arises due to the stateless nature of web programming.

Basics: The New Compilation Model and the Partial Classes


Each web form in an ASP.NET application derives directly or indirectly from a System.Web.UI.Page class. A web form has two components: a code behind file (WebForm.aspx.cs) which contains the code for the events and other methods related to a Page, and the designer ASPX file, which contains HTML control declarations and events (in the Visual Studio 2005 Web Application project model, we have a designer class named WebForm.aspx.designer.cs). In ASP.NET 2.0, we do not need to define the control variables as well as there event handlers in the code behind, thanks to Partial classes. In ASP.NET 1.x, all this code was auto generated and placed in the code behind file under InitializeComponent() section. But in version 2.0, the runtime will create a partial class dynamically from the ASPX page containing all this info and merge it with the code behind partial class. This will help in making the actual code behind class a lot cleaner and more manageable. Also, this would eliminate the name change related issues which were common in VS 2003 (if we change any control's ID, it had to be changed everywhere and VS used to modify the code many times). All control related events are defined in the ASPX markup code. So having a single place for controls names and event handlers is cleaner and flexible, whereas the previous VS 2003 model was more "brittle".

Real Thing: The Page life cycle


It is very important to know that for each request, the Page class is instantiated everytime from scratch. Which means that any values or whatever state it had previously will get lost unless we use one of the various state maintainance mechanisms provided by ASP.NET like Application, Session, Cache variables or Cookies.

Side Note: View state in ASP.NET 2.0 has changed and now comprises of two parts: Control State and View state. Refer this article for details: http://msdn2.microsoft.com/en-us/library/1whwt1k7(VS.80).aspx Below is the sequence of events which fire up sequentially with explanation on the relative importance with respect to web programming in code behind: Important Note: All events except the Init() and Unload() are fired from outermost to the innermost control. For e.g., a user controls init event would fire before the Page_Init() event of its parent Page class.

1. PreInit()
In this Page level event, all controls created during design time are initialized with their default values. For e.g., if you have a TextBox control with Text property = Hello, it would be set by now. We can create dynamic controls here. This event occurs only for the Page class and UserControls/MasterPages do not have this method to override. Sample code where you can override this method and add your custom code:

protected override void OnPreInit(EventArgs e)

{ //custom code base.OnPreInit(e); } Note that PreInit() is the only event where we can set themes programmatically. Special Case with MasterPages It is important to note that Master Page is treated like a control in the Content Pages. So if a Page has a Master Page associated with it, then the controls on the page will not be initialized and would be null in this stage. Only after the Init() event starts, you can access these controls directly from the page class. Why? The reason being that all controls placed in the Content Page are within a ContentPlaceholder which is a child control of a MasterPage. Now Master Page is merged and treated like a control in the Content Pages. As I mentioned earlier, all events

except the Init() and Unload() are fired from outermost to the innermost control. So PreInit() in the Page is the first event to fire but User Controls or MasterPage (which is itself a Usercontrol) do not have any PreInit event . Therefore in the Page_PreInit() method, neither the MasterPage nor any user control has been initialized and only the controls inside the Page class are set to their default values. Only after the Page_PreInit() event the Init() events of other controls fire up. See the diagram below showing control hierarchy after the Page_Init() event:

2. OnInit()
In this event, we can read the controls properties (set at design time). We cannot read control values changed by the user because that changed value will get loaded after LoadPostData() event fires. But we can access control values from the forms POST data as:

string selectedValue = Request.Form[controlID].ToString();

3. LoadViewState

This will only fire if the Page has posted back (IsPostBack == true). Here the runtime de-serializes the view state data from the hidden form element and loads all controls who have view state enabled.

4. LoadPostBackData
Again, this method will only fire if the Page has posted back. In this event the controls which implement IPostBackDataHandler interface gets loaded by the values from the HTTP POST data. Note that a textbox control does not gets its value from the view state but from the post data in the form in this event. So even if you disable view state for a particular control, it can get its value from the HTTP POST data if it implements IPostBackDataHandler interface. Also, an important point to note is that if we have a DropDownList control and we have dynamically added some items to it, the runtime cannot load those values unless the view state is enabled (even if the control derives from IPostBackDataHandler). The reason being that HTTP Post data has only one value per control, and the entire value collection is not maintained in the PostData but in view state.

5. Page_Load
This is the most popular method and the first one for all beginner developers to put their code. Beginners may also think that this is the first method which fires for a Page class. This can lead to a lot of confusion which makes understanding the Page lifecycle all the more important. Note: If the page has any user control, then it's Load method will fire after the Page class's Load method. The reason as explained earlier is the fact that all method except the Init() are fired from the outermost control to the innermost. So after Page_Load(), load methods of all other controls are fired recursively.

6. Control Event Handlers


These are basically event handlers (like Button1_Click()) which are defined for controls in the ASPX markup. Another source of confusion arises when the developer thinks that an event handler like Button_Click() should fire independently (like in windows apps) as soon as he clicks a Button on the web form, forgetting that Page_Load will fire first before any event handlers.

7. PreRender
This event is again recursively fired for each child controls in the Page. If we want to make any changes to control values, this is the last event we have to peform the same.

8. SaveViewState

Here, the ViewState of the controls gets saved in the form's hidden control.

9. Render
In this method all controls are rendered recursively (i.e. Render method of each control is called).

10. Unload
Here you can have the page and controls perform clean-up operations. This event has no relevance besides clean up operations because the Page has already rendered.

Dynamic Controls
Now we have seen the important events in the Page lifecycle, let's focus on how to create and maintain state of dynamically generated controls. Many times we need to generate controls dynamically for specific business use cases. For example, I was managing a famous hotel reservation website project and one of my team members was facing an issue in handling the Reservation screen. There was a TextBox where the user enters the number of rooms, and based on that value, dynamic usercontrols having a room's detailed info were created at runtime. The developer complained that although he was able to generate user controls as runtime in a for loop, but was unable to save their state. When I looked into the code, I noticed that the code to generate controls was written in a Button's Click event handler. Now as we dicussed above, event handlers like Button_Click() fire much later than LoadViewState() and LoadPostData(), where the control values get loaded from the view state and form's Post data. So unless he recreates the controls in the Page_Init() or Pre_Init() methods (which occur before LoadViewState and LoadPostData), the control values modified by the user won't get reloaded next time. Now, when he put the code in the Page_Init() event, he was unable to get the number of rooms entered by the user in the TextBox (which was a static control). The reason being that in Page_Init(), control values are initilized to their design time default values, and do not reflect the user entered values unless they are loaded from the POST data or the view state, a process which occurs later. So the only way to access the user entered value in the control is to get the value from the form's POST data. Here is the code:

protected override void OnInit(EventArgs e)

{ //get value of the TextBox from HTTP POST data

string selectedValue ; if(Request.Form["txtNoOfRooms"] != null) selectedValue = Request.Form["txtNoOfRooms"].ToString();

//code to create controls dynamically... ...............

base.OnInit(e); }

Note: Thanks to Mike Banavige of ASP.NET forums, I added this section. If you create a dynamic control in the Page_Load event, and add it to a PlaceHolder or Panel (with view state turned on), then this dynamic control will maintain its state even though it was not created in the Page_Init(). Why? The reason is the fact that once a control is added to the control tree of the page,

TrackViewState() method is responsible for tracking the state. This method gets fired
automatically whenever the control is added to the control tree. Due to this reason, any modifications to the control (like adding items etc) should be done *only after* the dynamic control has been added to the control tree of the Page class, else the state would be lost. See the code below:
protected void Page_Load(object sender, EventArgs e) { //create a dynamic dropdown DropDownList d = new DropDownList(); PlaceHolder1.Controls.Add(d); // TrackViewState() gets fired for our dropdown, so state is maintained

if (!IsPostBack) { d.Items.Add("test1"); d.Items.Add("test2"); } }

This will not work: protected void Page_Load(object sender, EventArgs e) { //create a dynamic dropdown DropDownList d = new DropDownList(); if (!IsPostBack) { d.Items.Add("test1"); d.Items.Add("test2"); } PlaceHolder1.Controls.Add(d); //"test1" and "test2" values are lost }

Summary
I have tried to explain relevant events in the Page lifecycle and their importance with some gotchas. I will keep updating this article with more tips and tricks, besides readers are welcome to point out mistakes and suggest corrections and give feedback! An important thing to remember here is that the entire lifecycle is repeated on every request. The Page class gets re-instantiated and after serving the request gets unloaded. Once we are clear with the sequence of the events, we can structure our code well to suit different use case requirements.

Understanding State Management


You need to maintain state-level and page-level information of an ASP.NET Web application because Web pages and ASP.NET Framework use HTTP protocol to communicate between a Web browser and a Web server. HTTP is a stateless protocol. Therefore it cannot automatically indicate whether the sequential requests are coming from the same or different clients. For example, if you need to develop a Web application that provides a personalized page to users after subsequent logon, you need to keep track of user activities when users access the web page. You need to implement session tracking for each user accessing the Web application because HTTP does not enable you to keep track of user activities in a Web Page. In addition, a Web page is fetched again, each time the page is posted to a Web server. This results in loss of information associated with the page and the controls on the page with each round trip. For example, if user selects a checkbox in a Web page, the selection will be lost in the round trip of the page. To overcome this limitation, ASP.NET provides different state management options. State management options can be divided into two categories: I. II. Client-Side management Server-Side management

The following table lists the Client-side and server-side options: CLIENT-SIDE OPTIONS View State property Hidden Fields Cookies Query Strings SERVER-SIDE OPTIONS Application state Session state Database support

Client-Side State Management Options


Client side state management options involve storing information either in a Web page or on a Client computer. Client-side management gives a better performance, as the load on the server is less. Disadvantage of this option is that only limited data can be stored. The clientside options are as follows:

View State
The ViewState property of an ASP.NET web page enables you to retain page and controlspecific values between round trips. Each web page and the controls on the page have the ViewState property that is inherited from the base Control class. ASP.NET framework uses the ViewState property to automatically save the values of the Web page and each control on the Web page prior to rendering the page. During postback of a Web page to itself, one of the tasks performed by ASP.NET is to restore the values in _VIEWSTATE. The view state is implemented with a hidden form field called _VIEWSTATE, which is automatically created in every Web page. When ASP.NET executes a Web page on a Web server, the values stored in the ViewState property of the page and controls on it are

collected and formatted into a single encoded string. The encoded string is then assigned to the Value attribute of the hidden form field _VIEWSTATE and is sent to the client as a part of the Web page. When page is initialized during postback, ASP.NET Framework parses the ViewState string to restore the property information in the page. The view state of a Web page or a control consists of the cumulative property values of the page or the control. To preserve these values across stateless HTTP requests, Web pages and controls in ASP.NET use an instance of the StateBag class. This class is the primary storage mechanism for HTML and server controls. It stores attribute/value pairs associated with HTML and server controls as strings. Therefore, this class is used to manage the view state of an ASP.NET Web page and the controls added to the page after the OnInit method is executed. When you add values to this class, the values are automatically added to the hidden _VIEWSTATE form variable. The syntax to add a value to the StateBag class is as follows: ViewState["any string"] = "some value"; By default, the Viewstate property of both Web page and the controls on the Web page is enabled. Perform the following steps to determine the effect of enabling and disabling the ViewState property in an ASP.NET web application: Create a new Web application. Add a label and a button control to Webform1.aspx. The label control and the button control should have the default name, Label1 and Button1, repectively. Ensure that the EnableViewState property of the Label and Button control are set to true. In addition, ensure that the EnableViewState property to the Page is set to true. Add the following lines of code in the load event of the page and execute the application. if(!IsPostBack) { Label1.Text="Hello"; } When the page is first loaded in the memory of the client computer, the message Hello is assigned to the Text property of the label control. However, if you click the button and reload the page, the label continues to display the message. It is because the Text property of the Label control, Label1 is automatically preserved through the view state property of the control. Now if you set the ViewState property of the label control to false and click the button, the displayed text would not be "hello" but "Label", the default text. Advantages of using ViewState Control The values in view state are stored in a standard HTML format as part of a Web page. Therefore, no Web server resource is required to maintain it. The view state can be easily implemented in the ASP.NET Web page. You just need to set the EnableViewState property of a Web page and server controls.

The values in view state are hashed, compressed and encoded for Unicode implementations. Therefore, values in view state are more secured than values stored in hidden fields. Limitations in using ViewState Storing large values can cause a page to slow down when user display it or post it because view state is stored in the page. View State is stored in a hidden field in a page. Although view state stores data in a hashed format. It can be tampered with. The information in the hidden field can be seen if the page output source is viewed directly, creating a potential security issue.

Hidden Fields

In ASP.NET, you can use the HTML-standard hidden fields in a Web form to store pagespecific information. A hidden field does not render in a Web browser. However, you can set the properties of the hidden field. When a page is submitted to the server, the content of a hidden field is sent in the HTTPForm collection along with the values or other controls. A hidden field stores a single variable in its value property and must be explicitly added to the page. In ASP.NET, the HtmlInputHidden control provides the hidden field functionality. Perform the following steps to implement an HtmlInputHidden control to store page-specific information: Create a new Web application and add a Text box and a button control to the Webform1.aspx. Add a hidden control onto the form form the HTML tab in the toolbox. Right click the hidden control and select the Run As Server Control option form the short-cut menu. Add a label control to the form. Add the following lines of code in the load event of the page: if (Page.IsPostBack) { Label1.Text="Hidden Value: "+ Hidden1.Value; } Add the following line of code in the Click event of the Button control. Hidden1.Value=TextBox1.Text; When the application is executed and you click the button after entering any text in the text box, the entered text id assigned to the Value property of the HtmlInputHidden control. During the round trip of the Web page, the value remains stored in the HtmlInputHidden control. At the time of loading the page, the value stored in Hidden1 is assigned to the Text property of the Label1. Interestingly, when a user clicks the button without specifying the value in the text box, label1 displays only the text Hidden Value without any additional text. This is because the value of the text box is always assigned to the hidden variable. In

addition, when the page loads for the first time, Page.IsPostBack will return false. Therefore, the text Hidden Value will not be displayed. Note: If you use hidden fields, you must submmit your pages to the server using the HTTP POST method instead of requesting the page using the page URL. You cannot take advantage of hidden fields if a page is processed in response to a link or the HTTP GET method. Advantages of using Hidden Form fields The hidden field can store page-specific information without accessing any Web server or Web browser resource. The hidden field can be easily implemented in an ASP.NET web form page. Limitations in using Hidden form fields You can view the information stored in the hidden field by accessing the source of the Web page. Therefore, the values stored in hidden form fields are not very secure. The hidden field does not support more than a single value field to store information. The hidden fields are stored in a page. Therefore, storing large values in hidden form fields can slow down the processing of the page.

Cookies
A cookie is used to store small piece of information on client machine. A cookie contains page-specific information that a Web server sends to a client along with page output. Cookies are used for sending page-specific information because HTTP is a stateless protocol and cannot indicate whether page requests are coming from the same or different clients. You can use cookies to keep track of each individual user who access a Web page across an HTTP connection. Cookies are saved on the Client computer. Cookies can either be temporary or persistent. Temporary cookies, also known as session cookies, exist in the memory space of a browser. When the browser is closed, all session cookies added to the browser are lost. A persistent cookie is saved as a text file in the file system of the client computer. A Web browser can access a cookie from the HttpCookieCollection by using the Request object. If a cookie is accessed using the Request built-in object, the cookie is a read only file. The cookie is stored on the Web browser and not on the Web server. However, if you want to modify a cookie, you need to use the Response built in object. Perform the following steps to create a persistent cookie on a client computer and read the contents of the cookie: Create a new web application and add a button control to the form. Add the following lines of code in the click event of the button control. HttpCookie mycookie=new HttpCookie ("Cookiename","hello"); mycookie.Expires =System.Convert .ToDateTime ("12/12/2007"); Response.Cookies.Add (mycookie);

HttpCookie myvar; myvar=Request.Cookies .Get ("Cookiename"); Response.Write ("Cookie :" + myvar.Name + "<br>"); Response.Write ("Expires : " + myvar.Expires + "<br>"); Now run the application. When you execute the application, only a button is displayed in the Web browser. After you click the button in the web form, a cookie with the name Cookiename is created in the Cookies folder on the client computer. After the cookie is created on the client computer, the details of the cookie, such as the name and the expiry date of the cookie are displayed in the client browser. Advantages of using Cookies A cookie is stored on the client computer and can be read by the server after a request for a page is posted. Therefore, no server resource is involved in maintaining the cookie. A cookie is a text-based data structure that contains key value pairs. Therefore, it is easy to create and manipulate cookies. A cookie can either expire when the browser session ends or exists indefinitely on the client computer, subject to the expiration rules on the client. Limitations in using Cookies Cookies that are stored on client computers have a limited size. Most browsers allow cookies to have up to 4096 bytes in size. Therefore, you cannot store a large amount of data in a cookie. Users can disable cookies to prevent them from being stored on the hard disk of their computer. If a user denies permission for cookies, an ASP.NET Web application cannot store cookies on the client computer. Users can tamper with cookies because cookies are stored on the client computer. Note: The above stated limitations of cookies are overcome in ASP.NET by means of cookie-less property. If you set the cookie-less property to TRUE, ASP.NET will embed the session id, normally stored in the cookie, into the URL that is sent back to the client. When the client makes a request using the URL containing the session id, ASP.NET is able to extract the session id and map the request to the appropriate session data.

Query String
If you need to submit information back to a Web page or another page by using a URL, you can use a query string. The query string is part of the request that appears after the Question mark (?) character in the URL. A query string provides a simple way to pass information from one page to another. For example, in a logon screen, the user name can be passed to the next page in the application by using query strings. Perform the following steps to pass a user name form one page to another page using query string:

1. In an ASP.NET Web application add one TextBox control and specify the ID property as txtusername. 2. Add one label control to indicate the type of value the user needs to enter in the TextBox control. Specify the Text property of the Label control as Enter username. 3. Add another label control to display an error message when the user does not enter any value in the TextBox control. Specify the ID of the label as lblmsg. Delete the default text property of the control. 4. Add a Web form to the project by using the Add Web form option from the project menu. Name it a mywebform. 5. Add a button control to WEbForm1.aspx and set the text property value as Submit. 6. Add the following lines of code in the click event of Button1. if (txtusername.Text == "") { lblmsg.Text = "Enter your name in the text box"; } else { Response.Redirect ("mywebform.aspx?=name="+ System.Web.HttpUtility.UrlEncode (txtusername.text)); //The HttpUtility class provides methods for encoding and decoding URLs when processing Web requests. } In the above code, the Redirect method of the Response object is used to redirect the execution of the Web application form WebForrm1.aspx Web page to mywebform.aspx. The UrlEncode method of the HttUtility class is used to pass the string entered in the txtusrname text box from WebForm1.aspx to mywebform.aspx in an encoded format. Therefore when user enters a username in the textbox control, the value that the user has entered is passed to the mywebform.aspx web page as part of the URL. If a user enters 'Richard' as the username and clicks the Submit button, mywebform.aspx is displayed with a URL as shown in the following figure (notice the shaded blue portion):

To ensure that query string values are available during page processing, you must submit the page by using the HTTP Get method. You can pass two or more name/value pairs using a query string. You can do this by separating each pair with an ampersand (&). In this case the ned of the URL might look like this:

?name=Richard&ID=A8135 Advantages of Query String A query string is contained in the HTTP request for a specific URL. Therefore, no server resource is involved to process a query string. Many Web browsers support passing values in a query string. Therefore, if you create a Web application that passes information from one page to another using a query string. Limitations in using Query String The information in a query string is directly visible to the user in the browser window. Therefore, you need to encrypt this information to ensure that any confidential information is not exposed to strangers. This causes an additional overhead to Web application development. There is a limit to the amount of information that you can pass from one page to another using query strings because most browsers support up to 255 characters of URL.

Server-Side State Management Options


There is a limit to client-side options, there are server-side state management options. By using these options, you can manage application and session-related information. Serverside options store information on the Web server. These options are as follows:

Application State
ASP.NET provides Application state as a means of storing application wide-specific information such as objects and variables. The information in the application state is stored in a key-value pair and is used to maintain data consistency between server round trips and between pages. Application state is created when each browser request is made for a specific URL. After an application state is created, the application-specific information is stored in it. All information stored in the application state is shared among all the pages of the Web application by using the HttpApplicationState class. The HttpApplictaionState class is accessed using the Application property of the HttpContext object. Variables and objects added to the application state are global to an ASP.NET application. Syntax to create a variable and store it in the application state: Application["myvar"] = "Hello"; After the application in which you declared myvar is executed, any page contained in the application can retrieve the value of the myvar. To read the value of the myvar, you need to use the following statement: Response.Write(Application["myvar"]);

You can also add complex objects, such as Collection and Dataset, in application state. For example, you can add a dataset to an application state by using the following statements: DataSet ds = new DataSet(); Application["DataSet"] = ds; To remove the application variable myvar from the application state, you need to use the following statement: Application.Remove(["myvar"]); or to remove all variable for application state wrote the following line of code: Application.RemoveAll(); It is important to note that after an object is added to an application state, it remains in the application state until the application is shut down, the Global.asax file is modified, or the item is explicitly removed from the application state. Since these variables are global to an application, it is important to consider the following issues while storing any value in an application state variable: The memory occupied by variables stored in an application state is not released until the value is either removed or replaced. Therefore, the number of variables and objects in an application state should be minimum. Otherwise, it will be an overhead on the Web server and the server response will be slow. Multiple pages within an application can access values stored in an application state simultaneously. Therefore, explicit synchronization methods need to be used to avoid deadlocks and access violations. The ASP.NET application supports events. Two important events associated with ASP.NET application are discussed in the following table: EVENT DESCRIPTION Application_Start This event is triggered when an application starts. If you want a code to be executed as the application starts, you should add it to the Application_Start event. This event is triggered only when the application starts and is not triggered again until the IIS is stopped, the Global.asax file is modified, or the application is unloaded. Application_End This event is triggered when an application ends

Application State and Synchronization Multiple pages within an ASP.NET Web application can simultaneously access values, stored in an application state. This can result in conflicts and deadlocks. For example you can add a variable named PageCounter in the application state to keep track of the number of times a page has been requested. If two users access a Web page simultaneously, there will be an attempt to update the value of the variable PageCounter simultaneously. This will lead to a

problem. To avoid such situations, the HttpApplicationState class provides two methods, LOCK ( ) and UNLOCK ( ). These methods only allow one thread at a time to access applications state variables and objects. Note: Each browser request for a Web page initiates a new thread on the Web server. Calling the Lock ( ) method on an Application object causes ASP.NET to block attempts by the code running on other worker threads to access anything in an application state. These threads are unblocked only when the thread that called the Lock ( ) method calls the corresponding Unlock ( ) method on the Application object. The following example illustrates the use of the Lock ( ) method and the Unlock ( ) method: Create a new ASP.NET Web application. Add the following lines of code in the Page_Load event of the page: Application.Lock(); if(Application["PageCounter"]==null) Application[ "PageCounter" ]=0; Application[ "PageCounter" ]=(int)Application[ "PageCounter" ]+1; Response.Write (Application[ "PageCounter" ]); Application.UnLock (); In the preceding example, the Lock() method is first called to ensure that the variable PageCounter cannot be simultaneously modified by another thread. Next, the counter is increased by 1 and then the value is displayed in the browser window. At last, the UnLock() methods is called to release the imposed lock on the application state variable PageCounter. You can notice the effect of Lock() and UnLock() methods by clicking the Refresh button on the browser window. Each time you click the Refresh button, the value of the PageCounter is incremented. You can open the same form in another window by copying and pasting the URL, you will note that the value displayed will be not 1 but 1 incremented to the value you left on the previous window. Note: If you do not explicitly call the Unlock( ) method, the .NET Framework automatically removes the lock when the request completes or times out, or when an unhandled error occurs during request execution and causes the request to fail. This automatic unlocking prevents the application from deadlocking. You cannot selectively lock items in an application state, the application state object as a whole is blocked. Advantages of using Application state: Application state is easy to use and is consistent with other .NET Framework classes. Storing information in application state involves maintaining only a single copy of information. Limitations in using Application State:

The data stored in an application state is lost when the Web server containing the application state fails due to a server crash, upgrade, or shutdown. Application state requires server memory and can affect the performance of the server and the scalability of the Web application.

Session State
In ASP.NET, session state is used to store session-specific information for a Website. Unlike application state, the scope of session state is limited to the current browser session. If different users are accessing a Web application, each will have a different session state. In addition, if a user exits and returns later, the user will have a different session state. The session state has a built in support in ASP.NET. The built-in session state feature automatically performs the following actions: Identify and classify requests coming from a browser into a logical application session on the server. Store session-specific data on the server for use across multiple browser requests. Raise session lifetime-related events, such as Session_OnStart and Session_OnEnd, which can be handled using application code. A unique 120-bit SessionID string containing ASCII characters identifies and tracks each active ASP.NET session. The following code can be used to add the variable name myvar in the session state: Session["myvar"] = "HELLO"; To display the value of my var, you can use the following statement: Response.Write(Session["myvar"]); There are three issues that you need to consider while adding variables and objects to a session state: Any variable or object that you add to a session state is available only until the user closes the browser window. The variables and the objects are explicitly removed form session state if the user does not requests a page for more than 20 minutes. Any variable or object added to a session state is related to a particular user. For example, you can store different values for myvar for two different users accessing the Web page and each user can access only the value that is assigned to him. Any object that supports serialization can be added to a session state. Since objects stored in a session state are stored on the server, session objects are not subject to the same size limitations as cookies. Similar to he application state you can remove a variable added to the session state by using the Remove ( ) or RemoveAll ( ) method. Starting and Ending a User Session

A user session starts when a user requests the first page from a Web Site. when the first page is requested, the Web server adds the ASP.NET SessionID cookie to the client computer. The following line enables you to view the value of session ID: Response.Write(Session.SessionID); You can use the Abandon() method of the Session object to explicitly stop a user session, by using the following line of code: Session.Abandon(); You can also modify the Timeout property of the Session object to change the default value of timeout i.e. 20 minutes. To do this open the Web.Config file and scroll to the <sessionState> section and modify the value of the Timeout property as shown in the shaded portion of the figure below:

Handling Session events Session states has the following events that you can capture to manipulate an ASP.NET web application.: Session_Start Session_End You can capture both these events by adding subroutines in the Global.asax file. A practical demonstration in the end of this article would make the usage of these events more clear. You can also use the Session_Start subroutine to automatically redirect users to a particular page when a user session begins.

Since the session data is stored on the Web server, and if the server crashes the session data would be lost. To avoid this, you can store session data in a separate Windows service. For this perform the following steps: Create a new ASP.NET web application. Search the ASP.NET State service and click the Start Service button. Modify the web.Config file to set the sessionstate mode to the value StateServer and specify the location of the State Server in the stateConnectionString. When the State Server is used to store the session state data, the process mode is InProc ( in-process), by default. You can also manage session state out of process by storing data in a Microsoft SQL Server database. The advantage is that you can cluster multiple database servers so that if one fails, another can take over the state management. For this change the mode property of sessionState in Web.config to SQLServer. By default session state is enabled for all pages of your application. Although you can disable it by modifying the page directive as follows: <%@ Page EnableSessionState = "False" %> Advantages of using Session state: It is event driven, therefore you can use session events to perform conditional execution of user-defined tasks. data in session state variables and objects can survive Web server restarts without losing data. Session states can be used in both multi-computer and multi-process configurations. A session state facility can work with browsers that do not support HTTP cookies. Limitations in using Session State: Session state variables are stored in memory until they are either removed or replaced. This can degrade Web server performance.

Practical Demonstration
Here we'll build a simple page that resembles some of the characteristics of a shopping cart. It will show number of items in the cart which may vary according as per every user who's logged on to this page. We will also have a button to remove items from the cart. I have kept it simple, and I am just counting the number of items in the cart, you can do this by assigning the value to the session variable as a DataSet or an Arraylist. For the sake of your learning I will also show you the usage of application state and the session events. You can download example project from this link . This application keeps a track of the number of users who have visited the site. Had you wanted to keep a track of just the active users, you could have added the following line of code to the Session_End event. Application["Counter"] = (int)Application["Counter"]-1;

ASP.NET Caching: Techniques and Best Practices


Contents Steve's Caching Tips Page Level Output Caching Fragment Caching, User Control Output Caching Caching API, Using the Cache Object Summary Of the many features available in ASP.NET, caching support is far and away my favorite, and for good reason. It has the greatest potential impact on an application's performance, out of all the other features in ASP.NET, and it is one of the things that allows ASP.NET developers to accept the additional overhead of building sites using rather heavy controls like DataGrids without fear that performance will suffer too much. In order to see the most benefit from caching in your applications, you should consider ways of implementing caching at all levels of your program.

Steve's Caching Tips Cache Early; Cache Often


Implement caching at every layer of your application. Add caching support to the data layer, the business logic layer, and the UI or output layer. Memory is cheapby implementing caching in an intelligent fashion throughout the application, you can achieve great performance gains.

Caching Hides Many Sins


Caching can be a good way to get "good enough" performance without requiring a lot of time and analysis. Again, memory is cheap, so if you can get the performance you need by caching the output for 30 seconds instead of spending a day or a week trying to optimize your code or database, do the caching solution (assuming 30-second old data is ok) and move on. Caching is one of those things where 20% of the work provides 80% of the benefit, so it should be one of the first things you try to improve performance. Eventually, poor design will probably catch up to you, so of course you should try to design your applications correctly. But if you just need to get good enough performance today, caching can be an excellent, buying you time to refactor your application at a later date when you have the time to do so.

Page Level Output Caching


The simplest form of caching, output caching simply keeps a copy of the HTML that was sent in response to a request in memory. Subsequent requests are then sent the cached output until the cache expires, resulting in potentially very large performance gains (depending on how much effort was required to create the original page outputsending cached output is always very fast and fairly constant).

Implementation

To implement page output caching, simply add an OutputCache directive to the page.

<%@ OutputCache Duration="60" VaryByParam="*" %>


This directive, as with other page directives should appear at the top of the ASPX page, before any output. It supports five attributes (or parameters), two of which are required.

Duration

Required. Time, in seconds, the page should be cached. Must be a positive integer. Specifies where the output should be cached. If specified, must be one of: Any, Client, Downstream, None, Server or ServerAndClient. Required. The names of the variables in the Request, which should result in, separate cache entries. "none" can be used to specify no variation. "*" can be used to create new cache entries for every different set of variables. Separate variables with ";". Varies cache entries based on variations in a specified header. Allows custom variations to be specified in the global.asax (for example, "Browser").

Location

VaryByParam

VaryByHeader VaryByCustom

Most situations can be handled with a combination of the required Duration and VaryByParam options. For instance, if you have a product catalog that allows the user to view pages of the catalog based on a categoryID and a page variable, you could cache it for some period of time (an hour would probably be acceptable unless the products change all the time, so a duration of 3600 seconds) with a VaryByParam of "categoryID;page". This would create separate cache entries for every page of the catalog for each category. Each entry would persist for one hour from its first request. VaryByHeader and VaryByCustom are primarily used to allow customization of the page's look or content based on the client that is accessing them. Perhaps the same URL renders output for both browsers and mobile phone clients, and needs to cache separate versions based on this. Or perhaps the page is optimized for IE but needs to be able to degrade gracefully for Netscape or Opera (instead of just breaking). This last example is common enough that we'll show an example of how to do it: Example: VaryByCustom to support browser customization In order to enable separate cache entries for each browser, VaryByCustom can be set to a value of "browser". This functionality is built into the caching module, and will insert separate cached versions of the page for each browser name and major version.

<%@ OutputCache Duration="60" VaryByParam="None" VaryByCustom="browser"


Fragment Caching, User Control Output Caching
Often, caching an entire page is not feasible, because certain parts of the page are customized for the user.

%>

However, there may be other parts of the page that are common to the entire application. These are perfect candidates for caching, using fragment caching and user controls. Menus and other layout elements, especially ones that are dynamically generated from a data source, should be cached with this technique. If need be, the cached controls can be configured to vary based on the changes to its controls (or other properties) or any of the other variations supported by page level output caching. Hundreds of pages using the same controls can also share the cached entries for those controls, rather than keeping separate cached versions for each page.

Implementation
Fragment caching uses the same syntax as page level output caching, but applied to a user control (.ascx file) instead of to a web form (.aspx file). All of the attributes supported by the OutputCache directive on a web form are also supported for user controls except for the Location attribute. User controls also support an OutputCache attribute called VaryByControl, which will vary the caching of the user control depending on the value of a member of that control (typically a control on the page, such as a DropDownList). If VaryByControl is specified, VaryByParam may be omitted. Finally, by default each user control on each page is cached separately. However, if a user control does not vary between pages in an application and is named the same across all such pages, the Shared="true" parameter can be applied to it, which will cause the cached version(s) of the user control to be used by all pages referencing that control. Examples

<%@ OutputCache Duration="60" VaryByParam="*" %>


This would cache the user control for 60 seconds, and would create a separate cache entry for every variation of querystring and for every page this control is placed on.

<%@ OutputCache Duration="60" VaryByParam="none" VaryByControl="CategoryDropDownList" %>


This would cache the user control for 60 seconds, and would create a separate cache entry for each different value of the CategoryDropDownList control, and for each page this control is placed on.

<%@ OutputCache Duration="60" VaryByParam="none" VaryByCustom="browser" Shared="true %>


Finally, this would cache the user control for 60 seconds, and would create one cache entry for each browser name and major version. The cache entries for each browser would then be shared by all pages referencing this user control (as long as all pages refer to the control with the same ID).

Caching API, Using the Cache Object


Page and user control level output caching can be a quick and easy way to boost performance of your site, but the real flexibility and power of caching in ASP.NET is exposed via the Cache object. Using the Cache object, you can store any serializeable data object, and control how that cache entry expires based on a combination of one or more dependencies. These dependencies can include time elapsed since the item was cached, time elapsed since the item was last accessed, changes to files and/or folders, changes to other cached items, or (with a little work) changes to particular tables in a database.

Storing Data in the Cache


The simplest way to store data in the Cache is simply to assign it, using a key, just like a HashTable or Dictionary object: Cache["key"] = "value"; This will store the item in the cache without any dependencies, so it will not expire unless the cache engine removes it in order to make room for additional cached data. To include specific cache dependencies, the Add() or

Insert() method is used. Each of these has several overloads. The only difference between Add() and Insert() is that Add() returns a reference to the cached object, while has no return value (void in C#, Sub in VB). Examples

Cache.Insert("key", myXMLFileData, new System.Web.Caching.CacheDependency(Server.MapPath("users.xml")));


This would insert xml data from a file into the cache, eliminating the need to read from the file on subsequent requests. The CacheDependency will ensure that when the file changes, the cache will immediately expire, allowing the latest data to be pulled from the file and re-cached. An array of filenames can also be specified if the cached data depends on several files.

Cache.Insert("dependentkey", myDependentData, new System.Web.Caching.CacheDependency(new string[] {}, new string[] {"key"}));


This example would insert a second piece of data that depended on the existence of the first piece (with a key value of "key"). If no key existed in the cache called "key", or if the item associated with that key expires or is updated, then the cache entry for "dependentkey" would expire.

Cache.Insert("key", myTimeSensitiveData, null, DateTime.Now.AddMinutes(1), TimeSpan.Zero);


Absolute Expiration: This example will cache the time sensitive data for one minute, at which point the cache will expire. Note that absolute expiration and sliding expiration (below) cannot be used together.

Cache.Insert("key", myFrequentlyAccessedData, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1));


Sliding Expiration: This example will cache some frequently used data. The data will remain in the cache until one minute passes without anything referencing it. Note that sliding expiration and absolute expiration cannot be used together.

More Options
In addition to the dependencies described above, we can also specify the priority of the item (from low to high to NotRemovable, defined in the System.Web.Caching.CacheItemPriority enumeration) and a CacheItemRemovedCallback function to call when the item expires from the cache. Most of the time, the default priority will sufficelet the caching engine do what it's good at and handle the cache's memory management. The CacheItemRemovedCallback option allows for some interesting possibilities, but in practice it too is rarely used. However, to demonstrate the technique, I'll provide an example of its usage: CacheItemRemovedCallback example

System.Web.Caching.CacheItemRemovedCallback callback = new System.Web.Caching.CacheItemRemovedCallback (OnRemove); Cache.Insert("key",myFile,null, System.Web.Caching.Cache.NoAbsoluteExpiration,

TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Default, callback); . . . public static void OnRemove(string key, object cacheItem, System.Web.Caching.CacheItemRemovedReason reason) { AppendLog("The cached value with key '" + key + "' was removed from the cache. reason.ToString()); }
This will log the reason for the expiration of data from the cache using whatever logic is defined in the

Reason: " +

AppendLog() method (not included heresee Writing Entries to Event Logs. Logging items as they are
removed from the cache and noting the reason for removal might allow you to determine if you are using the cache effectively, or if you might need to increase the memory on your server. Note that the callback is a static (Shared in VB) method, which is recommended since otherwise an instance of the class holding the callback function will be kept in memory to support the callback (which isn't necessary for a static/Shared method). One potential use for this feature would be to refresh cached data in the background so that users never need to wait for the data to be populated, but the data is kept relatively fresh. Unfortunately in practice, this doesn't work very well with the current version of the caching API, because the callback doesn't fire or complete execution prior to the cached item being removed from the cache. Thus, a user will frequently make a request that will try to access the cached value, find that it is null, and be forced to wait for it to repopulate. In a future version of ASP.NET, I would like to see an additional callback, which might be called CachedItemExpiredButNotRemovedCallback, which if defined must complete execution before the cached item is removed.

Cached Data Reference Pattern


Whenever an attempt is made to access data from the cache, it should be with the assumption that the data might not be there any more. Thus, the following pattern should be universally applied to your access of cached data. In this case, we're going to assume the object that has been cached is a DataTable.

public DataTable GetCustomers(bool BypassCache) { string cacheKey = "CustomersDataTable"; object cacheItem = Cache[cacheKey] as DataTable; if((BypassCache) || (cacheItem == null)) { cacheItem = GetCustomersFromDataSource(); Cache.Insert(cacheKey, cacheItem, null, DateTime.Now.AddSeconds(GetCacheSecondsFromConfig(cacheKey), TimeSpan.Zero); }

return (DataTable)cacheItem; }
There are several points I'd like to make about this pattern: Values, like cacheKey, cacheItem and the cache duration, are defined once and only once. The cache can be bypassed as neededfor example, after registering a new customer and redirecting to a list of customers, it would probably be best to bypass the cache and repopulate it with the latest data, which would include the newly inserted customer.

Cache is only accessed once. This has performance benefits and ensures that NullReferenceExceptions don't occur because the item was present the first time it was checked but had expired before the second check.

The pattern uses strong type checking. The "as" operator in C# will attempt to cast an object to a type and will simply return null if it fails or if the object is null. The duration is stored in a configuration file. All cache dependencies, whether file-based, time-based, or otherwise, should ideally be stored in a configuration file so that changes can be made and performance measured easily. I also recommend that a default cache duration be specified, and that the GetCacheSecondsFromConfig() method uses the default if no duration is specified for the cacheKey being used.

The associated code sample is a helper class that will handle all of the above but allow cached data to be accessed with one or two lines of code. Download CacheDemos.msi.

Summary
Caching can provide huge performance benefits to applications, and should therefore be considered when an application is being designed as well as when it is being performance tested. I have yet to encounter an application that could not benefit from caching in some capacity, though certainly some applications are better suited than others. A solid understanding of the caching options available in ASP.NET is an important skill for any ASP.NET developer to master.

How to: Add Items to the Cache


You can access items in the application cache using the Cache object. You can add an item to the application cache using the Cache object's Insert method. The method adds an item to the cache and has several overloads that enable you to add the item with different options for setting dependencies, expiration, and removal notification. If you use the Insert method to add an item to the cache and an item with the same name already exists, the existing item in the cache is replaced. You can also add items to the cache using the Add method. This method enables you to set all the same options as the Insert method; however, Add method returns the object you added to the cache. Additionally, if you use the Add method and an item with the same name already exists in the cache, the method will not replace the item and will not raise an exception. The procedures in this topic illustrate the following ways to add items to the application cache:

Adding an item to the cache by directly setting the item via key and value. Adding items to the cache using the Insert method.

Adding an item to the cache and adding a dependency so that the item is removed from the cache when the dependency changes. You can set dependencies based on other cache items, on files, and on multiple objects.

Adding an item to the cache with expiration policies. In addition to being able to set an item's dependency, you can set the item to expire after a period of time (a sliding expiration) or at a specific time (an absolute expiration). You can define either an absolute expiration or a sliding expiration, but not both.

Adding an item to the cache and defining the relative priority of the cached item. Relative priorities help the .NET Framework determine what cache items to remove; lower priority items are removed from the cache before higher priority items.

Adding an item by calling the Add method.

In addition to the dependencies shown here, you can create a dependency on a SQL Server table or based on a custom dependency. For more information, see ASP.NET Caching Overview and Caching in ASP.NET with the SqlCacheDependency Class. You can also have the application cache notify your application when the item is removed from the cache, using the CacheItemRemovedCallback delegate. For a full example, see How to: Notify an Application When an Item Is Removed from the Cache.

To add an item to the cache by directly setting the item via key and value
Add items to the cache as you would add items to a dictionary by specifying the item's key and value. The following code example adds an item named C#

CacheItem1 to the Cache object:

Cache["CacheItem1"] = "Cached Item 1";


Visual Basic

Cache("CacheItem1") = "Cached Item 1"


To add items to the cache by using the Insert method
Call the Insert method, passing the key and value of the item to add. The following code example adds a string under the name C#

CacheItem2:

Cache.Insert("CacheItem2", "Cached Item 2");


Visual Basic

Cache.Insert("CacheItem2", "Cached Item 2")


To add an item to the cache by specifying a dependency
Call the Insert method, passing it an instance of the CacheDependency object

The following code example adds an item named the cache named C#

CacheItem3 that is dependent on another item in

CacheItem2:

string[] dependencies = { "CacheItem2" }; Cache.Insert("CacheItem3", "Cached Item 3", new System.Web.Caching.CacheDependency(null, dependencies));
Visual Basic

Dim dependencies As String() = {"CacheItem2"} Cache.Insert("CacheItem3", "Cached Item 3", _ New System.Web.Caching.CacheDependency( _ Nothing, dependencies)) The following code example shows an item named CacheItem4 added to the cache and having a file
dependency set on the file named XMLFile.xml: C#

Cache.Insert("CacheItem4", "Cached Item 4", new System.Web.Caching.CacheDependency( Server.MapPath("XMLFile.xml")));


Visual Basic

Cache.Insert("CacheItem4", "Cached Item 4", _ New System.Web.Caching.CacheDependency( _ Server.MapPath("XMLFile.xml")))


The following code example shows how to create multiple dependencies. It adds a key dependency on another item in the cache named C#

CacheItem1 and a file dependency on the file named XMLFile.xml.

System.Web.Caching.CacheDependency dep1 = new System.Web.Caching.CacheDependency(Server.MapPath("XMLFile.xml")); string[] keyDependencies2 = { "CacheItem1" }; System.Web.Caching.CacheDependency dep2 = new System.Web.Caching.CacheDependency(null, keyDependencies2); System.Web.Caching.AggregateCacheDependency aggDep = new System.Web.Caching.AggregateCacheDependency(); aggDep.Add(dep1); aggDep.Add(dep2); Cache.Insert("CacheItem5", "Cached Item 5", aggDep);
Visual Basic

Dim dep1 As CacheDependency = _ New CacheDependency(Server.MapPath("XMLFile.xml")) Dim keyDependencies2 As String() = {"CacheItem1"} Dim dep2 As CacheDependency = _ New System.Web.Caching.CacheDependency(Nothing, _ keyDependencies2) Dim aggDep As AggregateCacheDependency = _ New System.Web.Caching.AggregateCacheDependency() aggDep.Add(dep1) aggDep.Add(dep2) Cache.Insert("CacheItem5", "Cached Item 5", aggDep)

The add an item to the cache with expiration policies


Call the Insert method, passing it an absolute or sliding expiration time. The following code example adds an item to the cache with an absolute expiration of one minute: C#

Cache.Insert("CacheItem6", "Cached Item 6", null, DateTime.Now.AddMinutes(1d), System.Web.Caching.Cache.NoSlidingExpiration);


Visual Basic

Cache.Insert("CacheItem6", "Cached Item 6", _ Nothing, DateTime.Now.AddMinutes(1.0), _ TimeSpan.Zero)


The following code example adds an item to the cache with a sliding expiration time of 10 minutes: C#

Cache.Insert("CacheItem7", "Cached Item 7", null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0));
Visual Basic

Cache.Insert("CacheItem7", "Cached Item 7", _ Nothing, System.Web.Caching.Cache.NoAbsoluteExpiration, _ New TimeSpan(0, 10, 0))
To add an item to the Cache with priority settings
Call the Insert method, specifying a value from the CacheItemPriority enumeration. The following code example adds an item to the cache with a priority value of High: C#

Cache.Insert("CacheItem8", "Cached Item 8", null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, null);


Visual Basic

Cache.Insert("CacheItem8", "Cached Item 8", _ Nothing, System.Web.Caching.Cache.NoAbsoluteExpiration, _ System.Web.Caching.Cache.NoSlidingExpiration, _ System.Web.Caching.CacheItemPriority.High, _ Nothing)


To add an item to the cache using the Add method
Call the Add method, which returns an object representing the item. The following code example adds an item to the cache named the variable

CacheItem9 and sets the value of

CachedItem9 to be the item that was added.

C#

string CachedItem9 = (string)Cache.Add("CacheItem9", "Cached Item 9", null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Default, null);
Visual Basic

Dim CachedItem9 As String = CStr(Cache.Add("CacheItem9", _ "Cached Item 9", Nothing, _ System.Web.Caching.Cache.NoAbsoluteExpiration, _ System.Web.Caching.Cache.NoSlidingExpiration, _ System.Web.Caching.CacheItemPriority.Default, _ Nothing))

Overview of user controls vs. custom controls On This Page


Introduction Overview What are user controls? How to create a user control How to use a user control in a Web Forms page How to create an instance of a user control programmatically in the code behind file of a Web Forms page How a user control is processed What are custom controls? How to choose the base class for your custom control How to create and use a simple custom control that extends from System.Web.UI.Control using Visual Studio How to expose properties on the custom control How to apply design-time attributes on the custom control Why design-time attributes are needed What are the basic differences between user controls and custom controls? Advanced topics State management Example using view state in a custom control Example using the previous control on a Web Forms page Rendering Rendering methods of the System.Web.UI.Control class How a control is rendered on the page Rendering methods of the System.Web.UI.WebControl class How the rendering of the WebControl class takes place Conclusion

Overview
In this month's column, I'll discuss the following topics:

What are user controls? What are custom controls? What are the basic differences between user controls and custom controls?

I'll also introduce a few of the advanced topics that concern custom controls, such as state management and the rendering of custom controls.

What are user controls?


User controls are custom, reusable controls, and they use the same techniques that are employed by HTML and Web server controls. They offer an easy way to partition and reuse common user interfaces across ASP.NET Web applications. They use the same Web Forms programming model on which a Web Forms page works. For more details about the Web Forms programming model, visit the following Microsoft Developer Network (MSDN) Web sites: Introduction to Web Forms pages http://msdn2.microsoft.com/en-us/library/65tcbxz3(vs.71).aspx Web Forms code model http://msdn2.microsoft.com/en-us/library/015103yb(vs.71).aspx

How to create a user control


The syntax you use to create a user control is similar to the syntax you use to create a Web Forms page (.aspx). The only difference is that a user control does not include the <html>, <body>, and <form> elements since a Web Forms page hosts the user control. To create a user control, follow these steps: 1. Open a text or HTML editor, and create a server-side code block exposing all the properties, methods, and events.

<script language="C#" runat="server"> public void button1_Click(object sender, EventArgs e) { label1.Text = "Hello World!!!"; } </script>
2. Create a user interface for the user control.

<asp:Label id="label1" runat="server"/> <br><br> <asp:button id="button1" text="Hit" OnClick="button1_Click" runat="server" />
How to use a user control in a Web Forms page
1. Create a new Web Forms page (.aspx) in Microsoft Visual Studio .NET 2002, Microsoft Visual Studio .NET 2003, Microsoft Visual Studio 2005, or any text editor. 2. Declare the @ Register directive. For example, use the following code.

<%@ Register TagPrefix="UC" TagName="TestControl" Src="test.ascx" %>


Note Assume that the user control and the Web Forms page are in the same location. 3. To use the user control in the Web Forms page, use the following code after the @ Register directive.

<html> <body> <form runat="server"> <UC:TestControl id="Test1" runat="server"/> </form> </body> </html>

How to create an instance of a user control programmatically in the code behind file of a Web Forms page
The previous example instantiated a user control declaratively in a Web Forms page using the @ Register directive. However, you can instantiate a user control dynamically and add it to the page. Here are the steps for doing that: 1. Create a new Web Forms page in Visual Studio. 2. Navigate to the code behind file generated for this Web Forms page. 3. In the Page_Load event of the Page class, write the following code.

// Load the control by calling LoadControl on the page class. Control c1 = LoadControl("test.ascx"); // Add the loaded control in the page controls collection. Page.Controls.Add(c1);
Note You can add a user control dynamically at certain events of the page life cycle. For more information, visit the following Web sites: Adding controls to a Web Forms page programmatically http://msdn2.microsoft.com/en-us/library/kyt0fzt1(vs.71).aspx Control execution lifecycle http://msdn2.microsoft.com/en-us/library/aa719775(vs.71).aspx Dynamic Web controls, postbacks, and view state, by Scott Mitchell http://aspnet.4guysfromrolla.com/articles/092904-1.aspx

How a user control is processed


When a page with a user control is requested, the following occurs:

The page parser parses the .ascx file specified in the Src attribute in the @ Register directive and
generates a class that derives from the System.Web.UI.UserControl class.

The parser then dynamically compiles the class into an assembly. If you are using Visual Studio, then at design time only, Visual Studio creates a code behind file for the
user control, and the file is precompiled by the designer itself.

Finally, the class for the user control, which is generated through the process of dynamic code
generation and compilation, includes the code for the code behind file (.ascx.cs) as well as the code written inside the .ascx file.

What are custom controls?


Custom controls are compiled code components that execute on the server, expose the object model, and render markup text, such as HTML or XML, as a normal Web Form or user control does.

How to choose the base class for your custom control


To write a custom control, you should directly or indirectly derive the new class from the System.Web.UI.Control class or from the System.Web.UI.WebControls.WebControl class:

You should derive from System.Web.UI.Control if you want the control to render nonvisual

elements. For example, <meta> and <head> are examples of nonvisual rendering.

You should derive from System.Web.UI.WebControls.WebControl if you want the control to render
HTML that generates a visual interface on the client computer. If you want to change the functionality of existing controls, such as a button or label, you can directly derive the new class with these existing classes and can change their default behavior. In brief, the Control class provides the basic functionality by which you can place it in the control tree for a Page class. The WebControl class adds the functionality to the base Control class for displaying visual content on the client computer. For example, you can use the WebControl class to control the look and styles through properties like font, color, and height.

How to create and use a simple custom control that extends from System.Web.UI.Control using Visual Studio
1. 2. 3. 4. 5. Start Visual Studio. Create a class library project, and give it a name, for example, CustomServerControlsLib. Add a source file to the project, for example, SimpleServerControl.cs. Include the reference of the System.Web namespace in the references section. Check whether the following namespaces are included in the SimpleServerControl.cs file.

System System.Collections System.ComponentModel System.Data System.Web System.Web.SessionState System.Web.UI System.Web.UI.WebControls


6. 7. Inherit the SimpleServerControls class with the Control base class.

public class SimpleServerControl : Control


Override the Render method to write the output to the output stream.

protected override void Render(HtmlTextWriter writer) { writer.Write("Hello World from custom control"); }
Note The HtmlTextWriter class has the functionality of writing HTML to a text stream. The Write method of the HtmlTextWriter class outputs the specified text to the HTTP response stream and is the same as the Response.Write method. 8. Compile the class library project. It will generate the DLL output. 9. Open an existing or create a new ASP.NET Web application project. 10. Add a Web Forms page where the custom control can be used. 11. Add a reference to the class library in the references section of the ASP.NET project. 12. Register the custom control on the Web Forms page.

<%@ Register TagPrefix="CC " Namespace=" CustomServerControlsLib " Assembly="CustomServerControlsLib " %>
13. To instantiate or use the custom control on the Web Forms page, add the following line of code in the <form> tags.

<form id="Form1" method="post" runat="server"> <CC:SimpleServerControl id="ctlSimpleControl" runat="server">

</CC:SimpleServerControl > </form>


Note In this code, SimpleServerControl is the control class name inside the class library. 14. Run the Web Forms page, and you will see the output from the custom control. If you are not using Visual Studio, you need to perform the following steps: 1. Open any text editor. 2. Create a file named SimpleServerControl.cs, and write the code as given in steps 1 through 14. 3. In the PATH variable, add the following path: c:\windows (winnt)\Microsoft.Net\Framework\v1.1.4322 4. Start a command prompt, and go to the location where SimpleServerControl.cs is present. 5. Run the following command: csc /t:library /out: CustomServerControlsLib. SimpleServerControl.dll /r:System.dll /r:System.Web.dll SimpleServerControl.cs For more information about the C# compiler (csc.exe), visit the following MSDN Web site: http://msdn2.microsoft.com/en-us/library/1700bbwd(vs.71).aspx 6. To run the custom control on the Web Forms page, do the following: a. Create a directory under the wwwroot folder. b. Start Microsoft Internet Information Services (IIS) Manager, and mark the new directory as the virtual root directory. c. Create a Bin folder under the new directory. d. Copy the custom control DLL into the Bin folder. e. Place the sample Web Forms page that you created in the previous steps inside the new directory. f. Run the sample page from IIS Manager.

Now that you have built a simple custom control, let's look at how to expose properties and apply designtime attributes on that custom control.

How to expose properties on the custom control


I will build on the previous example and introduce one or more properties that can be configured while using the custom control on the Web Forms page. The following example shows how to define a property that will display a message from the control a certain number of times, as specified in the property of the control: 1. Open SimpleServerControl.cs in a text editor. 2. Add a property in the SimpleServerControl class.

public class SimpleServerControl : Control

{ private int noOfTimes; public int NoOfTimes { get { return this.noOfTimes;} set { this.noOfTimes = value; } } protected override void Render (HtmlTextWriter writer) { for (int i=0; i< NoOfTimes; i++) { write.Write("Hello World.."+"<BR>"); } } }
3. Compile the custom control. 4. To use the custom control on the Web Forms page, add the new property to the control declaration.

<CC:SimpleServerControl id="ctlSimpleControl" NoOfTimes="5" runat="server"></CC:SimpleServerControl>


5. Running the page will display the message "Hello world" from the custom control as many times as specified in the property of the control.

How to apply design-time attributes on the custom control


Why design-time attributes are needed

The custom control that you built in the previous example works as expected. However, if you want to use that control in Visual Studio, you may want the NoOfTimes property to be automatically highlighted in the Properties window whenever the custom control is selected at design time. To make this happen, you need to provide the metadata information to Visual Studio, which you can do by using a feature in Visual Studio called attributes. Attributes can define a class, a method, a property, or a field. When Visual Studio loads the custom control's class, it checks for any attributes defined at the class, method, property, or field level and changes the behavior of the custom control at design time accordingly. To find more information about attributes, visit the following MSDN Web site: http://msdn2.microsoft.com/en-us/library/Aa288059(VS.71).aspx Let's build a sample that uses commonly used attributes: 1. Open SimpleServerControl.cs in a text editor. 2. Introduce some basic attributes at the class level, for example, DefaultProperty, ToolboxData, and TagPrefixAttrbute. We'll build our sample on these three attributes.

[ // Specify the default property for the control. DefaultProperty("DefaultProperty"), // Specify the tag that is written to the aspx page when the // control is dragged from the Toolbox to the Design view. // However this tag is optional since the designer automatically // generates the default tag if it is not specified. ToolboxData("<{0}:ControlWithAttributes runat=\"server\">" + "</{0}:ControlWithAttributes>") ] public class ControlWithAttributes : Control { private string _defaultProperty; public string DefaultProperty { get { return "This is a default property value"; } set { this._defaultProperty = value; } } protected override void

Render(HtmlTextWriter writer) { writer.Write("Default Property --> <B>" + DefaultProperty + "</B>"); } }


3. There is one more tag called TagPrefixAttrbute. It is an assembly-level attribute that provides a prefix to a tag when you drag the control from the Toolbox to the designer. Otherwise, the designer generates a prefix such as "cc1" by default. TagPrefixAttrbute is not directly applied to the control class. To apply TagPrefixAttrbute, open AssemblyInfo.cs, include the following line of code, and then rebuild the project.

[assembly:TagPrefix("ServerControlsLib ", "MyControl")]


Note If you want to build the source using the command line, you need to create the AssemblyInfo.cs file, place the file in the directory that contains all the source files, and run the following command to build the control: > csc /t:library /out: ServerControlsLib.dll /r:System.dll /r :System.Web.dll *.cs

What are the basic differences between user controls and custom controls?
Now that you have a basic idea of what user controls and custom controls are and how to create them, let's take a quick look at the differences between the two.

Factors

User control

Custom control Designed so that it can be used by more than one application Deployed either in the application's Bin directory or in the global assembly cache Distributed easily and without problems associated with redundancy and maintenance

Deployment Designed for single-application scenarios Deployed in the source form (.ascx) along with the source code of the application If the same control needs to be used in more than one application, it introduces redundancy and maintenance problems Creation Creation is similar to the way Web Forms pages are created; well-suited for rapid application development (RAD) A much better choice when you need static content within a fixed layout, for example, when you make headers and footers Writing doesn't require much application designing because they are authored at design time and mostly contain static data

Writing involves lots of code because there is no designer support

Content

More suited for when an application requires dynamic content to be displayed; can be reused across an application, for example, for a data bound table control with dynamic rows Writing from scratch requires a good understanding of the control's life cycle and the order in which events execute, which is normally taken care of in user controls

Design

Advanced topics
Next, let's take a look at a few of the advanced features that you may use while developing custom controls.

State management
Web applications are built on HTTP, which is stateless. A page and its child controls are created on every request and are disposed of after the request is over. To maintain state in classic ASP programming, you use session and application objects. But for that, you need to do lots of coding. To avoid this, ASP.NET provides a mechanism known as view state for maintaining state across several requests. To learn more about state management and view state, visit the following MSDN Web sites:

Introduction to Web Forms state management http://msdn2.microsoft.com/en-us/library/75x4ha6s(vs.71).aspx The ASP.NET view state http://msdn.microsoft.com/msdnmag/issues/03/02/cuttingedge/default.aspx Saving Web Forms page values using view state http://msdn2.microsoft.com/en-us/library/4yfdwycw(vs.71).aspx
Example using view state in a custom control

ViewStateExample.cs

using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using System.Text; namespace ServerControlLib { /// <summary> /// When a page framework reloads this control after postback, it /// will restore the values which are in view state. /// This control can easily perform state management without /// implementing our own logic for maintaining the state. /// </summary> public class ViewStateExample : WebControl { // Text to be displayed in Text box control. private string _text; /* * This property needs to be populated before every * postback in order to * retain its value. */ public string Text { get { return (_text == null) ? "_text property is empty" : _text; } set { _text = value; } } /* * This property needs to be filled once and should be * available on the successive postbacks. */ public string TextInViewState { get { object o = ViewState["TextInViewState"]; return (o == null) ? "View state is empty" : (string)o; } set { ViewState["TextInViewState"] = value; } } /* * Over-ridden method on WebControl base class which * displays both of the property values * i.e. one stored in view state and other which is not * saved in view state. */ protected override void RenderContents(HtmlTextWriter writer) { writer.Write("Text Without View State = "); writer.Write(Text); writer.Write("<hr><br>"); writer.Write("Text In View State = "); writer.Write(TextInViewState); } } }
Example using the previous control on a Web Forms page

ViewStateExampleDemo.aspx

<%@ Page Language="C#" %> <%@ Register TagPrefix="CC" Namespace="ServerControlLib" Assembly = "ServerControlLib" %> <html> <head> <script runat="server"> void button1_Click(object sender, EventArgs e) { Control1.Text = textbox1.Text; Control1.TextInViewState = textbox2.Text; } </script> </head> <body> <form runat="server" ID="Form1"> <br> Property Value Without View State: <asp:TextBox id="textbox1" runat="server" /> <br> Property Value with View State: <asp:TextBox id="textbox2" runat="server" /> <asp:Button text="Cause Postback" onClick="button1_Click" id="button1" Runat="server" /> Output from the ViewStateExample Control : <CC:ViewStateExample id="Control1" runat="server"/> </form> </body> </html>
Rendering
In this section, I'll briefly describe what methods you should override when you derive a custom control from either the Control class or the WebControl class.
Rendering methods of the System.Web.UI.Control class

For information about the rendering methods of the System.Web.UI.Control class, visit the following MSDN Web sites:

Control.Render method http://msdn2.microsoft.com/en-us/library/system.web.ui.control.render(vs.71).aspx Control.RenderControl method http://msdn2.microsoft.com/en-us/library/system.web.ui.control.rendercontrol(vs.71).aspx Control.RenderChildren method http://msdn2.microsoft.com/en-us/library/system.web.ui.control.renderchildren(vs.71).aspx


How a control is rendered on the page

Every page has a control tree that represents a collection of all the child controls for that page. To render the control tree, an object of the HtmlTextWriter class is created that contains the HTML to be rendered on the client computer. That object is passed to the RenderControl method. In turn, the RenderControl method invokes the Render method. Then, the Render method calls the RenderChildren method on each child control, making a recursive loop until the end of the collection is reached. This process is best explained by the following example code.

public void RenderControl(HtmlTextWriter writer) { // Render method on that control will only be called if its visible property is true. if (Visible) { Render(writer); } } protected virtual void Render(HtmlTextWriter writer) { RenderChildren(writer); } protected virtual void RenderChildren(HtmlTextWriter writer) { foreach (Control c in Controls) { c.RenderControl(writer); } }
Rendering methods of the System.Web.UI.WebControl class

For information about the rendering methods of the System.Web.UI.WebControl class, visit the following MSDN Web sites: WebControl.RenderBeginTag method http://msdn2.microsoft.com/enus/library/system.web.ui.webcontrols.webcontrol.renderbegintag(vs.71).aspx WebControl.RenderContents method http://msdn2.microsoft.com/enus/library/system.web.ui.webcontrols.webcontrol.rendercontents(vs.71).aspx WebControl.RenderEndTag method http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderendtag(vs.71).aspx
How the rendering of the WebControl class takes place

The following code example shows the Render method for the custom control.

protected override void Render(HtmlTextWriter writer) { RenderBeginTag(writer); RenderContents(writer); RenderEndTag(writer); }


You don't need to override the Render method for the WebControl class. If you want to render contents within the WebControl class, you need to override the RenderContents method. However, if you still want to override the Render method, you must override the RenderBeginTag method as well as the RenderEndTag method in the specific order that is shown in the previous code example.

Conclusion
That's all for now on user controls and custom controls in ASP.NET 1.0 and ASP.NET 1.1. I hope that this column helps you understand the basic differences between them and the various approaches you can take to develop them. Thank you for your time. We expect to write more about the advanced topics for custom controls, such as state management, control styles, composite controls, and design-time support for custom controls, in the near future. For more information about controls, visit the following MSDN Web sites: ASP.NET server control development basics http://msdn2.microsoft.com/en-us/library/aa310918(vs.71).aspx An extensive examination of user controls

http://msdn2.microsoft.com/en-us/library/ms972975.aspx Building templated custom ASP.NET server controls http://msdn2.microsoft.com/en-us/library/Aa478964.aspx Events in ASP.NET server controls http://msdn2.microsoft.com/en-us/library/aa720049(vs.71).aspx Composite control vs. user control http://msdn2.microsoft.com/en-us/library/aa719735(vs.71).aspx Developing ASP.NET server controls http://msdn2.microsoft.com/en-us/library/aa719973(vs.71).aspx Developing custom controls: Key concepts http://msdn2.microsoft.com/en-us/library/aa720226(vs.71).aspx Adding design-time support to ASP.NET controls http://msdn2.microsoft.com/en-us/library/Aa478960.aspx

S-ar putea să vă placă și