Sei sulla pagina 1di 38

1 ASP.

NET Caching Caching is a mechanism of storing items such as data Objects, pages or part of the page in memory the first time they are requested. They can be stored in the web server or in the proxy server or in the browser. This allows us to avoid recreating information that satisfied a previous request, particularly information that demands significant processor time, or other resources, on the server when it is created. Thus, the server does not have to recreate information, saving time and resources.

Advantages of caching Caching increases 1. Performance : Caching Techniques are used to improve application performance by Storing data as close as possible to the consumer thus avoiding repetitive data creation , processing and transportation 2. Scalability The same data, business functionality, and user interface fragments are often required by many users and processes in an application. If this information is processed for each request, valuable resources are wasted recreating the same output. Instead, you can store the results in a cache and reuse them for each request. This improves the scalability of your application because as the user base increases, the demand for server resources for these tasks remains constant. 3. Availability Occasionally the services that provide information to your application may be unavailable. By storing that data in another place, your application may be able to survive system failures such as network latency, Web service problems, or hardware failures. You use caching to store data that is consumed frequently by an application; you can also use it to store data that is expensive to create, obtain, or transform. There are three main benefits to implementing caching in your applications: Reduction of the amount of data that is transferred between processes and computers Reduction of the amount of data processing that occurs within the system Reduction of the number of disk access operations that occur ASP.NET Caching ASP offers the Session and Application objects, which enable storing key/value pairs in memory. The Session object is used to store per-user data across multiple requests, and the Application object is used to store per-application data for use by requests from multiple users. ASP.NET introduces a new key/value pair object the Cache object. The scope of the ASP.NET cache is the application domain; therefore, you cannot access it from other application domains or processes. The ASP.NET Cache objects life span is tied to the application, and the Cache object is re-created every time the application restarts, similar to the ASP Application object. The main difference between the Cache and

2 Application objects is that the Cache object provides cache-specific features, such as dependencies and expiration policies. ASP.NET provides two types of caching The first is called output caching, which allows you to store dynamic page and user control responses on any HTTP 1.1 cache-capable device in the output stream, from the originating server to the requesting browser. On subsequent requests, the page or user control code is not executed; the cached output is used to satisfy the request. The second type of caching is traditional application data caching, which you can use to programmatically store arbitrary objects, such as data sets, to server memory so that your application can save the time and resources it takes to recreate them. ASP.NET output caching The Cache object is defined in the System.Web.Caching namespace. You can get a reference to the Cache object by using the Cache property of the HttpContext class in the System.Web namespace or by using the Cache property of the Page object. You can also access cached information in a user control through the Cache property of the UserControl class. Adding Items to the Cache There are three different techniques you can use to add an item to the Cache object. If you want to take advantage of the scavenging, expiration, and dependency support offered by the cache, you must use either the Cache.Insert method or the Cache.Add method. The Add and Insert methods have the same signature, but there are subtle differences between them. o First, calling the Add method returns an object that represents the cached item, while calling Insert does not. o Second, their behavior is different if you call these methods and add an item to the cache that is already stored there. The Insert method replaces the item, while the Add method fails. To add an item to the Cache by specifying its key and value You can add items to the cache as you would add items to a dictionary by specifying the item's key and value. The following code adds the current Value property of a text box to the cache.
Cache("txt1") = txtName.value

To add items to the Cache by using the Insert method The Insert method is overloaded, allowing you to define values for the parameters of the version that you are using. For example, to add only an item key and value, use the following code. Cache.Insert("MyData1", connectionString) To add items to the Cache by using the Add method The Add method has the same signature as the Insert method, but it returns an object representing the item you added.
Cache.Add("MyData1", connectionString)

3 Dependency and Expiration File dependency Allows you to invalidate a specific cache item when a disk based file or files change. To add an item to the Cache that has a dependency You can add an item to the Cache with a dependency by using the dependencies parameter in the Add or Insert method. The following example demonstrates using the Insert method to add an item to the cache with a dependency on an XML file. Cache.Insert("MyData1", connectionString, new CacheDependency(Server.MapPath(\\myServer\myConfig.xml))) Key dependency Invalidates a specific cache item when another cached item changes. For example, when you cache basic data alongside calculation results on that data, the calculated data should be invalidated when the basic data changes or becomes invalid. The following example shows how to make one cache item dependent on another. // Create a cache entry. Cache["key1"] = "Value 1"; // Make key2 dependent on key1. String[] dependencyKey = new String[1]; dependencyKey[0] = "key1"; CacheDependency dependency = new CacheDependency(null, dependencyKey); Cache.Insert("key2", "Value 2", dependency); Time-based expiration To add an item to the Cache with expiration policies You can add an item to the Cache with expiration policies by using the absoluteExpiration parameter and the slidingExpiration parameter. You can define either an absolute expiration or a sliding expiration, but not both. When you define an expiration policy with one of the parameters mentioned, you must set the other parameter to 0. The Cache class defines two fields that do this automatically: NoAbsoluteExpiration and NoSlidingExpiration. Simply set the appropriate parameter to its corresponding field value when you define an absolute or sliding expiration. The following examples uses the Insert method to add an item to the Cache with an absolute expiration of two minutes.
Cache.Insert("MyData1", connectionString, null, DateTime.Now.AddMinutes(2), NoSlidingExpiration)

The following code uses the Insert method to add an item to the Cache with a sliding expiration of 30 seconds.
Cache.Insert("MyData1", connectionString, null, NoAbsoluteExpiration, TimeSpan.FromSeconds(30))

4 When you set an absolute expiration, use the DateTime structure. When you set a sliding expiration, use the TimeSpan structure. Also, if you create a sliding expiration that is less than zero or more than a year, an ArgumentOutOfRangeException Class is thrown. Using Cache CallBacks You can add a callback method to a cached item to execute when that item is removed from the cache. You can implement such a callback to ensure that the cached item is not removed from the cache or that the cache is updated based on new data. ASP.NET provides the CacheItemRemovedCallback delegate. It defines the signature to use when you write event handlers to respond when an item is deleted from the cache. ASP.NET also provides the CacheItemRemovedReason enumeration, which you can use to make event handlers dependent upon the reason the item is deleted. To notify an application when an item is deleted from the cache Create a local variable that raises the event for the CacheItemRemovedCallback delegate. For example, the following code creates an onRemove local variable of type CacheItemRemovedCallback.
private static CacheItemRemovedCallback onRemove = null;

The variable must be of this type to be used in the onRemoveCallback parameter of the Cache.Add or Cache.Insert method in step four. Create an event handler to respond when the item is removed from the cache. For example, the following code sets the static Boolean itemRemoved to true, and the static CacheItemRemovedReason reason to the value passed when the item is removed from the cache. Using the members of the CacheItemRemovedReason enumeration to create conditional code for the method in this step is an option open to you. Dim reason As CacheItemRemovedReason Public Sub RemovedCallback(key As String, value As Object, reason As CacheItemRemovedReason)
reason = r End Sub

This event handler must use the same signature as the CacheItemRemovedCallback delegate. This code assumes that you have created two static variables: itemRemoved of type Boolean and reason of type CacheItemRemovedReason. Create an instance of the CacheItemRemovedCallback delegate that calls the event handler. The following code calls the method created in step two.
onRemove = new CacheItemRemovedCallback(this.RemovedCallback);

