State Management in ASP.NET
Richard Harris
DevOps, Online & Mobile at TD Bank Group #devops #agile #cloud #java #js #csharp
Overview
State management is the task of retaining information between web requests. In this article, you’ll see how you can use ASP.NET’s state management features to store information using one of the different storage options, including view state, session state, cookies, and application state. You’ll also consider how to transfer information from page to page using cross-page posting and the query string. Each state management choice has a different lifetime, scope, performance overhead, and level of support.
Contents
- State Management Options Compared
- ViewState
- Cross-Page Posting
- The Query String
- Cookies
- Session State
- Application State
- References
State Management Options Compared
View State
- Allowed Data Types: All serializable .NET data types.
- Storage Location: A hidden field in the current web page.
- Lifetime: Retained permanently for postbacks to a single page.
- Scope: Limited to the current page.
- Security: Tamper proof by default but easy to read. You can enforce encryption by using ViewStateEncryptionMode property of the page directive.
- Performance Implications: Slow if a large amount of information is stored, but will not affect server performance.
- Typical Use: Page-specific settings.
Query String
- Allowed Data Types: A limited amount of string data.
- Storage Location: The browser's URL string.
- Lifetime: Lost when the user enters a new URL or closes the browser. However, this can be stored in a bookmark.
- Scope: Limited to the target page.
- Security: Clearly visible and easy for the user to modify.
- Performance Implications: None, because the amount of data is trivial.
- Typical Use: Sending an ID (i.e. product) from a list (i.e. catalog) page to a details page.
Cookies
- Allowed Data Types: String data.
- Storage Location: The client's computer (in memory or a small text file, depending on its lifetime settings).
- Lifetime: Set by the programmer. Can be used in multiple pages and can persist between visits.
- Scope: The whole ASP.NET application.
- Security: Insecure, and can be modified by the user.
- Performance Implications: None, because the amount of data is trivial.
- Typical Use: Personalization preferences for a website.
Session State
- Allowed Data Types: All .NET data types for the default in-process storage mode. All serializable .NET data types if you use an out-of-process storage model.
- Storage Location: Server memory, state service, or SQL Server, depending on the mode you choose.
- Lifetime: Times out after a predefined period (usually 20 minutes, but can be altered globally or programmatically).
- Scope: The whole ASP.NET application.
- Security: Very secure, because data is never transmitted to the client.
- Performance Implications: Slow when storing a large amount of information, especially if there are many users at once, because each user will have their own copy of session data.
- Typical Use: Storing items in a shopping basket.
Application State
- Allowed Data Types: All .NET data types.
- Storage Location: Server memory.
- Lifetime: The lifetime of the applciation (typically, until the server is rebooted).
- Scope: The whole ASP.NET application (application data is global to all users).
- Security: Very secure, because data is never transmitted to the client.
- Performance Implications: Slow when storing a large amount of information, because this data will never time out and be removed.
- Typical Use: Storing any type of global data.
ViewState
- One of the most common ways to store information is in view state. View state uses a hidden field that ASP.NET automatically inserts in the final, rendered HTML of a web page. It’s a perfect place to store information that’s used for multiple postbacks in a single web page.
- Web controls store most of their property values in view state, provided you haven’t switched ViewState off (for example, by setting the EnableViewState property of the control or the page to false).
- View state information is stored in a single jumbled string that looks like this:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="dDw3NDg2NTI5MDg7Oz4=" />
- Because this value isn't formatted as clear text, many ASP.NET programmers assume that their view state data is encrypted. It isn't. It's a Base64 string.
- You have probably noticed that any information you set in a member variable for an ASP.NET page is automatically abandoned when the page processing is finished and the page is sent to the client. Interestingly, you can work around this limitation using view state.
- The basic principle is to save all member variables to view state when the Page.PreRender event occurs and retrieve them when the Page.Load event occurs. Remember, the Load event happens every time the page is created. In the case of a postback, the Load event occurs first, followed by any other control events.
- Retrieve:
int counter = 1; if (ViewState["Counter"] != null) counter = (int)ViewState["Counter"] + 1;
- Store:
ViewState["Counter"] = 1;
- One technique commonly used is to save state / persist data in Page.PreRender, and restores the data in Page.Load:
// Page_PreRender (save): ViewState["contents"] = contents; // persist variable // Page_Load: if(this.IsPostBack) contents = (string)ViewState["contents"]; // retrieve / restore
- If your view state contains some information you want to keep secret, you can enable view state encryption. You can turn on encryption for an individual page using the ViewStateEncryptionMode property of the Page directive: <%@Page ViewStateEncryptionMode="Always" %>. Or you can set the same attribute in a configuration file to configure view state encryption for all the pages in your website:
<configuration> <system.web> <pages viewStateEncryptionMode="Always" /> ... </system.web> </configuration>
- You can store your own objects in view state just as easily as you store numeric and string types. However, to store an item in view state, ASP.NET must be able to convert it into a stream of bytes so that it can be added to the hidden input field in the page. This process is called serialization.
- If a class declaration is preceded with [Serializable] attribute, instance of the class can be placed in view state.
- If your objects aren’t serializable (and by default they’re not), you’ll receive an error message when you attempt to place them in view state.
- To make your objects serializable, you need to add a Serializable attribute before your class declaration.
[Serializable] public class Customer { ... }
Cross-Page Posting
- One of the most significant limitations with view state is that it's tightly bound to a specific page.
- Two basic techniques to transfer information between pages: cross-page posting and the query string.
- The infrastructure that supports cross-page postbacks is a property named PostBackUrl, which is defined by the IButtonControl interface and turns up in button controls such as ImageButton, LinkButton, and Button. To use cross-posting, you simply set PostBackUrl to the name of another web form. When the user clicks the button, the page will be posted to that new URL with the values from all the input controls on the current page.
<asp:Button runat="server" ID="cmdPost" PostBackUrl="CrossPage2.aspx" Text="Cross-Page Postback" />
- To get more specific details, such as control values, you need to cast the PreviousPage reference to the appropriate page class.
CrossPage1 prevPage = PreviousPage as CrossPage1; if(prevPage != null) // (Read some information from the previous page)
- Notice that in a target page (i.e. CrossPage2.aspx), you can access the Title property of the previous page (i.e. CrossPage1.aspx) without performing any casting. That's because the Title property is defined as part of the base System.Web.UI.Page class.
- Once you’ve cast the previous page to the appropriate page type, you still won’t be able to directly access the control objects it contains. That’s because the controls on the web page are not publicly accessible to other classes. You can work around this by using properties.
- Define specific, limited methods or properties that extract just the information you need. For example, you might decide to add a FullName property that retrieves just the text from two text boxes.
public partial class CrossPage1 : System.Web.UI.Page { public string FullName { get { return txtFirstName.Text + " " + txtLastName.Text; } } }
- And then to display the information from CrossPage1.aspx in CrossPage2.aspx we'd have:
if (PreviousPage != null) { CrossPage1 prevPage = PreviousPage as CrossPage1; if (prevPage != null) { lblInfo.Text += "You typed in this: " + prevPage.FullName + "<br />"; } }
The Query String
- Another common approach is to pass information using a query string in the URL. This approach is commonly found in search engines. For example, if you perform a search on the Google website, you’ll be redirected to a new URL that incorporates your search parameters. Here’s an example: https://www.google.ca/search?q=organic+gardening
- The query string is the portion of the URL after the question mark. In this case, it defines a single variable named q, which contains the string organic+gardening.
- The advantage of the query string is that it’s lightweight and doesn’t exert any kind of burden on the server. However, it also has several limitations:
- Information is limited to simple strings, which must contain URL-legal characters.
- Information is clearly visible to the user and to anyone else who cares to eavesdrop on the Internet.
- The enterprising user might decide to modify the query string and supply new values, which your program won’t expect and can’t protect against.
- Many browsers impose a limit on the length of a URL (usually from 1KB to 2KB). For that reason, you can’t place a large amount of information in the query string and still be assured of compatibility with most browsers.
- The query string is particularly well suited in database applications where you present the user with a list of items that correspond to records in a database, such as products. The user can then select an item and be forwarded to another page with detailed information about the selected item. One easy way to implement this design is to have the first page send the item ID to the second page. The second page then looks that item up in the database and displays the detailed information. You’ll notice this technique in e-commerce sites such as Amazon.
- To store information in the query string, you need to place it there (into the URL) yourself. Here’s an example that uses this approach with the Response.Redirect() method:
// Go to newpage.aspx. Submit a single query string argument // named recordID, and set to 10. Response.Redirect("newpage.aspx?recordID=10");
- You can send multiple parameters as long as they’re separated with an ampersand (&):
// Go to newpage.aspx. Submit two query string arguments: // recordID (10) and mode (full). Response.Redirect("newpage.aspx?recordID=10&mode=full");
- The receiving page has an easier time working with the query string. It can receive the values from the QueryString dictionary collection exposed by the built-in Request object:
string ID = Request.QueryString["recordID"];
- Note that information is always retrieved as a string, which can then be converted to another simple data type. Values in the QueryString collection are indexed by the variable name. If you attempt to retrieve a value that isn’t present in the query string, you’ll get a null reference.
- Note: Unlike view state, information passed through the query string is clearly visible and unencrypted. Don’t use the query string for information that needs to be hidden or made tamperproof.
URL Encoding
- One potential problem with the query string is that some characters aren’t allowed in a URL. In fact, the list of characters that are allowed in a URL is much shorter than the list of allowed characters in an HTML document. All characters must be alphanumeric or one of a small set of special characters (including $-_.+!*'(),).
- Some characters have special meaning. For example, the ampersand (&) is used to separate multiple query string parameters, the plus sign (+) is an alternate way to represent a space, and the number sign (#) is used to point to a specific bookmark in a web page. If you try to send query string values that include any of these characters, you’ll lose some of your data.
- To avoid potential problems, it’s a good idea to perform URL encoding on text values before you place them in the query string. With URL encoding, special characters are replaced by escaped character sequences starting with the percent sign (%), followed by a two-digit hexadecimal representation. For example, the & character becomes %26. The only exception is the space character, which can be represented as the character sequence %20 or the + sign.
- To perform URL encoding, you use the UrlEncode() and UrlDecode() methods of the HttpServerUtility class. A HttpServerUtility object is made available to your code in every web form through the Page.Server property. The following code uses the UrlEncode() method to rewrite the previous example, so it works with product names that contain special characters:
string url = "QueryStringRecipient.aspx?"; url += "Item=" + Server.UrlEncode(lstItems.SelectedItem.Text) Response.Redirect(url);
- You can use the UrlDecode() method to return a URL-encoded string to its initial value. However, you don’t need to take this step with the query string. That’s because ASP.NET automatically decodes your values when you access them through the Request.QueryString collection. (Many people still make the mistake of decoding the query string values a second time. Usually, decoding already decoded data won’t cause a problem. The only exception is if you have a value that includes the + sign. In this case, using UrlDecode() will convert the + sign to a space, which isn’t what you want.)
Cookies
- Cookies are small files that are created in the web browser’s memory (if they’re temporary) or on the client’s hard drive (if they’re permanent). One advantage of cookies is that they work transparently without the user being aware that information needs to be stored. They also can be easily used by any page in your application and even be retained between visits, which allows for truly long-term storage.
- They suffer from some of the same drawbacks that affect query strings - namely, they're limited to simple string information, and they’re easily accessible and readable if the user finds and opens the corresponding file. These factors make them a poor choice for complex or private information or large amounts of data.
- Some users disable cookies on their browsers, which will cause problems for web applications that require them. Also, users might manually delete the cookie files stored on their hard drives. But for the most part, cookies are widely adopted and used extensively on many websites.
- Cookies are available by using the System.Net namespace.
- You retrieve cookies from the Request object, and you set cookies using the Response object.
- The only way to remove a cookie is replacing it with a cookie that has an expiration date that has already passed.
- Retrieve:
HttpCookie cookie = Request.Cookies["Preferences"]; if (cookie == null) lblWelcome.Text = "<b>Unknown Customer</b>"; else { lblWelcome.Text = "<b>Cookie Found.</b><br><br>"; lblWelcome.Text += "Welcome, " + cookie["Name"]; }
- Store:
HttpCookie cookie = Request.Cookies["Preferences"]; if (cookie == null) { cookie = new HttpCookie("Preferences"); } cookie["Name"] = txtName.Text; cookie.Expires = DateTime.Now.AddYears(1); Response.Cookies.Add(cookie);
- Remove:
HttpCookie cookie = new HttpCookie("Preferences"); cookie.Expires = DateTime.Now.AddDays(-1); Response.Cookies.Add(cookie);
Session State
- Session state management is one of ASP.NET’s premier features. It allows you to store any type of data in memory on the server. The information is protected, because it is never transmitted to the client, and it’s uniquely bound to a specific session. Every client that accesses the application has a different session and a distinct collection of information. Session state is ideal for storing information such as the items in the current user’s shopping basket when the user browses from one page to another.
- When the client presents the session ID, ASP.NET looks up the corresponding session, retrieves the objects you stored previously, and places them into a special collection so they can be accessed in your code. This process takes place automatically.
- For this system to work, the client must present the appropriate session ID with each request. You can accomplish this in two ways:
- Using cookies: In this case, the session ID is transmitted in a special cookie (named ASP.NET_SessionId), which ASP.NET creates automatically when the session collection is used. This is the default.
- Using modified URLs: In this case, the session ID is transmitted in a specially modified (or munged) URL. This allows you to create applications that use session state with clients that don’t support cookies.
- You can interact with session state using the System.Web.SessionState.HttpSessionState class, which is provided in an ASP.NET web page as the built-in Session object. The syntax for adding items to the collection and retrieving them is basically the same as for adding items to a page’s view state.
- Before you attempt to use the dsInfo object seen above, you'll need to check that it actually exists (that it isn't a null reference). If the dsInfo is null, it's up to you to regenerate it.
- It’s also a good practice to add a few session-friendly features in your application. For example, you could add a logout button to the page that automatically cancels a session using the Session.Abandon() method. This way, the user will be encouraged to terminate the session rather than just close the browser window, and the server memory will be reclaimed faster.
- Common HttpSessionState Members: Count, IsCookieless, IsNewSession, Keys, Mode, SessionID, Timeout, Abandon(), Clear()
- Reference: MSDN > HttpSessionStateClass
- Store:
Session["Furniture1"] = piece1;
- Retrieve:
Furniture piece = (Furniture)Session[key];
- You might store a DataSet in session memory like this:
Session["InfoDataSet"] = dsInfo;
- You can then retrieve with an appropriate conversion operation:
dsInfo = (DataSet)Sessions["InfoDataSet"];
Session state is global to your entire application for the current user. However, session state can be lost in several ways:
- If the user closes and restarts the browser.
- If the user accesses the same page through a different browser window, although the session will still exist if a web page is accessed through the original browser window. Browsers differ on how they handle this situation.
- If the session times out due to inactivity. More information about session timeout can be found in the configuration section.
- If your web page code ends the session by calling the Session.Abandon() method.
Session State Configuration
- You configure session state through the web.config file for your current application. The configuration file allows you to set advanced options such as the timeout and the session state mode.
- The following listing shows the most important options that you can set for the <sessionState> element. Keep in mind that you won’t use all of these details at the same time. Some settings apply only to certain session state modes, as you’ll see shortly.
<?xml version="1.0" ?> <configuration> <system.web> <!-- Other settings omitted. --> <sessionState cookieless="UseCookies" cookieName="ASP.NET_SessionId" regenerateExpiredSessionId="false" timeout="20" mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" stateNetworkTimeout="10" sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI" sqlCommandTimeout="30" allowCustomSqlDatabase="false" customProvider="" compressionEnabled="false" /> </system.web> </configuration>
- The session state mode settings allow you to configure ASP.NET to use different session state services. Two notable values include Off and SqlServer.
- The Off Mode setting disables session state management for every page in the application. This can provide a slight performance improvement for websites that are not using session state.
- SQLServer setting instructs ASP.NET to use an SQL Server database to store session information, as identified by the sqlConnectionString attribute. This is the most resilient state store but also the slowest by far. To use this method of state management, you’ll need to have a server with SQL Server installed.
Application State
- Application state allows you to store global objects that can be accessed by any client. Application state is based on the System.Web.HttpApplicationState class, which is provided in all web pages through the built-in Application object.
- Application state is similar to session state. It supports the same type of objects, retains information on the server, and uses the same dictionary-based syntax.
- A common example with application state is a global counter that tracks how many times an operation has been performed by all the web application’s clients.
- For example, you could create a global.asax event handler that tracks how many sessions have been created or how many requests have been received into the application.
- Or you can use similar logic in the Page.Load event handler to track how many times a given page has been requested by various clients. Here’s an example of the latter:
protected void Page_Load(Object sender, EventArgs e) { // Retrieve the current counter value. int count = 0; if (Application["HitCounterForOrderPage"] != null) { count = (int)Application["HitCounterForOrderPage"]; } // Increment the counter. count++; // Store the current counter value. Application["HitCounterForOrderPage"] = count; lblCounter.Text = count.ToString(); }
- Once again, application state items are stored as objects, so you need to cast them when you retrieve them from the collection.
- Items in application state never time out. They last until the application or server is restarted or the application domain refreshes itself (because of automatic process recycling settings or an update to one of the pages or components in the application).
- Application state isn’t often used, because it’s generally inefficient and inaccurate (particularly in times of heavy traffic when client requests are being made at the same time).
- Use the Lock() and Unlock() methods to explicitly allow only one client to access the Application state collection at a time:
protected void Page_Load(Object sender, EventArgs e) { // Acquire exclusive access. Application.Lock(); int count = 0; if (Application["HitCounterForOrderPage"] != null) { count = (int)Application["HitCounterForOrderPage"]; } count++; lblCounter.Text = count.ToString(); Application["HitCounterForOrderPage"] = count; // Release exclusive access. Application.Unlock(); }
- Unfortunately, all other clients requesting the page will be stalled until the Application collection is released. This can drastically reduce performance.
Generally, frequently modified values are poor candidates for application state. In fact, application state is rarely used in the .NET world because its two most common uses have been replaced by easier, more efficient methods:
- web.config - In the past, application state was used to store application-wide constants, such as a database connection string. This type of constant can be stored in the web.config file, which is generally more flexible because you can change it easily without needing to hunt through web page code or recompile your application.
- Cache - Application state can also be used to store frequently used information that is time-consuming to create, such as a full product catalog that requires a database lookup. However, using application state to store this kind of information raises all sorts of problems about how to check whether the data is valid and how to replace it when needed. It can also hamper performance if the product catalog is too large. A similar but much more sensible approach—storing frequently used information in the ASP.NET cache. Many uses of application state can be replaced more efficiently with caching.
References
- ASP.NET Page Life Cycle Overview - MSDN
- ASP.NET Session State Overview - MSDN
- HttpSessionState Class - MSDN
- A Beginner's Tutorial on ASP.NET State Management - Code Project
- Exploring Session in ASP.NET - Code Project
- State Management in ASP.NET - Introduction - CodeProject
- Understanding Session Management Techniques in ASP.NET - CodeProject
- List all active ASP.NET Sessions - Stack Overflow
Software developer
2 天前superb and very detailed
Security Architect @ TCS | VJTI’ 93 | GECA’ 91
5 年Nice.