Page and Controls Framework
Page and Controls Framework
NET is a unified Web development model that includes the services necessary for you to
build enterprise-class Web applications with a minimum of coding. ASP.NET is part of the .NET
Framework, and when coding ASP.NET applications you have access to classes in the .NET
Framework. You can code your applications in any language compatible with the common
language runtime (CLR), including Microsoft Visual Basic, C#, JScript .NET, and J#. These
languages enable you to develop ASP.NET applications that benefit from the common language
runtime, type safety, inheritance, and so on.
ASP.NET includes:
The ASP.NET page and controls framework is a programming framework that runs on a Web
server to dynamically produce and render ASP.NET Web pages. ASP.NET Web pages can be
requested from any browser or client device, and ASP.NET renders markup (such as HTML) to
the requesting browser. As a rule, you can use the same page for multiple browsers, because
ASP.NET renders the appropriate markup for the browser making the request. However, you can
design your ASP.NET Web page to target a specific browser, such as Microsoft Internet
Explorer 6, and take advantage of the features of that browser. ASP.NET supports mobile
controls for Web-enabled devices such as cellular phones, handheld computers, and personal
digital assistants (PDAs).
ASP.NET Web pages are completely object-oriented. Within ASP.NET Web pages you can
work with HTML elements using properties, methods, and events. The ASP.NET page
framework removes the implementation details of the separation of client and server inherent in
Web-based applications by presenting a unified model for responding to client events in code
that runs at the server. The framework also automatically maintains the state of a page and the
controls on that page during the page processing life cycle.
The ASP.NET page and controls framework also enables you to encapsulate common UI
functionality in easy-to-use, reusable controls. Controls are written once, can be used in many
pages, and are integrated into the ASP.NET Web page that they are placed in during rendering.
The ASP.NET page and controls framework also provides features to control the overall look
and feel of your Web site via themes and skins. You can define themes and skins and then apply
them at a page level or at a control level.
In addition to themes, you can define master pages that you use to create a consistent layout for
the pages in your application. A single master page defines the layout and standard behavior that
you want for all the pages (or a group of pages) in your application. You can then create
individual content pages that contain the page-specific content you want to display. When users
request the content pages, they merge with the master page to produce output that combines the
layout of the master page with the content from the content page.
ASP.NET Compiler
All ASP.NET code is compiled, which enables strong typing, performance optimizations, and
early binding, among other benefits. Once the code has been compiled, the common language
runtime further compiles ASP.NET code to native code, providing improved performance.
ASP.NET includes a compiler that will compile all your application components including pages
and controls into an assembly that the ASP.NET hosting environment can then use to service
user requests.
Security Infrastructure
ASP.NET always runs with a particular Windows identity so you can secure your application
using Windows capabilities such as NTFS Access Control Lists (ACLs), database permissions,
and so on.
State-Management Facilities
ASP.NET provides intrinsic state management functionality that enables you to store information
between page requests, such as customer information or the contents of a shopping cart. You can
save and manage application-specific, session-specific, page-specific, user-specific, and
developer-defined information. This information can be independent of any controls on the page.
ASP.NET offers distributed state facilities, which enable you to manage state information across
multiple instances of the same application on one computer or on several computers.
ASP.NET Configuration
ASP.NET applications use a configuration system that enables you to define configuration
settings for your Web server, for a Web site, or for individual applications. You can make
configuration settings at the time your ASP.NET applications are deployed and can add or revise
configuration settings at any time with minimal impact on operational Web applications and
servers. ASP.NET configuration settings are stored in XML-based files. Because these XML
files are ASCII text files, it is simple to make configuration changes to your Web applications.
You can extend the configuration scheme to suit your requirements.
ASP.NET includes features that enable you to monitor health and performance of your ASP.NET
application. ASP.NET health monitoring enables reporting of key events that provide
information about the health of an application and about error conditions. These events show a
combination of diagnostics and monitoring characteristics and offer a high degree of flexibility
in terms of what is logged and how it is logged.
Debugging Support
In addition, the ASP.NET page framework provides a trace mode that enables you to insert
instrumentation messages into your ASP.NET Web pages
ASP.NET supports XML Web services. An XML Web service is a component containing
business functionality that enables applications to exchange information across firewalls using
standards like HTTP and XML messaging. XML Web services are not tied to a particular
component technology or object-calling convention. As a result, programs written in any
language, using any component model, and running on any operating system can access XML
Web services.
ASP.NET includes an extensible hosting environment that controls the life cycle of an
application from when a user first accesses a resource (such as a page) in the application to the
point at which the application is shut down. While ASP.NET relies on a Web server (IIS) as an
application host, ASP.NET provides much of the hosting functionality itself. The architecture of
ASP.NET enables you to respond to application events and create custom HTTP handlers and
HTTP modules.
ASP.NET includes enhanced support for creating designers for Web server controls for use with
a visual design tool such as Visual Studio. Designers enable you to build a design-time user
interface for a control, so that developers can configure your control's properties and content in
the visual design tool.
Based on Microsoft ASP.NET technology, in which code that runs on the server
dynamically generates Web page output to the browser or client device.
Compatible with any browser or mobile device. An ASP.NET Web page automatically
renders the correct browser-compliant HTML for features such as styles, layout, and so
on. Alternatively, you can design your ASP.NET Web pages to run on a specific browser
such as Microsoft Internet Explorer 6 and take advantage of browser-specific features.
Compatible with any language supported by the .NET common language runtime,
including Microsoft Visual Basic, Microsoft Visual C#, Microsoft J#, and
Microsoft JScript .NET.
Built on the Microsoft .NET Framework. This provides all the benefits of the framework,
including a managed environment, type safety, and inheritance.
Flexible because you can add user-created and third party controls to them.
In ASP.NET Web pages, user interface programming is divided into two pieces: the visual
component and the logic. If you have worked with tools like Visual Basic and Visual C++ in the
past, you will recognize this division between the visible portion of a page and the code behind
the page that interacts with it.
The visual element consists of a file containing static markup such as HTML or ASP.NET server
controls or both. The ASP.NET Web page works as a container for the static text and controls
you want to display.
The logic for the ASP.NET Web page consists of code that you create to interact with the page.
The code can reside either in a script block in the page or in a separate class. If the code is in a
separate class file, this file is referred to as the code-behind file. The code in the code-behind file
can be written in Visual Basic, Visual C#, Visual J#, or JScript .NET.
ASP.NET Web pages are compiled into a dynamic-link library (.dll) file. The first time a user
browses to the .aspx page, ASP.NET automatically generates a .NET class file that represents the
page and then compiles it. The .dll file runs on the server and dynamically produces the HTML
output for your page.
Web application programming presents challenges that do not typically arise when programming
traditional client-based applications. Among the challenges are:
Implementing a rich Web user interface It can be difficult and tedious to design and
implement a user interface using basic HTML facilities, especially if the page has a
complex layout, a large amount of dynamic content, and full-featured user-interactive
objects.
Separation of client and server In a Web application, the client (browser) and server are
different programs often running on different computers (and even on different operating
systems). Consequently, the two halves of the application share very little information;
they can communicate, but typically exchange only small chunks of simple information.
Stateless execution When a Web server receives a request for a page, it finds the page,
processes it, sends it to the browser, and then discards all page information. If the user
requests the same page again, the server repeats the entire sequence, reprocessing the
page from scratch. Put another way, a server has no memory of pages that it has
processed—pages are stateless. Therefore, if an application needs to maintain information
about a page, its stateless nature can become a problem.
Unknown client capabilities In many cases, Web applications are accessible to many
users using different browsers. Browsers have different capabilities, making it difficult to
create an application that will run equally well on all of them.
Complications with data access Reading from and writing to a data source in traditional
Web applications can be complicated and resource-intensive.
Complications with scalability In many cases Web applications designed with existing
methods fail to meet scalability goals due to the lack of compatibility between the various
components of the application. This is often a common failure point for applications
under a heavy growth cycle.
Meeting these challenges for Web applications can require substantial time and effort. ASP.NET
Web pages and the ASP.NET page framework address these challenges in the following ways:
The following table describes the stages of the ASP.NET application life cycle.
Stage Description
The life cycle of an ASP.NET application starts with a request sent by a
browser to the Web server (for ASP.NET applications, typically IIS).
ASP.NET is an ISAPI extension under the Web server. When a Web server
receives a request, it examines the file-name extension of the requested file,
determines which ISAPI extension should handle the request, and then passes
the request to the appropriate ISAPI extension. ASP.NET handles file name
extensions that have been mapped to it, such as .aspx, .ascx, .ashx, and .asmx.
Note:
If a file name extension has not been mapped to ASP.NET, ASP.NET will not receive
User requests an the request. This is important to understand for applications that use ASP.NET
application authentication. For example, because .htm files are typically not mapped to ASP.NET,
resource from the
ASP.NET will not perform authentication or authorization checks on requests for .htm
Web server.
files. Therefore, even if a file contains only static content, if you want ASP.NET to
check authentication, create the file using a file name extension mapped to ASP.NET,
such as .aspx.
Note:
If you create a custom handler to service a particular file name extension, you must
map the extension to ASP.NET in IIS and also register the handler in your application's
Web.config file. For more information, see HTTP Handlers and HTTP Modules
Overview.
ASP.NET When ASP.NET receives the first request for any resource in an application, a
receives the first class named ApplicationManager creates an application domain. Application
request for the domains provide isolation between applications for global variables and allow
application. each application to be unloaded separately. Within an application domain, an
instance of the class named HostingEnvironment is created, which provides
access to information about the application such as the name of the folder
where the application is stored.
The following diagram illustrates this relationship:
Note:
The request is The following events are executed by the HttpApplication class while the
processed by the request is processed. The events are of particular interest to developers who
HttpApplication want to extend the HttpApplication class.
pipeline.
1. Validate the request, which examines the information sent by the
browser and determines whether it contains potentially malicious
markup. For more information, see ValidateRequest and Script Exploits
Overview.
2. Perform URL mapping, if any URLs have been configured in the
UrlMappingsSection section of the Web.config file.
10. Based on the file name extension of the requested resource (mapped in
the application's configuration file), select a class that implements
IHttpHandler to process the request. If the request is for an object
(page) derived from the Page class and the page needs to be compiled,
ASP.NET compiles the page before creating an instance of it.
During the application life cycle, the application raises events that you can handle and calls
particular methods that you can override. To handle application events or methods, you can
create a file named Global.asax in the root directory of your application.
If you create a Global.asax file, ASP.NET compiles it into a class derived from the
HttpApplication class, and then uses the derived class to represent the application.
An instance of HttpApplication processes only one request at a time. This simplifies application
event handling because you do not need to lock non-static members in the application class when
you access them. This also allows you to store request-specific data in non-static members of the
application class. For example, you can define a property in the Global.asax file and assign it a
request-specific value.
ASP.NET automatically binds application events to handlers in the Global.asax file using the
naming convention Application_event, such as Application_BeginRequest. This is similar to the
way that ASP.NET page methods are automatically bound to events, such as the page's
Page_Load event. For details, see ASP.NET Page Life Cycle Overview.
The Application_Start and Application_End methods are special methods that do not represent
HttpApplication events. ASP.NET calls them once for the lifetime of the application domain, not
for each HttpApplication instance.
The following table lists some of the events and methods that are used during the application life
cycle. There are many more events than those listed, but they are not commonly used.
You should set only static data during application start. Do not set any instance
data because it will be available only to the first instance of the
HttpApplication class that is created.
Raised at the appropriate time in the application life cycle, as listed in the
application life cycle table earlier in this topic.
When the first request is made to an application, ASP.NET compiles application items in a
specific order. The first items to be compiled are referred to as the top-level items. After the first
request, the top-level items are recompiled only if a dependency changes. The following table
describes the order in which ASP.NET top-level items are compiled.
Item Description
The application's global resources are compiled and a resource
App_GlobalResources assembly is built. Any assemblies in the application's Bin folder
are linked to the resource assembly.
Proxy types for Web services are created and compiled. The
App_WebResources resulting Web references assembly is linked to the resource
assembly if it exists.
Profile properties defined in If profile properties are defined in the application's Web.config
the Web.config file file, an assembly is generated that contains a profile object.
Source code files are built and one or more assemblies are
App_Code created. All code assemblies and the profile assembly are linked
to the resources and Web references assemblies if any.
The application object is compiled and linked to all of the
Global.asax
previously generated assemblies.
After the application's top level items have been compiled, ASP.NET compiles folders, pages,
and other items as needed. The following table describes the order in which ASP.NET folders
and items are compiled.
Item Description
If the folder containing the requested item contains an
App_LocalResources folder, the contents of the local
App_LocalResources
resources folder are compiled and linked to the global
resources assembly.
Individual Web pages (.aspx files), user
controls (.ascx files), HTTP handlers Compiled as needed and linked to the local resources
(.ashx files), and HTTP modules (.asmx assembly and the top-level assemblies.
files)
Skin files for individual themes, master pages, and
Themes, master pages, other source files other source code files referenced by pages are
compiled when the referencing page is compiled.
Compiled assemblies are cached on the server and reused on subsequent requests and are
preserved across application restarts as long as the source code is unchanged.
Because the application is compiled on the first request, the initial request to an application can
take significantly longer than subsequent requests. You can precompile your application to
reduce the time required for the first request.
Application Restarts
Modifying the source code of your Web application will cause ASP.NET to recompile source
files into assemblies. When you modify the top-level items in your application, all other
assemblies in the application that reference the top-level assemblies are recompiled as well.
In addition, modifying, adding, or deleting certain types of files within the application's known
folders will cause the application to restart. The following actions will cause an application
restart:
When an application restart is required, ASP.NET will serve all pending requests from the
existing application domain and the old assemblies before restarting the application domain and
loading the new assemblies.
HTTP Modules
The ASP.NET application life cycle is extensible through IHttpModule classes. ASP.NET
includes several classes that implement IHttpModule, such as the SessionStateModule class. You
can also create your own classes that implement IHttpModule.
If you add modules to your application, the modules themselves can raise events. The application
can subscribe to in these events in the Global.asax file by using the convention
modulename_eventname. For example, to handle the Authenticate event raised by a
FormsAuthenticationModule object, you can create a handler named
FormsAuthentication_Authenticate.
The SessionStateModule class is enabled by default in ASP.NET. All session events are
automatically wired up as Session_event, such as Session_Start. The Start event is raised each
time a new session is created.
If you develop custom controls, you must be familiar with the page life cycle in order to
correctly initialize controls, populate control properties with view-state data, and run control
behavior code. The life cycle of a control is based on the page life cycle, and the page raises
many of the events that you need to handle in a custom control.
Life-cycle Events
In general terms, the page goes through the stages outlined in the following table. In addition to
the page life-cycle stages, there are application stages that occur before and after a request but
are not specific to a page.
Some parts of the life cycle occur only when a page is processed as a postback. For postbacks,
the page life cycle is the same during a partial-page postback (as when you use an UpdatePanel
control) as it is during a full-page postback.
Stage Description
The page request occurs before the page life cycle begins. When the page is
requested by a user, ASP.NET determines whether the page needs to be parsed
Page request
and compiled (therefore beginning the life of a page), or whether a cached
version of the page can be sent in response without running the page.
In the start stage, page properties such as Request and Response are set. At this
Start stage, the page also determines whether the request is a postback or a new request
and sets the IsPostBack property. The page also sets the UICulture property.
During page initialization, controls on the page are available and each control's
UniqueID property is set. A master page and themes are also applied to the page
Initialization if applicable. If the current request is a postback, the postback data has not yet
been loaded and control property values have not been restored to the values from
view state.
During load, if the current request is a postback, control properties are loaded
Load
with information recovered from view state and control state.
If the request is a postback, control event handlers are called. After that, the
Postback event
Validate method of all validator controls is called, which sets the IsValid property
handling
of individual validator controls and of the page.
Rendering Before rendering, view state is saved for the page and all controls. During the
rendering stage, the page calls the Render method for each control, providing a
text writer that writes its output to the OutputStream object of the page's
Response property.
The Unload event is raised after the page has been fully rendered, sent to the
Unload client, and is ready to be discarded. At this point, page properties such as
Response and Request are unloaded and cleanup is performed.
Life-Cycle Events
Within each stage of the life cycle of a page, the page raises events that you can handle to run
your own code. For control events, you bind the event handler to the event, either declaratively
using attributes such as onclick, or in code.
Pages also support automatic event wire-up, meaning that ASP.NET looks for methods with
particular names and automatically runs those methods when certain events are raised. If the
AutoEventWireup attribute of the @ Page directive is set to true, page events are automatically
bound to methods that use the naming convention of Page_event, such as Page_Load and
Page_Init.
The following table lists the page life-cycle events that you will use most frequently. There are
more events than those listed; however, they are not used for most page-processing scenarios.
Instead, they are primarily used by server controls on the ASP.NET Web page to initialize and
render themselves. If you want to write custom ASP.NET server controls, you need to
understand more about these events.
Note:
If the request is a postback, the values of the controls have not yet been
restored from view state. If you set a control property at this stage, its
value might be overwritten in the next event.
Raised after all controls have been initialized and any skin settings have
been applied. The Init event of individual controls occurs before the Init
Init event of the page.
Use this event to make changes to view state that you want to make sure are
persisted after the next postback.
Raised after the page loads view state for itself and all controls, and after it
PreLoad
processes postback data that is included with the Request instance.
The Page object calls the OnLoad method on the Page object, and then
recursively does the same for each child control until the page and all
controls are loaded. The Load event of individual controls occurs after the
Load Load event of the page.
Use the OnLoad event method to set properties in controls and to establish
database connections.
Use these events to handle specific control events, such as a Button control's
Click event or a TextBox control's TextChanged event.
Note:
Control events
In a postback request, if the page contains validator controls, check the IsValid
property of the Page and of individual validation controls before performing any
processing.
Use the event to make final changes to the contents of the page or its
controls before the rendering stage begins.
Raised after each data bound control whose DataSourceID property is set
PreRenderComplete calls its DataBind method. For more information, see Data Binding Events
for Data-Bound Controls later in this topic.
Raised after view state and control state have been saved for the page and
SaveStateComplete for all controls. Any changes to the page or controls at this point affect
rendering, but the changes will not be retrieved on the next postback.
This is not an event; instead, at this stage of processing, the Page object calls
this method on each control. All ASP.NET Web server controls have a
Render method that writes out the control's markup to send to the browser.
If you create a custom control, you typically override this method to output
Render the control's markup. However, if your custom control incorporates only
standard ASP.NET Web server controls and no custom markup, you do not
need to override the Render method.
In controls, use this event to do final cleanup for specific controls, such as
closing control-specific database connections.
For the page itself, use this event to do final cleanup work, such as closing
open files and database connections, or finishing up logging or other
Unload request-specific tasks.
Note:
During the unload stage, the page and its controls have been rendered, so you
cannot make further changes to the response stream. If you attempt to call a
method such as the Response.Write method, the page will throw an exception.
Individual ASP.NET server controls have their own life cycle that is similar to the page life
cycle. For example, a control's Init and Load events occur during the corresponding page events.
Although both Init and Load recursively occur on each control, they happen in reverse order. The
Init event (and also the Unload event) for each child control occur before the corresponding
event is raised for its container (bottom-up). However the Load event for a container occurs
before the Load events for its child controls (top-down).
When you create a class that inherits from the Page class, in addition to handling events raised by
the page, you can override methods from the page's base class. For example, you can override
the page's InitializeCulture method to dynamically set culture information. Note that when an
event handler is created using the Page_event syntax, the base implementation is implicitly
called and therefore you do not need to call it in your method. For example, the base page class's
OnLoad method is always called, whether you create a Page_Load method or not. However, if
you override the page OnLoad method with the override keyword (Overrides in Visual Basic),
you must explicitly call the base method. For example, if you override the OnLoad method on
the page, you must call base.Load (MyBase.Load in Visual Basic) in order for the base
implementation to be run.
If controls are created dynamically at run time or declaratively within templates of data-bound
controls, their events are initially not synchronized with those of other controls on the page. For
example, for a control that is added at run time, the Init and Load events might occur much later
in the page life cycle than the same events for controls created declaratively. Therefore, from the
time that they are instantiated, dynamically added controls and controls in templates raise their
events one after the other until they have caught up to the event during which it was added to the
Controls collection.
To help you understand the relationship between the page life cycle and data binding events, the
following table lists data-related events in data-bound controls such as the GridView,
DetailsView, and FormView controls.
If a child control has been data bound, but its container control has not yet been data bound, the
data in the child control and the data in its container control can be out of sync. This is true
particularly if the data in the child control performs processing based on a data-bound value in
the container control.
For example, suppose you have a GridView control that displays a company record in each row,
and it displays a list of the company officers in a ListBox control. To fill the list of officers, you
would bind the ListBox control to a data source control (such as SqlDataSource) that retrieves
the company officer data using the company ID in a query.
If the ListBox control's data-binding properties, such as DataSourceID and DataMember, are set
declaratively, the ListBox control will try to bind to its data source during the containing row's
DataBinding event. However, the CompanyID field of the row does not contain a value until the
GridView control's RowDataBound event occurs. In this case, the child control (the ListBox
control) is bound before the containing control (the GridView control) is bound, so their data-
binding stages are out of sync.
To avoid this condition, put the data source control for the ListBox control in the same template
item as the ListBox control itself, and do not set the data binding properties of the ListBox
declaratively. Instead, set them programmatically at run time during the RowDataBound event,
so that the ListBox control does not bind to its data until the CompanyID information is
available.
The Login control can use settings in the Web.config file to manage membership authentication
automatically. However, if your application requires you to customize how the control works, or
if you want to understand how Login control events relate to the page life cycle, you can use the
events listed in the following table.
Control
Typical Use
Event
Raised during a postback, after the page's LoadComplete event has occurred. This
event marks the beginning of the login process.
LoggingIn
Use this event for tasks that must occur prior to beginning the authentication
process.
Raised after the LoggingIn event.
Authenticate
Use this event to override or enhance the default authentication behavior of a
Login control.
Raised after the user name and password have been authenticated.
LoggedIn
Use this event to redirect to another page or to dynamically set the text in the
control. This event does not occur if there is an error or if authentication fails.
Raised if authentication was not successful.
LoginError
Use this event to set text in the control that explains the problem or to direct the
user to a different page.
Object
Description ASP.NET Class
Name
Provides access to the output stream for the current page. You
Response can use this class to inject text into the page, to write cookies, HttpResponse
and more.
Provides access to the current page request, including the
request headers, cookies, client certificate, query string, and
Request HttpRequest
so on. You can use this class to read what the browser has
sent.
Provides access to the entire current context (including the
Context request object). You can use this class to share information HttpContext
between pages.
Exposes utility methods that you can use to transfer control
Server between pages, get information about the most recent error, HttpServerUtility
encode and decode HTML text, and more.
Provides access to application-wide methods and events for
Application all sessions. Also provides access to an application-wide HttpApplicationState
cache you can use to store information.
Provides information to the current user session. Also
provides access to a session-wide cache you can use to store
Session HttpSessionState
information, along with the means to control how the session
is managed.
Provides a way to display both system and custom trace
Trace TraceContext
diagnostic messages in the HTTP page output.
Scenarios
Features
Background
Class Reference
Scenarios
View state is used automatically by the ASP.NET page framework to persist information that
must be preserved between postbacks. This information includes any non-default values of
controls.
You can also use view state to store application data that is specific to a page.
Features
View state is a repository in an ASP.NET page that can store values that have to be retained
during postback. The page framework uses view state to persist control settings between
postbacks.
You can use view state in your own applications to do the following:
Keep values between postbacks without storing them in session state or in a user profile.
Create a custom view state provider that lets you store view state information in a SQL
Server database or in another data store.
For example, you can store information in view state that your code can access during the page
load event the next time that the page is sent to the server.
Background
A Web application is stateless. A new instance of the Web page class is created every time that
the page is requested from the server. This would ordinarily mean that all information in the page
and in its controls would be lost with each round trip. For example, by default if a user enters
information into a text box on an HTML Web page, that information is sent to the server.
However, it is not returned to the browser in the response.
To overcome this intrinsic limitation of Web programming, the ASP.NET page framework
includes several state-management features to preserve page and control values between round
trips to the Web server. One of these features is view state
By default, the ASP.NET page framework uses view state to preserve page and control values
between round trips. When the HTML for the page is rendered, the current state of the page and
values that must be retained during postback are serialized into base64-encoded strings. They are
then put into a hidden field or fields in the page.
You can access view state in your code by using the page's ViewState property. The ViewState
property is a dictionary that contains key/value pairs that contain the view state data.
Security Note:
It is easy for a malicious user to see and modify the contents of a hidden field.
You can change the default behavior and store view state in another location such as a SQL
Server database by implementing a custom PageStatePersister class to store page data.
View state provides state information for a specific ASP.NET page. If you need to use
information on more than one page, or if you need the information to persist across visits to the
Web site, you must use another method for maintaining state. You can use application state,
session state, or profile properties.
View state information is serialized into XML and then encoded by using base-64 encoding,
which can generate large amounts of data. When the page is posted to the server, the contents of
view state are sent as part of the page postback information. If view state contains a large amount
of information, it can affect performance of the page. Test the performance of your pages by
using typical data for your application to determine whether the size of view state is causing
performance problems.
If you do not have to store control information for individual controls, you can disable view state
for a control. If a control on a page is refreshed from the data store on each postback, you can
turn view state off for that control in order to reduce the size of view state. For example, you
might turn view state off for a control such as the GridView control.
Note:
Even when you explicitly turn view state off, a hidden field is still sent to the browser to indicate
that postback is occurring for the page.
Another consideration is that if the amount of data in a hidden field becomes large, some proxies
and firewalls will prevent access to the page that contains them. Because the maximum allowed
amount can vary with different firewall and proxy implementations, large hidden fields can cause
intermittent problems. If the amount of data that is stored in the ViewState property exceeds the
value specified in the page's MaxPageStateFieldLength property, the page splits view state into
multiple hidden fields. This reduces the size of individual hidden fields below the size that
firewalls reject.
Some mobile devices do not allow hidden fields at all. Therefore, view state will not work for
those devices. For more information and alternatives, see ASP.NET Mobile Web Development
Overview.
Control State
In addition to view state, ASP.NET supports control state. The page uses control state to persist
control information that must be retained between postbacks, even if view state is disabled for
the page or for a control. Like view state, control state is stored in one or more hidden fields.
You can access view state information by using the page's ViewState property, which exposes a
dictionary object. You can use this dictionary to store custom values. A typical use is to store the
value of custom properties that you define in the page.
Because view state is sent as a hidden field, you can make changes to view state until the page's
PreRenderComplete event. After the page is rendered to the browser, changes to view state will
not be saved.
The information in the hidden view state field can be seen by users if they view the source of the
Web page and can decode base-64 encoded strings. This creates a potential security issue.
Note:
To use the ViewState property, the ASP.NET Web page must have a form element that has the
attribute runat="server".
To save a value to view state, create a new item that contains the value to save and add the item
to the view state dictionary. The following example shows an ASP.NET Web page with code
that saves a string and an integer value in view state.
Strings
Integers
Boolean values
Array objects
ArrayList objects
Hash tables
To read a value from view state, you get the ViewState property of page and then read the value
from the view state dictionary.
The following example shows how you can get an ArrayList object named arrayListInViewState
from view state and then bind a GridView control to the object as a data source.
Me.GridView1.DataSource = arrayList
Me.GridView1.DataBind()
Values in view state are typed as String. In Visual Basic, if you set Option Strict On, you must
cast view state values to the appropriate type before you use them, as shown in the previous
example. In C#, you must always cast to the appropriate type when you read view state values.
If you try to get a value out of view state that does not exist, no exception is thrown. To make
sure that a value is in view state, check first whether the object exists. The following example
shows how to check for a view state entry.
If you try to use a nonexistent view state entry in some other way (for example, to examine its
type), a NullReferenceException exception is thrown.
By creating a hash value, the ASP.NET page framework can test whether the view state data has
been corrupted or tampered with. However, even if it is not tampered with, view state data can
still be intercepted and read by malicious users.
View state
Control state
Hidden fields
Cookies
Query strings
Application state
Session state
Profile Properties
View state, control state, hidden fields, cookies, and query strings all involve storing data on the
client in various ways. However, application state, session state, and profile properties all store
data in memory on the server. Each option has distinct advantages and disadvantages, depending
on the scenario.
The following sections describe options for state management that involve storing information
either in the page or on the client computer. For these options, no information is maintained on
the server between round trips.
View State
The ViewState property provides a dictionary object for retaining values between multiple
requests for the same page. This is the default method that the page uses to preserve page and
control property values between round trips.
When the page is processed, the current state of the page and controls is hashed into a string and
saved in the page as a hidden field, or multiple hidden fields if the amount of data stored in the
ViewState property exceeds the specified value in the MaxPageStateFieldLength property. When
the page is posted back to the server, the page parses the view-state string at page initialization
and restores property information in the page.
You can store values in view state as well. The following example shows how to store a value in
the view state.
[Visual Basic]
ViewState("color") = "red"
[C#]
ViewState["color"] = "red";
Control State
Sometimes you need to store control-state data in order for a control to work properly. For
example, if you have written a custom control that has different tabs that show different
information, in order for that control to work as expected, the control needs to know which tab is
selected between round trips. The ViewState property can be used for this purpose, but view
state can be turned off at a page level by developers, effectively breaking your control. To solve
this, the ASP.NET page framework exposes a feature in ASP.NET called control state.
The ControlState property allows you to persist property information that is specific to a control
and cannot be turned off like the ViewState property.
The following example shows a custom control that stores a value in control state.
Class Sample
Inherits Control
End Class
Hidden Fields
ASP.NET allows you to store information in a HiddenField control, which renders as a standard
HTML hidden field. A hidden field does not render visibly in the browser, but you can set its
properties just as you can with a standard control. When a page is submitted to the server, the
content of a hidden field is sent in the HTTP form collection along with the values of other
controls. A hidden field acts as a repository for any page-specific information that you want to
store directly in the page.
Security Note:
It is easy for a malicious user to see and modify the contents of a hidden field. Do not store any
information in a hidden field that is sensitive or that your application relies on to work properly..
A HiddenField control stores a single variable in its Value property and must be explicitly added
to the page. The following example shows a HiddenField control with an initial value.
<asp:hiddenfield id="ExampleHiddenField"
value="Example Value"
runat="server"/>
In order for hidden-field values to be available during page processing, you must submit the page
using an HTTP POST command. If you use hidden fields and a page is processed in response to
a link or an HTTP GET command, the hidden fields will not be available.
Cookies
A cookie is a small amount of data that is stored either in a text file on the client file system or
in-memory in the client browser session. It contains site-specific information that the server
sends to the client along with page output. Cookies can be temporary (with specific expiration
times and dates) or persistent.
You can use cookies to store information about a particular client, session, or application. The
cookies are saved on the client device, and when the browser requests a page, the client sends the
information in the cookie along with the request information. The server can read the cookie and
extract its value. A typical use is to store a token (perhaps encrypted) indicating that the user has
already been authenticated in your application.
Security Note:
The browser can only send the data back to the server that originally created the cookie.
However, malicious users have ways to access cookies and read their contents. It is recommended
that you do not store sensitive information, such as a user name or password, in a cookie. Instead,
store a token in the cookie that identifies the user, and then use the token to look up the sensitive
information on the server.
Response.Cookies("destination").Value = "CA"
Response.Cookies("destination").Expires = DateTime.Now.AddDays(1)
Query Strings
A query string is information that is appended to the end of a page URL. A typical query string
might look like the following example:
http://www.contoso.com/listwidgets.aspx?category=basic&price=100
In the URL path above, the query string starts with a question mark (?) and includes two
attribute/value pairs, one called "category" and the other called "price."
Query strings provide a simple but limited way to maintain state information. For example, they
are an easy way to pass information from one page to another, such as passing a product number
from one page to another page where it will be processed. However, some browsers and client
devices impose a 2083-character limit on the length of the URL.
Security Note:
Information that is passed in a query string can be tampered with by a malicious user. Do not rely
on query strings to convey important or sensitive data. Additionally, a user can bookmark the
URL or send the URL to other users, thereby passing that information along with it.
In order for query string values to be available during page processing, you must submit the page
using an HTTP GET command. That is, you cannot take advantage of a query string if a page is
processed in response to an HTTP POST command.
ASP.NET offers you a variety of ways to maintain state information on the server, rather than
persisting information on the client. With server-based state management, you can decrease the
amount of information sent to the client in order to preserve state, however it can use costly
resources on the server. The following sections describe three server-based state management
features: application state, session state, and profile properties.
Application State
ASP.NET allows you to save values using application state — which is an instance of the
HttpApplicationState class — for each active Web application. Application state is a global
storage mechanism that is accessible from all pages in the Web application. Thus, application
state is useful for storing information that needs to be maintained between server round trips and
between requests for pages.
Application state is stored in a key/value dictionary that is created during each request to a
specific URL. You can add your application-specific information to this structure to store it
between page requests.
Once you add your application-specific information to application state, the server manages it.
[Visual Basic]
[C#]
Session State
ASP.NET allows you to save values by using session state — which is an instance of the
HttpSessionState class — for each active Web-application session.
Session state is similar to application state, except that it is scoped to the current browser session.
If different users are using your application, each user session will have a different session state.
In addition, if a user leaves your application and then returns later, the second user session will
have a different session state from the first.
Session state is structured as a key/value dictionary for storing session-specific information that
needs to be maintained between server round trips and between requests for pages.
Store session-specific data on the server for use across multiple browser or client-device
requests within the same session.
Raise appropriate session management events. In addition, you can write application code
leveraging these events.
Once you add your application-specific information to session state, the server manages this
object. Depending on which options you specify, session information can be stored in cookies,
on an out-of-process server, or on a computer running Microsoft SQL Server.
Session("FirstName") = FirstNameTextBox.Text
Session("LastName") = LastNameTextBox.Text
Profile Properties
ASP.NET provides a feature called profile properties, which allows you to store user-specific
data. This feature is similar to session state, except that the profile data is not lost when a user's
session expires. The profile-properties feature uses an ASP.NET profile, which is stored in a
persistent format and associated with an individual user. The ASP.NET profile allows you to
easily manage user information without requiring you to create and maintain your own database.
In addition, the profile makes the user information available using a strongly typed API that you
can access from anywhere in your application. You can store objects of any type in the profile.
The ASP.NET profile feature provides a generic storage system that allows you to define and
maintain almost any kind of data while still making the data available in a type-safe manner.
To use profile properties, you must configure a profile provider. ASP.NET includes a
SqlProfileProvider class that allows you to store profile data in a SQL database, but you can also
create your own profile provider class that stores profile data in a custom format and to a custom
storage mechanism such as an XML file, or even to a web service.
Because data that is placed in profile properties is not stored in application memory, it is
preserved through Internet Information Services (IIS) restarts and worker-process restarts
without losing data. Additionally, profile properties can be persisted across multiple processes
such as in a Web farm or a Web garden.
Profile.PostalCode = txtPostalCode.Text
You must define the PostalCode property in the Web.config file by using the following markup:
<profile>
<properties>
<add name="PostalCode" />
</properties>
</profile>
Scenarios
Background
Code Examples
Class Reference
Additional Resources
What's New
Scenarios
Cookies provide a means in Web applications to store user-specific information. For example,
when a user visits your site, you can use cookies to store user preferences or other information.
When the user visits your Web site another time, the application can retrieve the information it
stored earlier.
Background
A cookie is a small bit of text that accompanies requests and pages as they go between the Web
server and browser. The cookie contains information the Web application can read whenever the
user visits the site.
For example, if a user requests a page from your site and your application sends not just a page,
but also a cookie containing the date and time, when the user's browser gets the page, the
browser also gets the cookie, which it stores in a folder on the user's hard disk.
Later, if user requests a page from your site again, when the user enters the URL the browser
looks on the local hard disk for a cookie associated with the URL. If the cookie exists, the
browser sends the cookie to your site along with the page request. Your application can then
determine the date and time that the user last visited the site. You might use the information to
display a message to the user or check an expiration date.
Cookies are associated with a Web site, not with a specific page, so the browser and server will
exchange cookie information no matter what page the user requests from your site. As the user
visits different sites, each site might send a cookie to the user's browser as well; the browser
stores all the cookies separately.
Cookies help Web sites store information about visitors. More generally, cookies are one way of
maintaining continuity in a Web application—that is, of performing state management. Except
for the brief time when they are actually exchanging information, the browser and Web server
are disconnected. Each request a user makes to a Web server is treated independently of any
other request. Many times, however, it's useful for the Web server to recognize users when they
request a page. For example, the Web server on a shopping site keeps track of individual
shoppers so the site can manage shopping carts and other user-specific information. A cookie
therefore acts as a kind of calling card, presenting pertinent identification that helps an
application know how to proceed.
Cookies are used for many purposes, all relating to helping the Web site remember users. For
example, a site conducting a poll might use a cookie simply as a Boolean value to indicate
whether a user's browser has already participated in voting so that the user cannot vote twice. A
site that asks a user to log on might use a cookie to record that the user already logged on so that
the user does not have to keep entering credentials.
Cookie Limitations
Most browsers support cookies of up to 4096 bytes. Because of this small limit, cookies are best
used to store small amounts of data, or better yet, an identifier such as a user ID. The user ID can
then be used to identify the user and read user information from a database or other data store.
(See the section "Cookies and Security" below for information about security implications of
storing user information.)
Browsers also impose limitations on how many cookies your site can store on the user's
computer. Most browsers allow only 20 cookies per site; if you try to store more, the oldest
cookies are discarded. Some browsers also put an absolute limit, usually 300, on the number of
cookies they will accept from all sites combined.
A cookie limitation that you might encounter is that users can set their browser to refuse cookies.
If you define a P3P privacy policy and place it in the root of your Web site, more browsers will
accept cookies from your site. However, you might have to avoid cookies altogether and use a
different mechanism to store user-specific information. A common method for storing user
information is session state, but session state depends on cookies, as explained later in the
section "Cookies and Session State."
Although cookies can be very useful in your application, the application should not depend on
being able to store cookies. Do not use cookies to support critical features. If your application
must rely on cookies, you can test to see whether the browser will accept cookies. See the
"Checking Whether a Browser Accepts Cookies" section later in this topic.
Writing Cookies
The browser is responsible for managing cookies on a user system. Cookies are sent to the
browser via the HttpResponse object that exposes a collection called Cookies. You can access
the HttpResponse object as the Response property of your Page class. Any cookies that you want
to send to the browser must be added to this collection. When creating a cookie, you specify a
Name and Value. Each cookie must have a unique name so that it can be identified later when
reading it from the browser. Because cookies are stored by name, naming two cookies the same
will cause one to be overwritten.
You can also set a cookie's date and time expiration. Expired cookies are deleted by the browser
when a user visits the site that wrote the cookies. The expiration of a cookie should be set for as
long as your application considers the cookie value to be valid. For a cookie to effectively never
expire, you can set the expiration date to be 50 years from now.
Note:
Users can clear the cookies on their computer at any time. Even if you store cookies with long
expiration times, a user might decide to delete all cookies, wiping out any settings you might
have stored in cookies.
If you do not set the cookie's expiration, the cookie is created but it is not stored on the user's
hard disk. Instead, the cookie is maintained as part of the user's session information. When the
user closes the browser, the cookie is discarded. A non-persistent cookie like this is useful for
information that needs to be stored for only a short time or that for security reasons should not be
written to disk on the client computer. For example, non-persistent cookies are useful if the user
is working on a public computer, where you do not want to write the cookie to disk.
You can add cookies to the Cookies collection in a number of ways. The following example
shows two methods to write cookies:
Response.Cookies("userName").Value = "patrick"
Response.Cookies("userName").Expires = DateTime.Now.AddDays(1)
The example adds two cookies to the Cookies collection, one named userName and the other
named lastVisit. For the first cookie, the values of the Cookies collection are set directly. You
can add values to the collection this way because Cookies derives from a specialized collection
of type NameObjectCollectionBase.
For the second cookie, the code creates an instance of an object of type HttpCookie, sets its
properties, and then adds it to the Cookies collection via the Add method. When you instantiate
an HttpCookie object, you must pass the cookie name as part of the constructor.
Both examples accomplish the same task, writing a cookie to the browser. In both methods, the
expiration value must be of type DateTime. However, the lastVisited value is also a date-time
value. Because all cookie values are stored as strings, the date-time value has to be converted to
a String .
You can store one value in a cookie, such as user name and last visit. You can also store multiple
name-value pairs in a single cookie. The name-value pairs are referred to as subkeys. (Subkeys
are laid out much like a query string in a URL.) For example, instead of creating two separate
cookies named userName and lastVisit, you can create a single cookie named userInfo that has
the subkeys userName and lastVisit.
You might use subkeys for several reasons. First, it is convenient to put related or similar
information into a single cookie. In addition, because all the information is in a single cookie,
cookie attributes such as expiration apply to all the information. (Conversely, if you want to
assign different expiration dates to different types of information, you should store the
information in separate cookies.)
A cookie with subkeys also helps you limit the size of cookie files. As noted earlier in the
"Cookie Limitations" section, cookies are usually limited to 4096 bytes and you can't store more
than 20 cookies per site. By using a single cookie with subkeys, you use fewer of those
20 cookies that your site is allotted. In addition, a single cookie takes up about 50 characters for
overhead (expiration information, and so on), plus the length of the value that you store in it, all
of which counts toward the 4096-byte limit. If you store five subkeys instead of five separate
cookies, you save the overhead of the separate cookies and can save around 200 bytes.
To create a cookie with subkeys, you can use a variation of the syntax for writing a single
cookie. The following example shows two ways to write the same cookie, each with two
subkeys:
Response.Cookies("userInfo")("userName") = "patrick"
Response.Cookies("userInfo")("lastVisit") = DateTime.Now.ToString()
Response.Cookies("userInfo").Expires = DateTime.Now.AddDays(1)
Dim aCookie As New HttpCookie("userInfo")
aCookie.Values("userName") = "patrick"
aCookie.Values("lastVisit") = DateTime.Now.ToString()
aCookie.Expires = DateTime.Now.AddDays(1)
Response.Cookies.Add(aCookie)
By default, all cookies for a site are stored together on the client, and all cookies are sent to the
server with any request to that site. In other words, every page in a site gets all of the cookies for
that site. However, you can set the scope of cookies in two ways:
Limit the scope of cookies to a folder on the server, which allows you to limit cookies to
an application on the site.
Set scope to a domain, which allows you to specify which subdomains in a domain can
access a cookie.
To limit cookies to a folder on the server, set the cookie's Path property, as in the following
example:
Note:
You can also write cookies by adding them to the Cookies collection directly as shown in earlier
examples.
The path can either be a physical path under the site root or a virtual root. The effect will be that
the cookie is available only to pages in the Application1 folder or virtual root. For example, if
your site is called www.contoso.com, the cookie created in the previous example will be
available to pages with the path http://www.contoso.com/Application1/ and to any pages beneath
that folder. However, the cookie will not be available to pages in other applications such as
http://www.contoso.com/Application2/ or just http://www.contoso.com/.
Note:
In some browsers, the path is case sensitive. You cannot control how users type URLs into their
browsers, but if your application depends on cookies tied to a specific path, be sure that the URLs
in any hyperlinks you create match the case of the Path property value.
Limiting Cookie Domain Scope
By default, cookies are associated with a specific domain. For example, if your site is
www.contoso.com, the cookies you write are sent to the server when users request any page from
that site. (This might not include cookies with a specific path value.) If your site has subdomains
—for example, contoso.com, sales.contoso.com, and support.contoso.com—then you can
associate cookies with a specific subdomain. To do so, set the cookie's Domain property, as in
this example:
Response.Cookies("domain").Value = DateTime.Now.ToString()
Response.Cookies("domain").Expires = DateTime.Now.AddDays(1)
Response.Cookies("domain").Domain = "support.contoso.com"
When the domain is set in this way, the cookie will be available only to pages in the specified
subdomain. You can also use the Domain property to create a cookie that can be shared among
multiple subdomains, as shown in the following example:
Response.Cookies("domain").Value = DateTime.Now.ToString()
Response.Cookies("domain").Expires = DateTime.Now.AddDays(1)
Response.Cookies("domain").Domain = "contoso.com"
The cookie will then be available to the primary domain as well as to sales.contoso.com and
support.contoso.com domains.
Reading Cookies
When a browser makes a request to the server, it sends the cookies for that server along with the
request. In your ASP.NET applications, you can read the cookies using the HttpRequest object,
which is available as the Request property of your Page class. The structure of the HttpRequest
object is essentially the same as that of the HttpResponse object, so you can read cookies out of
the HttpRequest object much the same way you wrote cookies into the HttpResponse object. The
following code example shows two ways to get the value of a cookie named username and
display its value in a Label control:
Before trying to get the value of a cookie, you should make sure that the cookie exists; if the
cookie does not exist, you will get a NullReferenceException exception. Notice also that the
HtmlEncode method was called to encode the contents of a cookie before displaying it in the
page. This makes certain that a malicious user has not added executable script into the cookie.
For more about cookie security, see the "Cookies and Security" section.
Note:
Because different browsers store cookies differently, different browsers on the same computer
won't necessarily be able to read each other's cookies. For example, if you use Internet Explorer
to test a page one time, but then later use a different browser to test again, the second browser
won't find the cookies saved by Internet Explorer.
Reading the value of a subkey in a cookie is likewise similar to setting it. The following code
example shows one way to get the value of a subkey:
In the preceding example, the code reads the value of the subkey lastVisit, which was set earlier
to the string representation of a DateTime value. Cookies store values as strings, so if you want
to use the lastVisit value as a date, you have to convert it to the appropriate type, as in this
example:
Dim dt As DateTime
dt = DateTime.Parse(Request.Cookies("userInfo")("lastVisit"))
The browser is responsible for managing cookies, and the cookie's expiration time and date help
the browser manage its store of cookies. Therefore, although you can read the name and value of
a cookie, you cannot read the cookie's expiration date and time. When the browser sends cookie
information to the server, the browser does not include the expiration information. (The cookie's
Expires property always returns a date-time value of zero.) If you are concerned about the
expiration date of a cookie, you must reset it, which is covered in the "Modifying and Deleting
Cookies" section.
Reading Cookie Collections
You might occasionally need to read through all the cookies available to the page. To read the
names and values of all the cookies available to the page, you can loop through the Cookies
collection using code such as the following.
Dim i As Integer
Dim output As System.Text.StringBuilder = New System.Text.StringBuilder
Dim aCookie As HttpCookie
For i = 0 to Request.Cookies.Count - 1
aCookie = Request.Cookies(i)
output.Append("Cookie name = " & Server.HtmlEncode(aCookie.Name) _
& "<br />")
output.Append("Cookie value = " & _
Server.HtmlEncode(aCookie.Value) & "<br /><br />")
Next
Label1.Text = output.ToString()
Note:
When you run this code, you might see a cookie named ASP.NET_SessionId. That is a cookie
that ASP.NET uses to store a unique identifier for your session. The session cookie is not
persisted on your hard disk. For more about session cookies, see the "Cookies and Session State"
later in this topic.
A limitation of the preceding example is that if the cookie has subkeys, the display shows the
subkeys as a single name/value string. You can read a cookie's HasKeys property to determine
whether the cookie has subkeys. If so, you can read the subkey collection to get individual
subkey names and values. You can read subkey values from the Values collection directly by
index value. The corresponding subkey names are available in the AllKeys member of the
Values collection, which returns an array of strings. You can also use the Keys member of the
Values collection. However, the AllKeys property is cached the first time it is accessed. In
contrast, the Keys property builds an array each time it is accessed. For this reason, the AllKeys
property is much faster on subsequent accesses within the context of the same page request.
The following example shows a modification of the preceding example. It uses the HasKeys
property to test for subkeys, and if subkeys are detected, the example gets subkeys from the
Values collection:
Dim i As Integer
Dim j As Integer
Dim output As System.Text.StringBuilder = New StringBuilder()
Dim aCookie As HttpCookie
Dim subkeyName As String
Dim subkeyValue As String
For i = 0 To Request.Cookies.Count - 1
aCookie = Request.Cookies(i)
output.Append("Name = " & aCookie.Name & "<br />")
If aCookie.HasKeys Then
For j = 0 To aCookie.Values.Count - 1
subkeyName = Server.HtmlEncode(aCookie.Values.AllKeys(j))
subkeyValue = Server.HtmlEncode(aCookie.Values(j))
output.Append("Subkey name = " & subkeyName & "<br />")
output.Append("Subkey value = " & subkeyValue & _
"<br /><br />")
Next
Else
output.Append("Value = " & Server.HtmlEncode(aCookie.Value) & _
"<br /><br />")
End If
Next
Label1.Text = output.ToString()
Alternatively, you can extract the subkeys as a NameValueCollection object as shown in the
following example:
Dim i As Integer
Dim j As Integer
Dim output As System.Text.StringBuilder = New StringBuilder()
Dim aCookie As HttpCookie
Dim subkeyName As String
Dim subkeyValue As String
For i = 0 To Request.Cookies.Count - 1
aCookie = Request.Cookies(i)
output.Append("Name = " & aCookie.Name & "<br />")
If aCookie.HasKeys Then
Dim CookieValues As _
System.Collections.Specialized.NameValueCollection = _
aCookie.Values
Dim CookieValueNames() As String = CookieValues.AllKeys
For j = 0 To CookieValues.Count - 1
subkeyName = Server.HtmlEncode(CookieValueNames(j))
subkeyValue = Server.HtmlEncode(CookieValues(j))
output.Append("Subkey name = " & subkeyName & "<br />")
output.Append("Subkey value = " & subkeyValue & _
"<br /><br />")
Next
Else
output.Append("Value = " & Server.HtmlEncode(aCookie.Value) & _
"<br /><br />")
End If
Next
Label1.Text = output.ToString
You cannot directly modify a cookie. Instead, changing a cookie consists of creating a new
cookie with new values and then sending the cookie to the browser to overwrite the old version
on the client. The following code example shows how you can change the value of a cookie that
stores a count of the user's visits to the site:
Deleting Cookies
Deleting a cookie—physically removing it from the user's hard disk—is a variation on modifying
it. You cannot directly remove a cookie because the cookie is on the user's computer. However,
you can have the browser delete the cookie for you. The technique is to create a new cookie with
the same name as the cookie to be deleted, but to set the cookie's expiration to a date earlier than
today. When the browser checks the cookie's expiration, the browser will discard the now-
outdated cookie. The following code example shows one way to delete all the cookies available
to the application:
Modifying an individual subkey is the same as creating it, as shown in the following example:
Response.Cookies("userInfo")("lastVisit") = DateTime.Now.ToString()
Response.Cookies("userInfo").Expires = DateTime.Now.AddDays(1)
To delete an individual subkey, you manipulate the cookie's Values collection, which holds the
subkeys. You first recreate the cookie by getting it from the Cookies object. You can then call
the Remove method of the Values collection, passing to the Remove method the name of the
subkey to delete. You then add the cookie to the Cookies collection so it will be sent in its
modified form back to the browser. The following code example shows how to delete a subkey.
In the sample, the name of the subkey to remove is specified in a variable.
subkeyName = "userName"
Dim aCookie As HttpCookie = Request.Cookies("userInfo")
aCookie.Values.Remove(subkeyName)
aCookie.Expires = DateTime.Now.AddDays(1)
Response.Cookies.Add(aCookie)
Cookies and Security
The security issues with cookies are similar to those of getting data from the client. In your
application, cookies are another form of user input and are therefore subject to examining and
spoofing. A user can as a minimum see the data that you store in a cookie, since the cookie is
available on the user's own computer. The user can also change the cookie before the browser
sends it to you.
You should never store sensitive data in a cookie, such as user names, passwords, credit card
numbers, and so on. Do not put anything in a cookie that should not be in the hands of a user or
of someone who might somehow steal the cookie.
Similarly, be suspicious of information you get out of a cookie. Do not assume that the data is
the same as when you wrote it out; use the same safeguards in working with cookie values that
you would with data that a user has typed into a Web page. The examples earlier in this topic
showed HTML-encoding the contents of a cookie before displaying the value in a page, as you
would before displaying any information you get from users.
Cookies are sent between browser and server as plain text, and anyone who can intercept your
Web traffic can read the cookie. You can set a cookie property that causes the cookie to be
transmitted only if the connection uses the Secure Sockets Layer (SSL). SSL does not protect the
cookie from being read or manipulated while it is on the user's computer, but it does prevent the
cookie from being read while in transit because the cookie is encrypted.
Users can set their browser to refuse cookies. No error is raised if a cookie cannot be written.
The browser likewise does not send any information to the server about its current cookie
settings.
Note:
The Cookies property does not indicate whether cookies are enabled. It indicates only whether the
current browser inherently supports cookies.
One way to determine whether cookies are accepted is by trying to write a cookie and then trying
to read it back again. If you cannot read the cookie you wrote, you assume that cookies are
turned off in the browser.
The following code example shows how you might test whether cookies are accepted. The
sample consists of two pages. The first page writes out a cookie, and then redirects the browser
to the second page. The second page tries to read the cookie. It in turn redirects the browser back
to the first page, adding to the URL a query string variable with the results of the test.
The page first tests to see if this is a postback, and if not, the page looks for the query string
variable name AcceptsCookies that contains the test results. If there is no query string variable,
the test has not been completed, so the code writes out a cookie named TestCookie. After writing
out the cookie, the sample calls Redirect to transfer to the test page TestForCookies.aspx.
Appended to the URL of the test page is a query string variable named redirect containing the
URL of the current page; this will allow you to redirect back to this page after performing the
test.
The test page can consist entirely of code; it does not need to contain controls. The following
code example illustrates the test page.
Sub Page_Load()
After reading the redirect query string variable, the code tries to read the cookie. For
housekeeping purposes, if the cookie exists, it is immediately deleted. When the test is finished,
the code constructs a new URL from the URL passed to it in the redirect query string variable.
The new URL also includes a query string variable containing test results. The final step is to use
the new URL to redirect the browser to the original page.
An improvement in the example would be to keep the cookie test results in a persistent store
such as a database so that the test does not have to be repeated each time the user views the
original page. (Storing the test results in session state by default requires cookies.)
When a user navigates to your site, the server establishes a unique session for that user that lasts
for the duration of the user's visit. For each session, ASP.NET maintains session state
information where applications can store user-specific information.
ASP.NET must track a session ID for each user so that it can map the user to session state
information on the server. By default, ASP.NET uses a non-persistent cookie to store the session
state. However, if a user has disabled cookies on the browser, session state information cannot be
stored in a cookie.
ASP.NET offers an alternative in the form of cookieless sessions. You can configure your
application to store session IDs not in a cookie, but in the URLs of pages in your site. If your
application relies on session state, you might consider configuring it to use cookieless sessions.
However, under some limited circumstances, if the user shares the URL with someone else—
perhaps to send the URL to a colleague while the user's session is still active—then both users
can end up sharing the same session, with unpredictable results.
Class Reference
HttpCookie Provides a type-safe way to create and manipulate individual HTTP cookies.
Cookies Gets the response cookie collection.
Cookies Gets a collection of cookies sent by the client.
Background
Class Reference
Background
ASP.NET session state enables you to store and retrieve values for a user as the user navigates
ASP.NET pages in a Web application. HTTP is a stateless protocol. This means that a Web
server treats each HTTP request for a page as an independent request. The server retains no
knowledge of variable values that were used during previous requests. ASP.NET session state
identifies requests from the same browser during a limited time window as a session, and
provides a way to persist variable values for the duration of that session. By default, ASP.NET
session state is enabled for all ASP.NET applications.
Application state, which stores variables that can be accessed by all users of an ASP.NET
application.
Profile properties, which persists user values in a data store without expiring them.
ASP.NET caching, which stores values in memory that is available to all ASP.NET
applications.
Cookies.
The query string and fields on an HTML form that are available from an HTTP request.
Session Variables
Session variables are stored in a SessionStateItemCollection object that is exposed through the
HttpContext.Session property. In an ASP.NET page, the current session variables are exposed
through the Session property of the Page object.
The collection of session variables is indexed by the name of the variable or by an integer index.
Session variables are created by referring to the session variable by name. You do not have to
declare a session variable or explicitly add it to the collection. The following example shows
how to create session variables in an ASP.NET page for the first and last name of a user, and set
them to values retrieved from TextBox controls.
Session("FirstName") = FirstNameTextBox.Text
Session("LastName") = LastNameTextBox.Text
Session variables can be any valid .NET Framework type. The following example stores an
ArrayList object in a session variable named StockPicks. The value returned by the StockPicks
session variable must be cast to the appropriate type when you retrieve it from the
SessionStateItemCollection.
' Write the modified stock picks list back to session state.
Session("StockPicks") = stockPicks
Note:
When you use a session-state mode other than InProc, the session-variable type must be either a
primitive .NET type or serializable. This is because the session-variable value is stored in an
external data store. For more information, see Session-State Modes.
Session Identifiers
Sessions are identified by a unique identifier that can be read by using the SessionID property.
When session state is enabled for an ASP.NET application, each request for a page in the
application is examined for a SessionID value sent from the browser. If no SessionID value is
supplied, ASP.NET starts a new session and the SessionID value for that session is sent to the
browser with the response.
By default, SessionID values are stored in a cookie. However, you can also configure the
application to store SessionID values in the URL for a "cookieless" session.
A session is considered active as long as requests continue to be made with the same SessionID
value. If the time between requests for a particular session exceeds the specified time-out value
in minutes, the session is considered expired. Requests made with an expired SessionID value
result in a new session.
Security Note:
SessionID values are sent in clear text, whether as a cookie or as part of the URL. A malicious
user could get access to the session of another user by obtaining the SessionID value and
including it in requests to the server. If you are storing sensitive information in session state, it is
recommended that you use SSL to encrypt any communication between the browser and server
that includes the SessionID value.
Cookieless SessionIDs
By default, the SessionID value is stored in a non-expiring session cookie in the browser.
However, you can specify that session identifiers should not be stored in a cookie by setting the
cookieless attribute to true in the sessionState section of the Web.config file.
The following example shows a Web.config file that configures an ASP.NET application to use
cookieless session identifiers.
<configuration>
<system.web>
<sessionState cookieless="true"
regenerateExpiredSessionId="true" />
</system.web>
</configuration>
ASP.NET maintains cookieless session state by automatically inserting a unique session ID into
the page's URL. For example, the following URL has been modified by ASP.NET to include the
unique session ID lit3py55t21z5v55vlm25s55:
http://www.example.com/(S(lit3py55t21z5v55vlm25s55))/orderform.aspx
When ASP.NET sends a page to the browser, it modifies any links in the page that use an
application-relative path by embedding a session ID value in the links. (Links with absolute
paths are not modified.) Session state is maintained as long as the user clicks links that have been
modified in this manner. However, if the client rewrites a URL that is supplied by the
application, ASP.NET may not be able to resolve the session ID and associate the request with
an existing session. In that case, a new session is started for the request.
The session ID is embedded in the URL after the slash that follows the application name and
before any remaining file or virtual directory identifier. This enables ASP.NET to resolve the
application name before involving the SessionStateModule in the request.
Note:
To improve the security of your application, you should allow users to log out of your
application, at which point the application should call the Abandon method. This reduces the
potential for a malicious user to get the unique identifier in the URL and use it to retrieve private
user data stored in the session.
Regenerating Expired Session Identifiers
By default, the session ID values that are used in cookieless sessions are recycled. That is, if a
request is made with a session ID that has expired, a new session is started by using the
SessionID value that is supplied with the request. This can result in a session unintentionally
being shared when a link that contains a cookieless SessionID value is used by multiple
browsers. (This can occur if the link is passed through a search engine, through an e-mail
message, or through another program.) You can reduce the chance of session data being shared
by configuring the application not to recycle session identifiers. To do this, set the
regenerateExpiredSessionId attribute of the sessionState configuration element to true. This
generates a new session ID when a cookieless session request is made with an expired session
ID.
Note:
If the request that is made with the expired session ID is made by using the HTTP POST method,
any posted data will be lost when regenerateExpiredSessionId is true. This is because ASP.NET
performs a redirect to make sure that the browser has the new session identifier in the URL.
Custom Session Identifiers
You can implement a custom class to supply and validate SessionID values. To do so, create a
class that inherits the SessionIDManager class and override the CreateSessionID and Validate
methods with your own implementations. For an example, see the example provided for the
CreateSessionID method.
You can replace the SessionIDManager class by creating a class that implements the
ISessionIDManager interface. For example, you might have a Web application that associates a
unique identifier with non-ASP.NET pages (such as HTML pages or images) by using an ISAPI
filter. You can implement a custom SessionIDManager class to use this unique identifier with
ASP.NET session state. If your custom class supports cookieless session identifiers, you must
implement a solution for sending and retrieving session identifiers in the URL.
Session Modes
ASP.NET session state supports several storage options for session variables. Each option is
identified as a session-state Mode type. The default behavior is to store session variables in the
memory space of the ASP.NET worker process. However, you can also specify that session state
should be stored in a separate process, in a SQL Server database, or in a custom data source. If
you do not want session state enabled for your application, you can set the session mode to Off.
Session Events
ASP.NET provides two events that help you manage user sessions. The Session_OnStart event
is raised when a new session starts, and the Session_OnEnd event is raised when a session is
abandoned or expires. Session events are specified in the Global.asax file for an ASP.NET
application.
The Session_OnEnd event is not supported if the session Mode property is set to a value other
than InProc, which is the default mode.
Note:
If the Global.asax file or Web.config file for an ASP.NET application is modified, the application
will be restarted and any values stored in application state or session state will be lost. Be aware
that some anti-virus software can update the last-modified date and time of the Global.asax or
Web.config file for an application.
Configuring Session State
Session state is configured by using the sessionState element of the system.web configuration
section. You can also configure session state by using the EnableSessionState value in the
@ Page directive.
The sessionState element enables you to specify the following options:
The way in which session identifier values are sent between the client and the server.
The following example shows a sessionState element that configures an application for
SQLServer session mode. It sets the Timeout value to 30 minutes, and specifies that session
identifiers are stored in the URL.
<sessionState mode="SQLServer"
cookieless="true "
regenerateExpiredSessionId="true "
timeout="30"
sqlConnectionString="Data Source=MySqlServer;Integrated Security=SSPI;"
stateNetworkTimeout="30"/>
You can disable session state for an application by setting the session-state mode to Off. If you
want to disable session state for only a particular page of an application, you can set the
EnableSessionState value in the @ Page directive to false. The EnableSessionState value can
also be set to ReadOnly to provide read-only access to session variables.
Access to ASP.NET session state is exclusive per session, which means that if two different
users make concurrent requests, access to each separate session is granted concurrently.
However, if two concurrent requests are made for the same session (by using the same SessionID
value), the first request gets exclusive access to the session information. The second request
executes only after the first request is finished. (The second session can also get access if the
exclusive lock on the information is freed because the first request exceeds the lock time-out.) If
the EnableSessionState value in the @ Page directive is set to ReadOnly, a request for the read-
only session information does not result in an exclusive lock on the session data. However, read-
only requests for session data might still have to wait for a lock set by a read-write request for
session data to clear.
Back to top
Class Reference
The following table lists key classes that relate to session state are in the
System.Web.SessionState namespace.
Member Description
SessionIDManager Manages unique identifiers for ASP.NET session state.
SessionStateItemCollection Used to store session state variables.
Application state is stored in an instance of the HttpApplicationState class. This class exposes a
key-value dictionary of objects.
The HttpApplicationState instance is created the first time a user accesses any URL resource in
an application. The HttpApplicationState class is most often accessed through the Application
property of the HttpContext class.
You can use application state in two ways. You can add, access, or remove values from the
Contents collection directly through code. The HttpApplicationState class can be accessed at any
time during the life of an application. However, it is often useful to load application state data
when the application starts. To do so, you can put code to load application state into the
Application_Start method in the Global.asax file.
Alternatively, you can add objects to the StaticObjects collection via an <object runat="server">
declaration in your Web application's Global.asax file. Application state defined in this way can
then be accessed from code anywhere in your application. The following example shows an
object declaration for an application state value:
You can add objects to the StaticObjects collection only in the Global.asax file. The collection
throws a NotSupportedException if you attempt to add objects directly through code.
You can access members of objects stored in application state without having to reference the
Application collection. The following code example shows how to reference a member of an
object defined in the StaticObjects collection of application state. Notice that the label identifier
that is defined in the Global.asax file is used as the variable name.
When using application state, you must be aware of the following important considerations:
ASP.NET Caching
Caching
Caching is the process of storing frequently used data, usually data that is costly to generate, for
reuse. Typically this data is stored in memory since retrieving data from memory is much more
efficient than retrieving the data from other locations, such as a database.
ASP.NET has several facilities for supporting caching: a Cache API for storing arbitrary data
and an Output Cache used to store frequently requested Pages.
A catalog used on an e-commerce site might only change once a week. An ASP.NET Web
application could be built that provides a front-end interface for that catalog, allowing customers
to purchase products. When a customer is simply browsing the catalog, the system is making (in
most cases) network calls to a back-end database server. The database server is also doing
calculations on the data, such as a join query, and returning results.
This type of configuration is quite common, be it a catalog or some other type of commonly
requested data from a database. However, the design in the above example can be improved
upon. We know that the data in the database only changes once a week, and we know that there
are several performance costs associated with retrieving the data:
Caching allows us to eliminate much of the above work and improve the performance and
scalability of our application. We can improve performance by caching the results and serving
them statically (versus dynamically on each request) and our scalability increases since we're
using fewer resources to service each request.
Beta 1 of ASP.NET introduced the Cache API as well as Page output caching, which uses the
Cache API. Let's discuss these two features in more detail.
Cache API
Storing frequently requested data in memory is nothing new for ASP developers. We've had two
types of objects that solve this problem:
Session objects
Application objects
Session is used to store per-user data across multiple requests. There have been some changes for
Session in ASP.NET but most of these changes are application level changes and don't affect the
way Session is used, that is, it's still a simple key/value pair.
The Application object from ASP is also carried forward to ASP.NET, and it to remains
identical in function (key/value pairs). For example, we could write the following in either ASP
or ASP.NET:
The same semantics are used for Session. We simply name a key, in this case we used
SomeInterestingData, and assign it a value, in this case the string "Example data".
Dependencies—A key added to the Cache can set up dependency relationships that can force
that key to be removed from the Cache. The supported dependencies include key, file, and time.
Automatic Expiration—Underused items added to the Cache that have no dependencies will
automatically expire if they are underused.
Support for Callback—Code paths can be added that will be called when an item is removed
from the Cache, giving us an opportunity to update the Cache or not remove the item.
When we code our applications to use the Cache we do have to make one consideration:
Always check if the item exists in the Cache before attempting to use it.
Because the Cache will expire, items based on dependencies or under use, we must always write
our code to create or retrieve the item we need if it doesn't exist within the Cache.
' Connect
sqlConnection = new SQLConnection(sqlDSN)
sqlAdapater = new SQLDataSetCommand(sqlSelect, sqlConnection)
Return products
End Function
We could easily write code that took advantage of the Cache. Executing LoadDataSet() only
when the resulting DataSet is not already in the Cache:
Return Cache("ProductData")
End Function
However, this isn't really all that different from using Application. We essentially could
accomplish exactly this same thing. Where this gets interesting is when we set up dependencies.
Cache Dependencies
Dependencies allow us to invalidate a particular item within the Cache based on changes to files,
changes to other Cache keys, or at a fixed point in time. Let's look at each of these dependencies.
File-based Dependency
File-based dependency invalidates a particular Cache item when file(s) on disk change. For
example, if instead of loading our ProductData from a database, we loaded it from an XML file:
We obviously would also want to invalidate the data within the Cache if product.xml changes.
Assuming product.xml is in the same directory as the requesting application:
In the above code sample, we're creating an instance of a CacheDependency class, dependency,
and passing in the path to the product.xml file. We then use the Insert() method of the Cache to
create our ProductData key that is dependent upon the file it retrieves its data from.
Key-based Dependency
Key-based dependency invalidates a particular Cache item when another Cache item changes.
For example, if our application added multiple DataSets to the Cache, such as ProductData,
SalesData, and MarketingData and SalesData and MarketingData rely upon ProductData
being valid. We could use a key-based dependency to invalidate SalesData and MarketingData
if ProductData changes. We set up this dependency when we create the Cache entries for
SalesData and MarketingData:
Dim dependency (1) As String
dependencyKey(0) = "ProductData"
Dim productDataDependency As new CacheDependency(nothing, dependencyKey)
In the above example code, we use the Insert() method to create a new Cache entry named
SalesData passing in an instance of a CacheDependency class named productDataDependency
which names the Cache key ProductData. Now, whenever ProductData changes, SalesData
will be removed from the Cache.
Time-based Dependency
Time-based dependency simply expires the item at a defined point in time. Again, we would use
the Insert() method of the Cache to create this dependency. We have two options for time-based
dependency:
Absolute—Sets an absolute time; for example, current time + 10 minutes for the Cache entry to
expire.
Sliding—Resets the time for the item in the Cache to expire on each request.
We can use the Sliding expiration option to Cache our ProductData DataSet for a maximum of
10 minutes. As long as requests for ProductData are made within a 10-minute window, the data
is made valid for another 10 minutes:
Although this has been a relatively lightweight discussion of the Cache API, hopefully you've
seen just how easy it is to use. Underneath the covers, ASP.NET makes use of the Cache API
and it's time based expiration policy to support the concept of page output caching. In a future
column will dig into more detail on the Cache API.
Page output caching is a feature of ASP.NET that allows for the entire contents of a given page
to be stored in the Cache. We've been using the Cache API in the above example to store
DataSets in the Cache. What if, rather than simply storing the DataSet, we determine that the
entire page (that displays the results of the DataSet) can be cached? The benefit here is that
rather than dynamically executing the ASP.NET page on each request, we serve it statically from
memory. This can be a huge performance enhancement!
There is both a low-level and high-level API for working with Page Output Caching. We're only
going to discuss the high-level API in the remainder of this article, but we'll discuss the low-level
API in a future column (post Beta 2).
The high-level API consists of a Page directive that instructs ASP.NET to Cache the results from
the page for a period of time:
This directive, added to the top of an ASP.NET page, simply instructs ASP.NET to cache the
results of the page for 10 seconds. After 10 seconds the page will re-execute. Here's an example
that uses this directive:
This page simply executes on the first request, displays the time at which it was requested, and
then is served from the Cache for a period of 10 seconds. For example, if we request the page at
10:30:12, we would see that value for the output for 10 seconds, after which the page is re-
executed.
Summary
The Cache is a new feature for us ASP developers. However, it is both easy to use and powerful.
The API is similar to Application and Session, a simple key/value pair dictionary, but unlike
Application or Session, items within the Cache can expire. Unlike Application, the Cache
supports file, key, and time based dependencies, as well as callbacks, which we'll save for our
post Beta 2 discussion. The Cache is also used by ASP.NET for ASP.NET Page Output Caching.
In a future column we'll discuss some of the new Cache features that will be appearing in Beta 2,
such as Partial Page Caching and Web Service Caching, and we'll also look at some of the more
advanced features like callbacks.