Add the item to the Cache by using either the Cache.Add method or Cache.Insert method. You must specify the local variable, created in step one, in the onRemoveCallback parameter. The following code uses the Insert method to add an item to the cache with a key of "MyData1" and a value of Source. It defines the onRemove variable in the onRemoveCallback parameter. Cache.Insert("MyData1", Source, null, DateTime.Now.AddMinutes(2), NoSlidingExpiration, CacheItemPriority.High, onRemove); When the item added in step four is removed from the Cache for any reason, the RemovedCallback method is called, and the code within it can be accessed to render new content to a requesting client or to notify your application in a way you choose as appropriate.

Applying Priority to Cache Items When the server running your ASP.NET application runs low on memory resources, items are removed from cache to free memory in a process known as scavenging When memory is low, the cache determines which items are removed from cache based on priority. You can set the cache item priority when you add the item to the cache. Doing so controls which items scavenging removes first. You can also use the Add or Insert method to define the relative importance of the cached item by specifying a value from the CacheItemPriority enumeration. These relative priorities help the Web server when it scavenges to free memory. It can remove lower priority items from the Cache before higher priority items. To add an item to the Cache with priority settings You can add an item to the Cache with priority settings by using the priority parameter on the Add or Insert method. The following example uses the Add method to add an item to the Cache with a priority of High. Cache.Add("MyData1", connectionString, null, NoAbsoluteExpiration, TimeSpan.FromSeconds(30), CacheItemPriority.High, null) These methods also allow you to notify your application when the item is removed from the cache, using the CacheItemRemovedCallback delegate Retrieving Values from cached Items Retrieving data from the Cache is simple; you need to only specify the key and value that represent the data. You then write code to display the data on your page. To retrieve the value of a cached item The following code retrieves data that is assigned a key of MyData1 and a value of Source, verifies that the data still exists in the cache. It then displays the data in a DataGrid server control.
Dim Source As DataView Source = CType(Cache("MyData1"), DataView) If Not (Source Is Nothing) Then MyDataGrid.DataSource = Source MyDataGrid.DataBind() End If

6 To check for the existence of an item in the Cache A more complex situation is how your application responds when a data source or data set is not in the Cache. The following example modifies the code in the previous procedure to check for the cached data. If it is not in the cache, the example recreates it and adds it to the Cache.
Dim Source As DataView = CType(Cache("MyData1"), DataView) If Source Is Nothing Then Dim myConnection As New SqlConnection("server=localhost;uid=sa;pwd=;database=pubs") Dim myCommand As New SqlDataAdapter("select * from Authors", myConnection) Dim ds As New DataSet() myCommand.Fill(ds, "Authors") Source = New DataView(ds.Tables("Authors")) Cache("MyData1") = Source End If MyDataGrid.DataSource = Source MyDataGrid.DataBind()

Deleting Items From Cache There are several reasons for an item to be removed from an application's Cache. You can set expiration policies that determine the total amount of time the item remains in the cache (absolute expiration). You can also set expiration policies that are based on the amount of time that must pass following the previous time the item is accessed (sliding expiration). You can also specify files, directories, or keys that the item is dependent on. The item is removed from the Cache when those dependencies change. The server itself can remove an item from the Cache when it needs to free memory (scavenging). You have control over the priorities of cached items when this occurs. Any of these methods for removing items from the Cache are determined when you write code to add the item to the Cache using either the Cache.Add or Cache.Insert method. Additionally, you can explicitly remove items from the Cache by using the Cache.Remove method. You can use this method in event-handler code to respond to user input or some other input from your application. To delete an item from the Cache by using the Remove method The Remove method has one parameter that allows you to specify the key of the item you want to remove. For example, the following code removes an item assigned the MyData1 key.
[Visual Basic] Cache.Remove("MyData1")

Using an Output Cache You can use two types of output caching to cache information that is to be transmitted to and displayed in a Web browser: page output caching and page fragment caching. Page output caching caches an entire Web page and is suitable only when the content of that page is fairly static.

7 If parts of the page are changing, you can wrap the static sections as user controls and cache the user controls using page fragment caching. Page Output caching Page output caching adds the response of a given request to the ASP.NET cache object. After the page is cached, future requests for that page return the cached information instead of re-creating the entire page. You can use the page output cache to cache a variety of information, including: Static pages that do not change often and that are frequently requested by clients. Pages with a known update frequency. For example, a page that displays a stock price where that price is updated at given intervals. Pages that have several possible outputs based on HTTP parameters, and those possible outputs do not often change for example, a page that displays weather data based on country and city parameters. Results being returned from Web services.

[WebMethod(CacheDuration=60)] public string HelloWorld() { return "Hello World"; } Setting Expiration for Page Caching To set output-cache expirations for a page declaratively Include an @ OutputCache directive in the page (.aspx file) that you want to output cache. The directive must include a Duration attribute, with a positive numeric value, and a VaryByParam attribute. The following @ OutputCache directive sets the page's expiration to 60 seconds.
<%@ OutputCache Duration="60" VaryByParam="None" %>

You must include a VaryByParam attribute when using the @ OutputCache directive or a parser error will occur. If you do not want to use the functionality offered by the VaryByParam attribute, set its value to "None"

To set output-cache expirations for a page programmatically

In the page's code declaration block, or in the code-behind class for the page, include code that sets the expiration policy for the page by using Response.Cache syntax. The following example sets expirations for the page as the @ OutputCache directive does in the previous procedure.
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)) Response.Cache.SetCacheability(HttpCacheability.Public) Response.Cache.SetValidUntilExpires(True)

8 Once the duration for the cached page expires, the subsequent request for the page causes a dynamically generated response. This response page is cached again for the specified duration. Setting the cacheability of the page

The cacheability of a page or user control defines what HTTP 1.1 Internet devices a document can be cached on. These devices include the client making the request, the Web server responding to the request, and any cache-capable devices, such as proxy servers, that are in the request or response stream. When a Web server sends a response, it passes a Cache-Control HTTP header that, among other things, defines the devices on which the document can be cached. ASP.NET defines these values in the HttpCacheability enumeration. Depending on the needs of your application, you may choose to define which devices can and cannot cache specific pages. For example, you want to use different cacheability settings for a user logon page than for a page that displays a selection of products from a catalog. In the former case, for security reasons, you would want to cache the page on only the server, while the page in the latter scenario can, in all likelihood, be cached on any cache-capable device.

To set a page's cacheability declaratively Include an @ OutputCache directive in the .aspx file and define the required Duration and VaryByParam attributes. Include a Location attribute in the @ OutputCache directive and define its value as one of the supported values. These include Any, Client, Downstream, Server, or None. The default is Any. If you do not define a Location attribute, the page output can be cached on all cache-capable network applications that are involved in the response. These include the requesting client, the origin server, and any proxy servers through which the response passes To set a page's cacheability programmatically In the page's code-declaration block or code-behind class file, use Response.Cache syntax to access the HttpCachePolicy.SetCacheability method. The following code sets the Cache-Control HTTP header to Public. Response.Cache.SetCacheability(HttpCacheability.Public) Caching page output with cache key dependency

9 When you add pages to the output cache, the page will be removed when the amount of time you specify in the expiration policy has passed. There are times when you want a page, or versions of a page, to be removed from the output cache before it has expired. For example, if your page displays volatile data, such as a stock price or a temperature, the page will display incorrect information if the data is updated before the page expires. To address this issue ASP.NET provides the HttpResponse.AddCacheItemDependency and HttpResponse.AddCacheItemDependencies methods, which allow you to cache page output that is dependent upon an item in the Cache object. The AddCacheItemDependency method allows you to create a relationship between the page and a single item in the Cache, while the AddCacheItemDependencies method allows you to create relationship between the page and an array of Cache items. When any of the items the page is dependent upon change or are removed from the application Cache, the page output is invalidated and removed from the output cache. To make cached page output dependent upon a Cache item 1. Specify the settings for caching page output either declaratively or programmatically. 2. In the code-declaration block or the code-behind file for the page, use Response object syntax to call the AddCacheItemDependency or AddCacheItemDependencies method, specifying the cached item upon which the page is dependent. To use these methods, the argument passed to it must be the cache key specified for the cached item specified in the Cache.Item property call, the Cache.Add method call, or the Cache.Insert method call. The following example assumes that an application contains a temperature component. The component uses the Cache.Insert method to place a temperature into the application Cache.
[Visual Basic] Cache.Insert("Temperature.CurrentTemperature", currentTemperature)

The following page code, found in a code-declaration block or code-behind file, then gets the current temperature stored in the Cache, converts it to a string, and then displays it. It then makes its output cache version dependent upon the Temperature.CurrentTemperature key. From this point forward, when the temperature component updates the temperature, the page version is flushed from the output cache. The page will be placed in the output cache again when it is subsequently requested.
Dim temperature as Integer temperature = Cache.Get("Temperature.CurrentTemperature") LabelTemperature.Text = temperature.ToString() Response.AddCacheItemDependency("Temperature.CurrentTemperature")

10

Caching Multiple versions of a Page ASP.NET allows you to cache multiple versions of a page response. You can vary the output cache by query string or form POST parameters that are passed with a request, by the HTTP headers passed with a request, or by the major version of the browser that is making the request. You can also define a custom string in the page and implement how you want it to affect the response caching in your application's global.asax file. ASP.NET allows you to cache multiple versions of a page response declaratively by using attributes on the @ OutputCache directive and programmatically by using the properties and methods of the HttpCachePolicy class. Specifically, the @OutputCache directive includes three attributes that allow you to cache multiple versions of page output: The required VaryByParam attribute allows you to vary the cached output depending on GET query string or form POST parameters. The VaryByHeader attribute allows you to vary the cached output depending on the HTTP header associated with the request. The VaryByCustom attribute allows you to vary the cached output by browser type or by a custom string that you define. While you must include the VaryByParam attribute in any @ OutputCache directive, you can set its value to None if you do not want to use the functionality it provides. The HttpCachePolicy class provides two properties and a method that allow you to do the same things that the aforementioned attributes do. The Boolean VaryByParams and VaryByHeaders properties allow you to specify the parameter and header names, respectively, that you want to vary the cache by. The SetVaryByCustom method allows you to define custom strings to vary the output cache by. Caching versions of a page based on parameters If you use GET and POST HTTP methods to gather information from users, you know that they can generate different responses, depending on user input. GET requests with query strings and POST requests are associated with HTML forms, with which you can gather information from users. You can cache multiple versions of page responses, based on these parameters. To do this, you can use the @ OutputCache directive's VaryByParam attribute, or the HttpCachePolicy.VaryByParams property. To cache multiple versions of page output declaratively, based on query string or form POST parameters 1. Include an @OutputCache directive in the .aspx file that you want to cache. Be sure to set the required Duration attribute to a value greater than zero. 2. Use the VaryByParam attribute to set the query string or form POST parameter that you want to vary the page by.

11 Including the following example at the top of an .aspx file will cause different versions of page output to be cached for each request that arrives with a different City parameter value.
<%@ OutputCache duration="60" varybyparam="City" %>

If you want to vary the output cache by multiple parameters, define them in the VaryByParam attribute by using a semi-colon delimited list. If you want vary the cache by all the parameter values, set the attribute to an asterisk *.

To cache multiple versions of page output programmatically, based on query string or form POST parameters 1. In the page's code-declaration block or code-behind class, use Response.Cache syntax to set the expiration and visibility policies for the cached page content. You can accomplish this using the HttpCachePolicy.SetExpires and HttpCachePolicy.SetCacheability methods, respectively.

2. In the same code, specify the parameter name as the argument for the VaryByParams property, and set the property to true. The following code caches multiple versions of a page when requests arrive at the server with different City parameter values.
Response.Cache.VaryByParams("City") = true

If you want to vary the output cache by multiple parameters, include them in a semi-colon delimited list in the VaryByParams argument. If you want vary the cache by all the parameter values, set the attribute to an asterisk *. The following example demonstrates varying the page output by City and ZipCode parameters.
Response.Cache.VaryByParams("City;ZipCode") = true

The following discussion details how versions of a page are cached, depending upon incoming requests with different values that are passed in form POST or query string parameters. Your application contains an .aspx file, mycache.aspx, and you specify that different versions of the page should be cached, based on a city parameter. Four requests arrive with query strings attached: two with count parameters and four with city parameters.

12
http://www.microsoft.com/caching/mycache.aspx?count=10&city=dallas http://www.microsoft.com/caching/mycache.aspx?count=10&city=newyork http://www.microsoft.com/caching/mycache.aspx?city=dallas http://www.microsoft.com/caching/mycache.aspx?city=seattle

Since you instruct the output cache to vary by only the city parameter, three versions of the page's output are cached, one for dallas, one for newyork, and one for seattle. The first request, containing the dallas parameter value, causes a version of the page output to be cached, while the third request, also with the dallas parameter value, obtains the version of the page from the output cache. For the length of time that these versions remain in the cache, requests that contain city parameters with the value of dallas, new york, or seattle are satisfied from the output cache. If you vary the output cache by both the city and count parameters, four versions of the page output are cached. This is the case because the first entry contains a count query string parameter, while the third entry does not. If you vary the cache by all possible parameters, an output cache entry is created for each request with unique parameter values. In the current example, this also causes four versions of the page to be cached. GET query string or POST parameters with identical pairs of keys and values, regardless of the order that those parameters are passed, are satisfied by the cached version of the page for as long as it has not expired. Only if the parameter value is cased differently will ASP.NET treat the parameter as different from the original cached item and enter another version of the page in the output cache. Caching Versions of Page based on HTTP headers The @ OutputCache directive's VaryByHeader attribute and the HttpCachePolicy.VaryByHeaders property allow you to cache multiple versions of a page, dependent on the value of an HTTP header that you specify. You can specify a single header, multiple headers, or all headers passed to your application, when the page is requested. Depending upon the header or combination of headers you choose, multiple versions of the page's output is cached. To cache versions of a page declaratively, based on HTTP header values 1. Include an @OutputCache directive with the required Duration and VaryByParam attributes. The Duration attribute must be set to any integer greater than zero. If you do not want to use the functionality provided by the VaryByParam attribute, set its value to None. 2. Include the VaryByHeader attribute in the body of the @ OutputCache directive, with its value set to the name of the HTTP header that you want to vary the cache content by. The following example sets versions of a page to be cached, based on the value passed with the Accept-Language HTTP header.

13
<%@ OutputCache Duration="60" VaryByParam="None" VaryByHeader="Accept-Language" %>

If you want to vary the cached content by multiple headers, include a semicolon delimited list of header names. If you want to vary the cached content by all header values, set the VaryByHeader attribute equal to an asterisk *. To cache versions of a page programmatically, based on an HTTP header value 1. In the page's code-declaration block or code-behind class, use Response.Cache syntax to set the expiration and visibility policies for the cached page content. You accomplish this using the HttpCachePolicy.SetExpires and HttpCachePolicy.SetCacheability methods, respectively. 2. In the same code, specify the header name as the argument for the VaryByHeaders property, and set the property to true. The following code caches multiple versions of a page when requests arrive at the server that have different values assigned to the Accept-Language HTTP header.
Response.Cache.VaryByHeaders("Accept-Language") = true

If you want to vary the cache by multiple header values, set the VaryByHeaders property argument to a semicolon delimited list of valid HTTP header names. If you want to vary the pages in the cache by all HTTP header names, use the VaryByUnspecifiedParameters method. The following discussion assumes that a page's output is cached by using the code from one of the procedures in this topic. Four requests arrive for the page with the following Accept-Language headers.
de-lu en-us fr en-us

Since the second and fourth requests have the same Accept-Language HTTP header values, only the response generated for the first request is cached. The other two Accept-Language values generate page output versions that are also cached. A total of three documents are rendered and cached for these four requests. Any further requests for the page with the same Accept-Language values are satisfied from the output cache until the cached pages expire. This example demonstrates how to cache the page output of globalized content, depending upon the locale settings for the requesting browser. Caching Versions of the page based on the Requesting browser You can use the @ OutputCache directive's VaryByCustom attribute or the HttpCachePolicy.SetVaryByCustom method to vary the versions of page output by the major version of the browser that requests the page. This major version and browser type

14 information is passed through the HttpBrowserCapabilities.MajorVersion property associated with the current request. You could access this information through the Request object associated with the page, but it is simpler to use the built-in functionality offered by ASP.NET. To cache multiple versions of a page output declaratively based on browser type 1. In the .aspx file, include an @OutputCache directive with the required Duration and VaryByParam attributes. The Duration attribute must be set to any integer greater than zero. If you do not want to use the functionality provided by the VaryByParam attribute, you must set its value to None. 2. In the body of the @OutputCache directive, include the VaryByCustom attribute and set it to browser.
<%@ OutputCache Duration="10" VaryByParam="None" VaryByCustom="browser" %>

To output cache multiple versions of a page programmatically, based on custom strings 1. In the page's code-declaration block or code-behind class, use Response.Cache syntax to set the expiration and visibility policies for the cached page content. You accomplish this by using the HttpCachePolicy.SetExpires and HttpCachePolicy.SetCacheability methods, respectively. 2. In the same code, specify browser in the custom parameter of the SetVaryByCustom method.
Response.Cache.SetVaryByCustom("browser")

Regardless of which of these techniques you use, when you specify browser, ASP.NET automatically caches versions of the page output based on the browser name and major version information passed in the Request.Browser.Type property, with the current request. This information is available through the HttpContext class associated with the request. For example, when an Internet Explorer 5 browser requests a page, the version of the page is cached for the string value "IE5" that is passed in the Type property for the request. When a Netscape Navigator browser, another version of Internet Explorer, or any other browser requests the page, another version of the page is added to the output cache. Configuring the Output Cache Location You can control the location of your output cache by using the Location attribute of the @OutputCache directive. The Location attribute is supported only for page output caching and not for page fragment caching. You can use it to locate the cache on the originating server, the client, or a proxy server.

15 Configuring Page Output Caching You can configure the cache both declaratively (using page directives) and programmatically (using the cache API). The declarative method can meet most of common requirements for configuring a cache, but the cache API includes some additional functionality, such as the ability to register callbacks. The following example shows how to declaratively configure the cache using page directives in the ASP.NET page header. <%@ OutputCache Duration="20" Location="Server" VaryByParam="state" VaryByCustom="minorversion" VaryByHeader="Accept-Language"%> The following example shows how to programmatically configure the cache using the cache API. private void Page_Load(object sender, System.EventArgs e) { // Enable page output caching. Response.Cache.SetCacheability(HttpCacheability.Server); // Set the Duration parameter to 20 seconds. Response.Cache.SetExpires(System.DateTime.Now.AddSeconds(20)); // Set the Header parameter. Response.Cache.VaryByHeaders["Accept-Language"] = true; // Set the cached parameter to 'state'. Response.Cache.VaryByParams["state"] = true; // Set the custom parameter to 'minorversion'. Response.Cache.SetVaryByCustom("minorversion"); } Using Page Fragment Caching Page fragment caching involves the caching of a fragment of the page, as opposed to the entire page. Sometimes full page output caching is not feasible for example, when portions of the page need to be dynamically created for each user request. In such cases, it can be worthwhile to identify portions of the page or controls that do not often change and that take considerable time and server resources to create. After you identify these portions, you can wrap them in a Web Forms user control and cache the control so that these portions of the page dont need to be recreated each time. Determining What to Cache with Page Fragment Caching Page fragments (controls) that require high server resources to create. Sections on a page that contain static data.

16 Page fragments that can be used more than once by multiple users. Page fragments that multiple pages share, such as menu systems.

Configuring Page Fragment Caching Once you identify the portions of the page that you want to cache, and create the user controls that encapsulate each of those portions, you must determine the caching policies for the user controls. You can set these policies declaratively, using the @ OutputCache directive, or programmatically, using the PartialCachingAttribute class when creating your user control in a code-behind class. For example, if you include the following directive at the top of a user control file, a version of the control is stored in the output cache for 120 seconds.
<%@ OutputCache Duration="120" VaryByParam="None" %>

Similarly, if you develop your user control using the code-behind development method, including the following attribute in the metadata of your class declaration stores a version of the control in the output cache for 120 seconds.
<PartialCaching(120)>

Using either of these techniques, when the page that contains the user control is requested, only the user control is cached. Caching Multiple versions of the User Control Output You can also cache multiple versions of a user control on a page by declaring it more than once in its containing .aspx file. The @ OutputCache directive supports two attributes, VaryByParam and VaryByControl, that allow you to cache multiple versions of user control output, based on GET query string or form POST parameters. The PartialCachingAttribute class includes two properties, VaryByParams and VaryByControls, that allow you to do the same thing by adding an attribute to a user control in a code-behind class. There are some major differences between adding user control output to the output cache and doing the same for page output. While both support using GET query string and form POST parameters to create and cache multiple versions of output, user controls do not support caching based on HTTP headers or custom strings. There are three techniques you can use to vary output cached user controls: The VaryByParam attribute or the PartialCachingAttribute.VaryByParams property requires you to specify the ID of the user control, along with the parameter

17 name, so that the user control is parsed correctly. For example, if you developed a user control and gave it an ID of Authors, to vary it by parameter you must specify Authors.City in one of these techniques. The VaryByControl attribute or PartialCachingAttribute.VaryByControls property allow you to define only the parameter name, providing a shortcut to vary user control output by. These techniques allow you to declare City, from the previous example, as the parameter the user control will vary by. Additionally, the user control must contain all the code that processes the request on post back in order for these techniques to work. You can do this in an OnClick or OnServerClick method handler contained in the code for the user control. The post back cannot occur on the page that contains the user control. The third technique is to include a string property for the user control when you create it. Once you have done this, you can then declare that property as an attribute in the user control's tag when you declare the user control in its containing .aspx file. While this does not output cache multiple versions of the user control, it does allow you to output cache multiple versions of the user control on the same page. Simply declare different attribute values for each instance of the control. Caching Multiple Version of UserControl Based on Parameters You can vary user control output to the cache by specifying either the user control name and the parameter, or simply the parameter. For the former, use the VaryByParam attribute of the @ OutputCache directive or include the VaryByParams property in the PartialCachingAttribute located in the user control's code-behind file. For the latter, use the VaryByControl attribute or include the VaryByControls property in the PartialCachingAttribute. Varying user control output to the cache based on parameters will only work if the user control posts back and processes the postback itself. You cannot post back to the containing page and expect this type of caching of user control output to function properly. To cache multiple versions of a user control declaratively by using the VaryByControl attribute 1. Create a user control that posts back. 2. Include an @ OutputCache directive in the .ascx file with Duration and VaryByControl attributes. If you include use the VaryByControl attribute in the directive, you do not need to include the VaryByParam attribute.

18 3. Set the VaryByControl attribute to the name of the query string or form POST parameter that you want to vary the user control output by in the output cache. For example, the following @ OutputCache directive sets expirations for the user control to 60 seconds and varies the control's output by a state parameter.
<%@ OutputCache Duration="60" VaryByControl="State" %>

To cache multiple versions of a user control programmatically by using the VaryByControls property 1. In a code-behind class, create user control code that posts back. 2. Include a metadata PartialCaching attribute at the beginning user control code. 3. Include a value for the duration parameter and set the varybycontrols parameter to the query string or form POST parameter that you want to vary the user control output by. When included before the code that extends the UserControl class, the following example sets duration to 60 seconds and varybycontrols to State.
<PartialCaching(60, null, State, null)>

To cache multiple versions of a user control declaratively by using the VaryByParam attribute 1. Create a user control that posts back. 2. Include an @ OutputCache directive in the .ascx file with Duration and VaryByParam attributes. If you include the VaryByControl attribute in the @OutputCache directive for a user control, you do not need to include the VaryByParam attribute. Regardless of which attribute you include, set its value to None if you do not want to use the functionality it provides. 3. Set the VaryByParam attribute to the user control name appended to the beginning of the query string or form POST parameter that you want to vary the user control by. For example, the following @ OutputCache directive sets expirations for the user control to 60 seconds and varies the control's output by a State parameter. However, it includes Control1 as the name of the user control.
<%@ OutputCache Duration="60" VaryByParams="UserControl1.State" %>

To cache multiple versions of a user control programmatically by using the VaryByParams property

19 1. In a code-behind class, create user control code that posts back. 2. Include a metadata PartialCaching attribute at the beginning of the user control code. 3. Include a value for the duration parameter and set the varybyparams parameter to the user control name and the query string or form POST parameter that you want to vary the user control output by. When included before the code that extends the UserControl class, the following example sets duration to 60 seconds and varybyparams to Control1.State.
<PartialCaching(60, Control1.State, null, null)>

The following example demonstrates a user control that posts back to itself by including the code for a ServerClick event in the code-declaration block of the control. It also demonstrates using the VaryByControl parameter to vary user control output to the output cache, based on the State and Country form POST parameters associated with the two DropDownList server controls contained in the user control. To use it, name the user control file sample.ascx. It also includes a simple .aspx file that contains the user control.
<%@ Language="VB" %> <%@ OutputCache Duration="10" VaryByControl="State;Country" %> <%@ import namespace="System.Globalization"%> <script runat=server> Public Property Here() As String Get Return State.SelectedItem.Text End Get Set State.SelectedItem.Text = Here End Set End Property Public Property There() As [String] Get Return Country.SelectedItem.Text End Get Set Country.SelectedItem.Text = There End Set End Property Sub SubmitBtn_Click(Sender as Object, e as EventArgs) Label1.Text="You chose: " & state.SelectedItem.Text & " and " & country.SelectedItem.Text TimeMsg.Text = DateTime.Now.ToString("T") End Sub </script> <asp:DropDownList id=state runat="server"> <asp:ListItem> </asp:ListItem>

20
<asp:ListItem>Idaho</asp:ListItem> <asp:ListItem>Montana</asp:ListItem> <asp:ListItem>Nevada</asp:ListItem> <asp:ListItem>Oregon</asp:ListItem> <asp:ListItem>Washington</asp:ListItem> <asp:ListItem>Wyoming</asp:ListItem> </asp:DropDownList>

<br>

<asp:DropDownList id=country runat="server"> <asp:ListItem> </asp:ListItem> <asp:ListItem>Austria</asp:ListItem> <asp:ListItem>France</asp:ListItem> <asp:ListItem>Italy</asp:ListItem> <asp:ListItem>Germany</asp:ListItem> <asp:ListItem>Spain</asp:ListItem> <asp:ListItem>Switzerland</asp:ListItem> </asp:DropDownList> <br> <asp:button text="Submit" OnClick="SubmitBtn_Click" runat=server/> <br> <asp:Label id=Label1 font-name="Verdana" font-size="10pt" runat="server"> Select values from the lists </asp:Label> <br> <br> Control generated at: <asp:label id="TimeMsg" runat="server" /> </script> [*.aspx] <%@ Register TagPrefix="Sample" TagName="Places" Src="sample.ascx" %> <form runat=server> <Sample:Places id="Control1" runat=server /> </form>

Caching Multiple Versions of User Control By Using Declarative Attributes You can cache multiple versions of a user control by simply declaring it in a .aspx file more than once. In order to avoid clashing instances of the control on the page at the same time, you must include a String property in the user control code. Additionally, you must declare this property and its value as an attribute in the custom server control element that you use to include the user control in the .aspx file. For example, if you create a user control with a category property, you need to declare category as an attribute on the user control tag. Assign the attribute a value that is meaningful to your purposes. To cache multiple versions of a user control by using declarative attributes

21 1. In the code-declaration block of an .ascx file, or in the code-behind class for the user control, create a String property. This is in addition to any other user control code you plan to include. 2. Using either the @ OutputCache directive in an .ascx file or the PartialCachingAttribute in the code-behind class, specify the output cache settings for the user control. 3. Include multiple versions of the user control in a page, including the property you defined in the class as an attribute in the element. Make sure the property values are unique on the page. For example, you can include the following user control tags in the containing .aspx file with the custom Category attribute.
<MyUserControl:Menu Category="LeftMenu" runat="server" /> <MyUserControl:Menu Category="RightMenu" runat="server" />

The user control below contains the Category property that allows you to include it in the attribute in the custom server tags above.
<%@ OutputCache Duration="120" VaryByParam="None" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <script language="VB" runat="server"> Dim Category As String Sub Page_Load(sender As Object, e As EventArgs) Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter Dim ds As DataSet MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=y es") MyCommand = New SqlDataAdapter("select * from Authors", MyConnection) ds = New DataSet() MyCommand.Fill(ds, "Authors") MyDataGrid.DataSource=new DataView(ds.Tables(0)) MyDataGrid.DataBind() End Sub </script> <asp:datagrid id="MyDataGrid" runat=server/>

Simply including the @ OutputCache directive with a valid duration value in the .ascx file allows varied cache output of this user control. Using Remoting Singleton Caching Microsoft .NET remoting provides a rich and extensible framework for objects

22 executing in different AppDomains, in different processes, and on different computers to communicate seamlessly with each other. Microsoft .NET remoting singleton objects service multiple clients and share data by storing state information between client invocations. You can use .NET remoting when you need a custom cache that can be shared across processes in one or several computers. To do this, you must implement a caching service using a singleton object that serves multiple clients using .NET remoting. To implement a cache mechanism using .NET remoting, ensure that the remote object lease does not expire and that the remoting object is not destroyed by the garbage collector. An object lease is the period of time that a particular object can remain in memory before the .NET remoting system begins to delete it and reclaim the memory. When implementing a remoting singleton cache, override the InitializeLifetimeService method of MarshalByRefObject to return null. Doing so ensures that the lease never times out and the object associated with it has an infinite lifetime. The following example shows how to cause your object to have infinite lifetime. public class DatasetStore : MarshalByRefObject { // A hash table-based data store private Hashtable htStore = new Hashtable(); //Returns a null lifetime manager so that GC won't collect the object public override object InitializeLifetimeService() { return null; } // Your custom cache interface } This code ensures that the garbage collector does not collect the object by returning a null lifetime manager for the object. You can implement the remoting singleton as a caching mechanism in all layers of a multilayer architecture. However, because of the relatively high development cost of its implementation, youre most likely to choose this solution when a custom cache is needed in the application and data tiers. Using Static Variables for Caching Static variables are often used to save class state, and you can use them to create customized cache objects. To do so, declare your cache data store as a static variable in your custom-developed cache class, and implement interfaces to insert, remove, and access items in the data store. Using static variables is simple if no special cache capabilities are needed, such as dependencies, expiration, and scavenging. Because the cache is an in-memory

23 system, static variables provide fast, direct access to the cached data. Static variable caching is useful to store state when other mechanisms are not available or are too costly. Use a static variable cache when you do not have another key/value dictionary available or when you need a fast in-process caching mechanism. In ASP.NET applications, use the Cache object instead. You can use static variables to cache large data items, provided that the items do not often change. Because there is no mechanism for invalidating items, obsolete large items can waste valuable memory. When using a static variable cache, you must ensure that you either implement your own thread safety mechanism or use a .NET Framework object that can be synchronized, for example, a Hashtable object. The following example shows how to implement a static variable cache by using a hash table. static Hashtable mCacheData = new Hashtable(); The scope of the static variables can be limited to a class or a module or be defined with project-level scope. If the variable is defined as public in your class, it can be accessed from anywhere in your project code, and the cache will be available throughout the application domain. The lifetime of static variables is directly linked to their scope. Using ASP.NET Session State You can use ASP.NET session state (based on the HttpSessionState class) to cache per-user session state. It solves many of the limitations that are inherent in ASP session state, including: The ASP session state is tied to the ASP hosting process, and as such is recycled when the ASP process is recycled. You can configure ASP.NET session state to avoid this. ASP session state has no solution for functioning in a Web server farm. The ASP.NET session state solution does not provide the best results when scalability and availability are important, but it works well for small scalar values, such as authentication information. ASP session state depends on the client browser accepting cookies. If cookies are disabled in the client browser, session state cannot be used. ASP.NET session state can be configured not to use cookies.

24

Implementing Session State ASP.NET session state provides a simple interface for adding and removing variables and simple configuration using the Web.config file. Changes to this file are reflected immediately without the need to restart the ASP.NET process. The following example shows how to implement SQLServer mode session caching in the Web.config file. <sessionState mode="SQLServer" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1; Integrated Security=SSPI" cookieless="false" timeout="20" /> The following example shows how you can use the session object to store and access user credentials. private void SaveSession(string CartID) { Session["ShoppingCartID"] = CartID; } private void CheckOut() { string CartID = (string)Session["ShoppingCartID"]; if(CartID != null) { // Transfer execution to payment page. Server.Transfer("Payment.aspx"); } else { // Display error message. } } Using ASP.NET Client-Side Caching and State You can reduce the workload on your server by storing page information using client-side options. This approach has minimal security support but results in faster server performance because the demand on server resources is modest. Because you must send information to the client before it can be stored, there is a practical limit on how much information you can store this way. The main mechanisms to implement client-side caching are: Hidden fields View state

25 Hidden frames Cookies Query strings

Each of these mechanisms is useful for caching different types of state in different scenarios. Using Hidden Fields You can store page-specific information in a hidden field on your page to maintain the state of that page. It is best to store only small amounts of frequently changing data in hidden fields because this data is included in the roundtrips to the server on every postback. Storing a large amount of data slows your application because of network traffic load. ASP.NET provides the HtmlInputHidden control, which offers hidden field functionality. Benefits and Limitations of Hidden Fields The benefits of using hidden fields to store client-side state include: No server resources are required. The hidden field is stored and read directly from the page. Almost all browsers and client devices support forms with hidden fields. Hidden fields are simple to implement. Hidden fields are good for caching data in Web farm configurations because the data is cached on the client.

The limitations of using hidden fields are: The hidden field can be tampered with. The information in this field can be seen if the page output source is viewed directly, creating a potential security issue. The hidden field does not support rich structures; it offers only a single value field in which to place information. To store multiple values, you must implement delimited strings and write the code required to parse those strings. Page performance decreases when you store large values because hidden fields are stored in the page.

Hidden fields are a good solution for caching small amounts of noncritical, string data for use in Web pages. Implementing Hidden Fields The following example shows how to declare a hidden field on a Web page.

26 <input id="HiddenValue" type="hidden" value="Initial Value" runat="server" NAME="HiddenValue"> This code creates a hidden field containing the string data Initial Value. Using View State Web Forms pages and controls all have a ViewState property, which is a built-in structure for automatically retaining values among multiple requests for the same page. The view state is internally maintained as a hidden field on the page but is hashed, providing greater security than developer-implemented hidden fields do. You can use view state to store your own page-specific values across roundtrips when the page posts back to itself. For example, if your application is maintaining userspecific information, such as a user name that is displayed in a welcome message, you can store the information in the ViewState property. Performance of view state varies depending on the type of server control to which it is applied. Label, TextBox, CheckBox, RadioButton, and HyperLink are server controls that perform well with ViewState. DropDownList, ListBox, DataGrid, and DataList suffer from poor performance because of their size and the large amounts of data making roundtrips to the server. In some situations, using view state is not recommended because it can degrade performance. For example: Avoid using view state in pages that do not post back to the server, such as logon pages. Avoid using view state for large data items, such as DataSets, because doing so increases time in roundtrips to the server. Avoid using view state when session timeout is required because you cannot time out data stored in the ViewState property.

View state is a simple and easy-to-use implementation of hidden fields that provides some security features. Most of the performance considerations, benefits, and limitations of view state and hidden fields are similar. Benefits and Limitations of View State The benefits of using view state include: No server resources are required because state is contained in a structure in the page code. It is simple to implement. Pages and control state are automatically retained. The values in view state are hashed, compressed, and encoded, thus representing a higher state of security than hidden fields.

27 View state is good for caching data in Web farm configurations because the data is cached on the client.

Limitations to using view state include: Page loading and posting performance decreases when large values are stored because view state is stored in the page. Although view state stores data in a hashed format, it can still be tampered with because it is stored in a hidden field on the page. The information in the hidden field can also be seen if the page output source is viewed directly, creating a potential security risk.

Implementing View State The following example shows how to use the ViewState property to store and access user-specific information between page postbacks. public class ViewStateSample : System.Web.UI.Page { private void Page_Load(object sender, System.EventArgs e) { if (!Page.IsPostBack) { // Save some data in the ViewState property. this.ViewState["EnterTime"] = DateTime.Now.ToString(); this.ViewState["UserName"] = "John Smith"; this.ViewState["Country"] = "USA"; } } private void btnRefresh_Click(object sender, System.EventArgs e) { // Get the saved data in the view state and display it. this.lblTime.Text = this.ViewState["EnterTime"].ToString(); this.lblUserName.Text = this.ViewState["UserName"].ToString(); this.lblCountry.Text = this.ViewState["Country"].ToString(); } } Using Hidden Frames You can use hidden frames to cache data on the client, avoiding the roundtrips to the server that are inherent in hidden field and view state implementations. You create a hidden frame in your page that loads a Web page into the frame containing your data. The pages in your application can access this data using client-side scripting. This implementation does not require any server resources because the data fields in the hidden frame are stored and read directly from the page. Hidden frames let you secretly

28 load images for use on other pages within the site. When those images are required, they can be obtained from the client cache rather than from the server. Benefits and Limitations of Hidden Frames The benefits of using hidden frames to store client-side state include: The ability to cache more than one data field. The avoidance of roundtrips of data during postbacks. The ability to cache and access data items stored in different hidden forms. The ability to access JScript variable values stored in different frames if they come from the same site.

The limitations of using hidden frames are: Functionality of hidden frames is not supported by all browsers. Do not rely on hidden frames to provide data for the essential functionality of your pages. The hidden frame can be tampered with, and the information in the page can be seen if the page output source is viewed directly, creating a potential security threat. There is no limit to the number of frames (embedded or not) that you can hide. In frames that bring data from the database and that contain several Java applets or images, a large number of frames can negatively affect performance of the first page load. Hidden frames are useful for storing many items of data and resolve some of the performance issues inherent in hidden field implementations. Implementing Hidden Frames The following example shows how to declare a hidden frame in a Web page. <FRAMESET cols="100%,*"> <FRAMESET rows="100%,*"> <FRAME src="contents_of_frame1.html"> </FRAMESET> <FRAME src="contents_of_hidden_frame.html"> <FRAME src="contents_of_hidden_frame.html" frameborder="0" noresize scrolling="yes"> <NOFRAMES> <P>This frameset document contains: <UL> <LI> <A href="contents_of_frame1.html" TARGET="_top"> Some neat contents</A> <LI> <A href="contents_of_hidden_frame.html" TARGET="_top"> Some other neat contents</A> </UL> </NOFRAMES>

29 </FRAMESET> You can then use the data stored in this frame in your Web page by using client-side scripting. Using Cookies You can use cookies to store small amounts of infrequently changing information on the client. That information can then be included in a request to the server. Benefits and Limitations of Cookies Cookies are useful because: No server resources are required. The cookie is stored on the client, sent to the server in a request, and then read by the server after the post. They are simple to use. The cookie is a lightweight, text-based structure containing simple key/value pairs. They support configurable expiration. The cookie can expire when the browser session ends, or it can exist indefinitely on the client computer, subject to the expiration rules on the client. The use of cookies may be limited by: Size restrictions. Most browsers place a 4096-byte limit on the size of a cookie, although support for 8192-byte cookies is becoming more common in the new browser and client-device versions available today. User-configured refusal. Some users disable their browser or client devices ability to receive cookies, thereby limiting the use of cookies. Security breaches. Cookies can be subject to tampering. Users can manipulate cookies on their computer, which can potentially represent a security compromise or cause a cookie-dependent application to fail. Possible expirations. The durability of the cookie on a client computer is subject to cookie expiration processes on the client and to user intervention. Implementing Cookies The following example shows how to store and retrieve information that cookies hold. public class CookiesSample : System.Web.UI.Page { private void Page_Load(object sender, System.EventArgs e) { if (this.Request.Cookies["preferences1"] == null) { HttpCookie cookie = new HttpCookie("preferences1"); cookie.Values.Add("ForeColor","black"); cookie.Values.Add("BackColor","beige");

30 cookie.Values.Add("FontSize","8pt"); cookie.Values.Add("FontName","Verdana"); this.Response.AppendCookie(cookie); } } private string getStyle(string key) { string val = null; HttpCookie cookie= this.Request.Cookies["preferences1"]; if (cookie != null) { val = cookie.Values[key]; } return val; } } Never rely on cookies for essential functionality in your Web applications, because users can disable them in their browsers. Using Query Strings A query string is information sent to the server appended to the end of a pages URL. You can use a query string to submit data back to your page or to another page through the URL. Query strings provide a simple but limited way of maintaining some types of state information. For example, they make it easy to pass information from one page to another, such as passing a product number to another page, where it is processed. Query strings are a viable option only when a page is requested through its URL using HTTP GET. You cannot read a query string from a page that has been submitted to the server using HTTP POST. Benefits and Limitations of Query Strings Query strings offer the following benefits: No server resources are required. The query string is contained in the HTTP request for a specific URL. They provide broad support. Almost all browsers and client devices support passing values in a query string. They are simple to implement. ASP.NET provides full support for the query string method, including methods for reading query strings using the HttpRequest.Params property.

Query strings do have some limitations; for example:

31 The information in the query string is directly visible to the user in the browser user interface. The query values are exposed to the Internet in the URL, so in some cases, security might be an issue. Most browsers and client devices impose a 255-character limit on URL length. Query strings can be very useful in certain circumstances, such as when you are passing parameters to the server to customize the formatting of the data returned.

Implementing Query Strings The following example shows how to include a query string in a URL. http://www.cache.com/login.asp?user=ronen The following example shows how to access the information at the server. // Check for a query string in a request. string user = Request.QueryString["User"]; if( user != null ) { // Do something with the user name. } Query strings enable you to send string information directly from the client to the server for server-side processing. Summary : Hidden fields : To store small amounts of information for a page that posts back to itself or to another page when security is not an issue. You can use a hidden field only on pages that are submitted to the server. View state To store small amounts of information for a page that posts back to itself.Using view state provides basic security. Hidden frames To cache data items on the client and to avoid the roundtrips of the data to the server. Cookies To store small amounts of information on the client when security is not an issue. Query strings To transfer small amounts of information from one page to another when security is not an issue. You can use query strings only if you are requesting the same page or another page using a link. You must consider various coding implementation issues when planning to cache .NET Framework elements in your applications. Such issues include: Ensuring thread safety

32 Cloning Serializing Normalizing cached data

Ensuring Thread Safety When you write multithreaded applications, you must ensure that threads interact properly. For example, when a program or routine can be called from multiple threads, you must ensure that the activities of one thread do not corrupt information required by another. A routine is considered thread safe when it can be called from multiple programming threads without unwanted interaction among them. When you are caching data types that are type safe, you can eliminate the risk that one thread will interfere and modify data elements of another thread through coordinated access to shared data, thus circumventing potential data race situations. If your code is not thread safe, the following can occur: A cached item is read from the cache on one thread and then updated on another, resulting in the use of inconsistent data. A cached item is flushed from the cache by one thread while a client using another thread tries to read the item from cache. Two or more threads concurrently update a cached item with different values. Remove requests result in an item being removed from the cache while it is being read by another thread. You can avoid these problems by ensuring that your code is thread safe, allowing only synchronized access to the cached data. You can do so either by implementing locking in the caching mechanism or by using the ReaderWriterLock class in the cache items. Implementing Thread Safety Using the Cache You can implement thread safety by using the following methods when using a cache: Action-level locking You can implement thread safety in the Insert, Update, Get, and Delete cache interfaces. In this scenario, the cache automatically locks an item when it is added to the cache or updated. Cache-level locking You can provide Lock and Unlock methods that the client code uses when thread safety is needed. The client needs to call the Lock method before updating the cached item and call Unlock afterward. Implementing Thread Safety in the Cached Items If your chosen caching mechanism does not provide thread safety, you can implement thread safety directly in your cached objects by using the ReaderWriterLock class from the System.Threading namespace in the .NET Framework. The following example shows how you can use the ReaderWriterLock class to implement thread safety in cached items.

33 class Resource { ReaderWriterLock rwl = new ReaderWriterLock(); Object m_data; // Your class data public void SetData(Object data) { rwl.AcquireWriterLock(Timeout.Infinite); // Update your object data. rwl.ReleaseWriterLock(); } public Object GetData() { // Thread locks if other thread has writer lock rwl.AcquireReaderLock(Timeout.Infinite); // Get your object data... rwl.ReleaseReaderLock(); return m_data; } } Ensuring thread safety of cached items guarantees synchronized access of the items and avoids such issues as dirty reads and multiple writes. Cloning Another solution to thread safety and synchronization issues is to use cloning. Instead of obtaining a reference to the original copy of your object when retrieving cached items, your cache can clone the object and return a reference to the copy. To do so, your cached objects must implement the ICloneable interface. This interface contains one member, Clone(), which returns a copy of the current object. Take care to implement a deep copy of your object, copying all class members and all objects recursively referenced by your object. If you design your cache to include interfaces for receiving both a cloned object and a reference to the original cached object, you will find new possibilities for resolving synchronization issues in your application: If your object is not thread safe, you can use cloning to create a copy of your cached data, update it, and then update the cache with the new object. This technique solves synchronization issues when data is updated. In this scenario, updating the cached item is performed as an atomic action, locking the access to the object during the update. One process can be responsible for updating an object while another process uses a cloned copy of the object for read-only purposes. This solves the problem of synchronizing read-after-write operations on your cache because the read object is merely a copy of the cached object, and the original object can be updated at

34 the same time. Example 1. Process A gets a clone of a cached object and updates the cloned object. 2. Process B gets a read-only clone of the cached object. 3. Process A updates the object in cache from its cloned copy without affecting the copy process that B is using. The next time process B requests the object, it receives the new version of the object that process A updated. Serializing a .NET Class When sharing a cache between several processes or across an application farm, the cached items must be serialized when being inserted into the cache and deserialized when retrieved. An example of this is when you are storing ASP.NET session state in a SQL Server database. Because memory cannot be shared between two processes or between two computers,your cached object must be converted into a format such as XML or a binary representation to transport it between the memory locations. Consider this fact when designing your .NET classes, and if you plan to use a caching technology that requires objects to be serialized, you must make your .NET class serializable. You can do so by using the Serializable attribute or by custom serializing your classes by implementing the ISerializable interface. The following example shows how to use the Serializable attribute to make a class serializable. [Serializable] public class MyClass { } The following example shows how to custom serialize a .NET class by implementing the ISerializable interface. public class MyClass1: ISerializable { public int size; public String shape; //Deserialization constructor public MyClass1 (SerializationInfo info, StreamingContext context) { size = (int)info.GetValue("size", typeof(int)); shape = (String)info.GetValue("shape", typeof(string)); } //Serialization function public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("size", size);

35 info.AddValue("shape", shape); } } It is recommended that you implement ISerializable instead of using the Serializable attribute because ISerializable does not use reflection and results in better performance. Normalizing Cached Data When you are caching data, store it in the format in which clients use it; this is known as normalizing cached data. Normalizing cached data is a process in which an object is constructed once and then accessed as needed rather than being constructed anew each time it is accessed. For example, if you are caching a polygon for display in your applications user interface, and the polygon details are saved in a database as a set of points, do not cache these points in the user interface. Instead, construct the polygon class, and cache that object. By definition, normalizing cached data involves transforming your cached data to the format that is needed for later use. When you normalize your cached data, you ensure that: You can easily retrieve and use data from the cache; no formatting or deserialization is required. Repetitive transformation of the data each time it is retrieved from the cache is avoided. This definition of normalization differs from the classic data processing definition of the term, which is concerned with saving the data in the most efficient and memory-saving form. When you consider normalizing cached data, your first priority is usually performance rather than memory. Implementing .NET Framework Element Caching Caching Connection Strings Database connection strings are difficult to cache because of the security issues involved in storing credentials that are used to access your database for example, in Machine.config or Web.config because the .NET Framework automatically caches the configuration files. However, because the configuration files are stored as clear ASCII text files, encrypt your connection strings before entering them in the configuration files and then decrypt them in your application before using them. Caching DataSet Objects DataSet objects are excellent caching candidates because: They are serializable and as such can be stored in caches either in the same process or in another process. They can be updated without needing to reinsert them into the cache. Because you cache a reference to your DataSet, your application can update the data without the reference in the cache needing to change.

36 They store formatted data that is easily read and parsed by the client.

Caching frequently used DataSet objects in your applications often results in improved performance. Caching DataReader Objects Never cache DataReader objects. Because a DataReader object holds an open connection to the database, caching the object extends the lifetime of the connection, affecting other users of the database. Also, because the DataReader is a forwardonly stream of data, after a client has read the information, the information cannot be accessed again. Caching it would be futile. Caching DataReader objects disastrously affects the scalability of your applications. You may hold connections open and eventually cache all available connections, making the database unusable until the connections are closed. Never cache DataReader objects no matter what caching technology you are using. Also do not cache SqlDataAdapter objects because they use DataReader objects in their underlying data access method. Caching XML Schemas The .NET Framework includes the XmlSchemaCollection class that can help cache XML-Data Reduced (XDR) and XML Schema Definition language (XSD) schemas in memory instead of accessing them from a file or a URL. This makes the class a good caching candidate. The XmlSchemaCollection class has methods for adding schemas to the collection, checking for the existence of a schema in the collection, and retrieving a schema from the collection. You can also use the XmlSchemaCollection to validate an XML document against XSD schema. The XmlSchemaCollection improves performance by storing schemas in the cached collection so that they do not need to be loaded into memory each time validation occurs. Caching Windows Forms Controls Caching Windows Forms controls in your user interface can improve responsiveness of the user interface. Because Windows Forms controls that include structured data require you to populate them with the necessary data before displaying them to the user, applications may appear sluggish. However, because it is the data loading that takes a long time, caching the populated version of these controls improves performance . A static variable cache is the natural choice for caching Windows Forms controls because it has the following attributes: Application scope Your Windows Forms controls are used within the scope of your Windows-based application, which matches the scope of your cache. Simple implementation A static variable cache is an ideal choice for a simple caching implementation if you do not need advanced features such as dependencies, expirations, or scavenging. Good performance Because the static variable cache is held in the applications memory space, all caching calls are within the same process space, resulting in good performance.

37

You can use Windows Forms controls in only one page at a time. Because the cache holds a reference to the control, you have only one copy of the control to use at any given time. It does not make sense to clone Windows Forms controls because most of the work is in populating your control, and cloning effectively creates a new control. An exception to this is if you need to concurrently use the same class in several forms in your application. In this situation, you can clone several instances of the control to be used concurrently by all forms requiring the control. The following Windows Forms controls are classic examples of good caching candidates: DataGrid Displays ADO.NET data in a scrollable grid TreeView Contains a Nodes collection of TreeNode objects that implement ICloneable ListView Contains an Items collection of ListViewItem objects that implement Icloneable Because these controls often require complex processing before being rendered, caching them can improve application performance. Cache controls that take a long time to populate with data or that have complex initialization (that is, constructor) code. You may also decide to cache controls that are used in multiple forms in your application user interface. The following example shows how to create a cache based on a hash table. static Hashtable m_CachedControls = new Hashtable(); The following example shows how to create a TreeView control and insert it into the cache that has been created. private void btnCreate_Click(object sender, System.EventArgs e) { // Create the TreeView control and cache it. TreeView m_treeView = new TreeView(); m_treeView.Name = "tvCached"; m_treeView.Dock = System.Windows.Forms.DockStyle.Left; m_CachedControls.Add(m_treeView.Name, m_treeView); } The following example shows how to obtain the control from cache and bind it to a form private void GetAndBindControl(Form frm) { frm.Controls.Add((Control)m_CachedControls["tvCached"]); frm.Show(); }

38

These code samples are all you need to implement Windows Forms control caching in your application.

Potrebbero piacerti anche