1.1.1 Summary
Our system has recently faced severe performance bottlenecks due to increased traffic and requests from clients at the same time, which forces us to address this problem from two aspects, increase hardware and improve system performance.
We can use a variety of methods to optimize our system, this blog will introduce through the cache method to optimize the performance of the system to reduce the burden of the system.
1.1.2 Body
Cache at different locations
The cache locations used in Web applications include client browser caching, client and server, and server-side, so the cache can be grouped into the following categories:
Client-Side Caching (Caching)
Agent caching (proxy Caching)
Reverse proxy caching (Reverse proxy Caching)
Server caching (WEB server Caching)
Asp. NET in the cache
Asp. NET has two types of caching: output caching and data caching.
Output caching: This is the simplest type of cache, it saves a copy of the page that is sent to the client, and when the next client sends the same page request, the page is not regenerated (within the cache time limit), but the page is retrieved from the cache, and the page is regenerated, of course, because the cache expires or is reclaimed.
Data Caching
In addition, there are two special caches: fragment caching and data source caching.
Fragment caching: This is a special output cache, which is not caching the entire page, but caching parts of the page, because caching the entire page is usually not feasible because some parts of the page are customized to the user (for example, user login information), but we can cache the shared parts of the application. At this point we can consider using fragment caching and user control caching.
Data source caching: a cache that is built into a data source control that includes SqlDataSource, ObjectDataSource, and XmlDataSource controls. The data source cache uses the data caching method, the difference is that we do not need to use the display method to process the cache, we simply set the appropriate properties, and then the data source control can store and retrieve data.
Output Caching
The output cache can cache the final rendered page, and when the client requests the same page again, the control object is no longer recreated, the page life cycle is no longer started, no code is executed again, and the cached page is fetched in the cache.
Now we design a page that, whenever the user sends a page request, gets the current code execution time and then displays it on the page.
Figure 1 Output caching
This is the simplest example, whenever a user sends a page request, the page is updated to show the time, because each request gets a new page, in fact, we do not need real-time response to the user each page request, we can cache the page through the output cache whenever the user sends the same page request, and the cached page can be returned to the user through the output cache during cache validity.
To implement the output cache, simply add the following code to the page:
Copy Code code as follows:
<!--Adds OutputCache directive-->
<%@ OutputCache duration= "No" varybyparam= "None"%>
It supports five properties, of which two properties duration and VaryByParam are required
Duration |
Required Properties. The time, in seconds, that the page should be cached. Must be a positive integer. |
Location |
Specifies where the output should be cached. If you want to specify this parameter, you must be one of the following: Any, Client, downstream, None, Server, or serverandclient. |
VaryByParam |
Required Properties. The name of the variable in Request, which should produce a separate cache entry. "None" indicates no change. The "*" can be used to create a new cache entry for each variant array. separated by ";" between variables. |
VaryByHeader |
Changes the cached entry based on the changes in the specified header. |
VaryByCustom |
Allows you to specify a custom change (for example, "Browser") in Global.asax. |
Table 1 Output Cache Properties
Here we set the expiration of the output cache to 23 seconds, that is, when the cache exceeds the expiration date, it is reclaimed, and the page is recreated when the user requests the page again.
Client Cache
The other option is client-side caching, if the user clicks the Back button in the browser or reenter the URL in the Address bar, in which case the browser will fetch the page from the cache; However, if the user clicks on the "Refresh" button, the cache in the browser will fail and the browser sends the page request.
If we want to use client-side caching, just specify the properties in OutputCache location= "client" is OK, the specific code looks like this:
Copy Code code as follows:
<!--Sets client OutputCache-->
<%@ OutputCache duration= "a" varybyparam= "None" location= "Client"%>
By adding the Location attribute in outputcache, we implemented client-side caching, and by setting up client-side caching we were able to reduce client requests, some might ask: "Every user's first page request needs a server to complete, which is not a good way to reduce the pressure of service." Indeed, as opposed to server caching, client-side caching does not reduce code execution and database operations, but when we cache pages that contain personalized data in the server, the client requests the page because different user personalization data is different, which results in a request error. So we can use fragment caching to cache the common parts or the client cache to cache the user information.
Query String Caching
In the previous example, we set the VaryByParam property in OutputCache to None, Then the ASP.net program caches only one copy of the page, and if the page request contains the query parameters, we can only view the cached result within the validity of the cache, assuming we have a report program that provides the user with the product name to inquire about the relevant product information.
First we create two pages: Query and Results page, due to the time relationship we have the page design, as shown in the following:
Figure 2 Reporting procedures
First, we provide a query page, so that users based on the product name (ProductName) to query the corresponding product information, the specific code is as follows:
Copy Code code as follows:
protected void Page_Load (object sender, EventArgs e)
{
if (! Page.IsPostBack)
{
Gets Product ID from table production.product.
Then binding data to drop down list control.
Initcontrol (GetProductID ());
}
}
<summary>
Handles the Click event of the Btnsubmit control.
Redirects to relative product information page.
</summary>
protected void btnSubmit_Click (object sender, EventArgs e)
{
Response.Redirect (String. Format ("product.aspx?productname={0}", Ddlproductname.selectedvalue));
}
When the user clicks the Submit button, jumps to the product page and passes the query parameters in the URL-the product name (Producname).
Next, we continue to complete the query page, because in the previous page passed the query parameter ProductName, then we will be based on the ProductName query database to obtain the appropriate product information, the specific code as follows:
Copy Code code as follows:
protected void Page_Load (object sender, EventArgs e)
{
Get product name.
String productName = request.querystring["ProductName"];
Binding data to Data grid view control.
Initcontrol (this. GetData (ProductName));
}
<summary>
Inits the control.
</summary>
<param name= "DS" >the dataset.</param>
private void Initcontrol (DataSet ds)
{
Dgvproduct.datasource = ds;
Dgvproduct.databind ();
}
<summary>
Gets the data.
</summary>
<param name= "ProductName" >name of the Product.</param>
<returns>returns dataset</returns>
Private DataSet GetData (string productName)
{
The query SQL base on product name.
String sql =
String. Format (
"Select Name, ProductNumber, Safetystocklevel, ReorderPoint, StandardCost, DaysToManufacture"
+ "from Production.Product WHERE productnumber= ' {0} '",
ProductName);
Get data from table Production.Product.
using (var con = new SqlConnection (configurationmanager.connectionstrings["Sqlconn"). ToString ()))
using (var com = new SqlCommand (sql, con))
{
Com. Connection.Open ();
Gdvdata.datasource = com. ExecuteReader ();
Gdvdata.databind ();
var ada = new SqlDataAdapter (COM);
var ds = new DataSet ();
Ada. Fill (DS);
return DS;
}
}
In the previous example, we get the value of ProductName through the attribute querystring of the request, then query the database according to ProductName, and finally bind the fetch data to the DataGridView control (note: The previous instance does not consider SQL Injection problem).
Figure 3 Query Results
Now we add the output cache to the page, the following code:
Copy Code code as follows:
<!--Adds OutputCache directive-->
<%@ OutputCache duration= "All" varybyparam= "None"%>
As mentioned earlier, when the output-cached property varybyparam= "None", the ASP. NET program caches only one copy of the page during the cache validity period; Now we send the request within the cache validity period (30s).
Figure 4 Query Results
We found from the above figure that the query parameters are now productname=bk-m18b-40, but the query results are still productname=bb-9108 data, because the ASP.net program caches only one copy of the page during the cache validity period.
Through the example above, we find that caching only one page is not applicable to page output caching that contains query parameters; In fact, the previous example we can only slightly change to meet the query parameters of the situation, presumably we already know, just the VaryByParam property set to "*" on the OK.
Figure 5 Query Results
Now the query can get the result, if the query parameter is the same as the previous request and the page cache is valid, then the cache is reused, otherwise a new page cache is created.
Since ASP.net adds output caching to each query parameter, we should note whether it is really necessary to cache each query parameter to cache a copy of the page, assuming that a parameter parameter ProductID is added to the query URL, there are now two query parameters in the URL (ProductName and product ID).
Before we set the VaryByParam to "*", The ASP.net program creates a page cache for both ProductName and ProductID, and if we only create the page cache for ProductName, then we can modify the VaryByParam, as shown in the following example:
Copy Code code as follows:
<!--Sets VaryByParam property-->
<%@ OutputCache duration= "ProductName" varybyparam=%>
Customizing cache controls
We introduced the query parameter implementation cache one or more pages, in fact, ASP.net also allows us to customize the caching method to determine whether to cache the page or reuse existing, then we can set the VaryByCustom property to implement.
Suppose, now we want to design a cache based on different userhostname, because in the process of execution, the global Method GetVaryByCustomString () is invoked first to determine whether to cache pages or reuse existing ones. So we can implement userhostname based caching by rewriting the GetVaryByCustomString () method, first we create a Global.asax file and then reset the global Method getvarybycustomstring () Specifically implemented as follows:
Copy Code code as follows:
<summary>
Gets vary cache based on custom string value.
</summary>
<param name= "Context" >http context.</param>
<param name= "Custom" >custom string</param>
<returns></returns>
public override string GetVaryByCustomString (HttpContext context, string Custom)
{
if (string. Equals (Custom, "Userhostname", StringComparison.OrdinalIgnoreCase))
{
Indicates that cache should is vary on user host name.
return Context.Request.UserHostName;
}
Return base. GetVaryByCustomString (context, custom);
}
We have previously rewritten the getvarybycustomstring () method so that the Userhostname value is not the same and the corresponding cache value is obtained.
Then let the program create the cache based on Userhostname, so we'll add the following code to the page:
Copy Code code as follows:
<!--set vary cache based on custom string value-->
<%@ OutputCache duration= varybyparam= "None" varybycustom= "Userhostname"%>
By customizing the Present GetVaryByCustomString () method, we implement different caching methods based on userhostname, in fact, we can also implement more kinds of caching schemes, such as: Based on user roles, time and URLs, and so on.
Fragment caching
In some cases, we can't cache the entire page, but we still want to cache some of the pages to reduce the burden of the system; in fact, we can do this in two ways: fragment caching and data caching.
To implement fragment caching, we need to create a custom control cache part of the page, and then we add the OutputCache directive to the custom control so that the entire page is not cached, except for the custom cache control.
We introduced the use of output caching, just add the outputcache instruction to the page, suppose we want to add output cache to several pages this may be simpler, but we want to add the output caching feature to dozens of pages, And the previous example of the duration attribute values are directly hard code to each page, if we need to modify the Duration attribute value, then we must modify each page, ASP. NET also need to recompile these pages, which is not conducive to our maintenance, the most important thing is to increase our workload.
In fact We can define a outputcacheprofile (Productcacheprofile) in the Web.config file, and then add the CacheProfile attribute to the page and assign it to the Productcacheprofile,web.config file The settings are as follows:
Copy Code code as follows:
<caching>
<!--Sets out put cache profile-->
<outputCacheSettings>
<outputCacheProfiles>
<add name= "productcacheprofile" duration= "/>"
</outputCacheProfiles>
</outputCacheSettings>
</caching> Now, we add the CacheProfile property to the page and set it to Productcacheprofile as follows:
Copy Code code as follows:
<!--set CacheProfile property-->
<%@ OutputCache cacheprofile= "Productcacheprofile" varybyparam= "None"%>
Data caching
The cache object is thread safe: This means that there is no need to explicitly implement locking or unlocking, adding elements in the cache object, however, the elements in the cache object must be thread safe. For example, we create an entity product, and there are situations where multiple clients might be able to manipulate the object at the same time, then we have to implement lock and unlock operations for entity product (synchronous operations refer to the 6 implementations of the single case pattern (Singleton)).
Cache entries in the cache object are automatically removed: The cache entry is automatically removed when the cache expires, the dependency is modified, or the cache asp.net is out of memory.
Cache entries Support dependencies: We can add a file, database table, or other resource type dependency to a cached item.
SqlDataSource Cache
When we enable caching in the SqlDataSource control, it caches the results in SelectCommand, and if the SQL query statement contains parameters, the SqlDataSource control caches the results of each parameter value.
This is the same as when we implemented the report Program cache query page effect through the output cache, so we will use the SqlDataSource cache to implement the effect.
Suppose we want to provide a reporting program that allows users to obtain product information by selecting the product name (ProductName).
First, we create two data source controls in the page: Sourceproductname and sourceproduct, then bind the data source to the DropDownList and the GridView separately, as follows:
Copy Code code as follows:
<!--the product number datasource START-->
<asp:sqldatasource id= "Sourceproductname" runat= "Server" Providername= "System.Data.SqlClient"
enablecaching= "True" cacheduration= "3600" connectionstring= <%$ connectionstrings:sqlconn%>
Selectcommand= "Select ProductNumber from Production.Product" ></asp:SqlDataSource>
<!--the product number DataSource end-->
<!--the product datasource START-->
<asp:sqldatasource id= "sourceproduct" runat= "Server" Providername= "System.Data.SqlClient"
enablecaching= "True" cacheduration= "3600" connectionstring= <%$ connectionstrings:sqlconn%>
selectcommand= "Select Name, ProductNumber, Safetystocklevel, ReorderPoint, StandardCost, daystomanufacture
From Production.Product WHERE productnumber= @ProductNumber ">
<SelectParameters>
<asp:controlparameter controlid= "Ddlproductnumber" name= "ProductNumber" propertyname= "SelectedValue"/>
</SelectParameters>
</asp:SqlDataSource>
<!--the product number DataSource end-->
<!--Binding the product number to GridView control-->
<!--note:due to search and the same page, so need to set AutoPostBack is true-->
<asp:dropdownlist id= "Ddlproductnumber" autopostback= "True" datasourceid= "Sourceproductname"
Datatextfield= "ProductNumber" runat= "Server" >
</asp:DropDownList>
<!--Binding the product datasource to GridView control-->
<asp:gridview id= "gvproduct" runat= "Server" datasourceid= "sourceproduct" cssclass= "Product" >
</asp:GridView>
Now we query the report program, if the Proudctname has not been cached before the corresponding cache will be created, and the cached will be reused, the query results are as follows:
Figure 6 Query Results
Cached dependencies
dependencies between cached items
asp.net cache allows us to establish dependencies between caches, where one cache entry relies on another cache entry; The following example code creates two cache entries and establishes dependencies between them. Specifically implemented as follows:
Copy Code code as follows:
Creates cache object Key1.
cache["Key1"] = "Cache Item 1";
Makes cache["Key2"] dependent on cache["Key1"].
string[] Dependencykey = new String[1];
Dependencykey[0] = "Key1";
Creates a CacheDependency object.
CacheDependency dependency = new CacheDependency (null, dependencykey);
Establishs dependency between Cache Key1 and Key2.
Cache.Insert ("Key2", "Cache Item 2", dependency);
Now, when the Key1 cache entry is updated or deleted from the cache, the Key2 cache entry is automatically removed from the cache.
file Dependencies
We described the dependencies between cache entries earlier, and ASP.net cache also provides dependencies between cached items and files, which are invalidated when the file is updated or the corresponding cache entry is deleted.
In the last blog post, "Some of the Ajax and JSON summary," the final introduction of a Demo--weibo feed, we are in real-time way to the Sina Weibo API to send requests to obtain the appropriate data, but the number of requests within a certain time limit, Once the limit is exceeded, the request is no longer accepted (please refer to rate-limiting for details). So you can cache the data by caching, when the client requests, if the cache data already exists so direct return data, otherwise want to microblogging API request data.
First, we create a httphandler that is responsible for sending requests to the microblogging API and storing the data in the file, and finally returning the data to the client.
Figure 7 Request Flow
Next, we define the CacheData () method to save the microblog data to a text file and establish a dependency relationship between the cache and the data file.
Copy Code code as follows:
<summary>
Caches the data into text file.
</summary>
<param name= "Context" >the http context</param>
private void CacheData (HttpContext context)
{
Weibo API.
String uri = context. request.querystring["API" + "?" +
"Source=" + context. request.querystring["source" + "&" +
"Count=" + context. request.querystring["Count"];
HttpWebResponse response = this. Getweibos (URI);
if (null = = response)
{
throw new ArgumentNullException ("Response is null");
}
String Jsondata;
Writes the reponse data into text file.
using (var reader = new StreamReader (response). GetResponseStream (), encoding.getencoding (response. CharacterSet)))
{
Jsondata = reader. ReadToEnd ();
}
String datapath = context. Server.MapPath ("Weibo.json");
using (var writer = new StreamWriter (DataPath, False, encoding.getencoding (response). CharacterSet)))
{
Writer. Write (Jsondata);
}
Establishs dependency between cache Weibo and text file.
Sets Cache expires after 2 minuntes.
HttpRuntime.Cache.Insert ("Weibo", Jsondata, Dep, Cache.noabsoluteexpiration, Timespan.fromminutes (2));
}
Now that we've saved the data in a text file and created a dependency on the cache Weibo with the data file, we're going to return the JSON format data to the client.
Copy Code code as follows:
<summary>
Responses the Weibo data.
</summary>
<param name= "Context" >the http contex.</param>
private void Responseweibo (HttpContext context)
{
Gets the Weibo cache data.
byte[] buf = Encoding.UTF8.GetBytes (httpruntime.cache["Weibo"). ToString ());
Writes the data into the output stream.
Context. Response.OutputStream.Write (buf, 0, buf. Length);
Context. Response.OutputStream.Flush ();
Context. Response.close ();
}
Above we convert the JSON format string to a byte value, then write to OutputStream, and finally return the data to the client.
Copy Code code as follows:
The function to get Weibo data.
Loadweibo:function () {
$.ajax ({
Weibo API.
URL: "Weibohandler.ashx",
Type: "Get",
Note:we get the data from same domain,
DataType is JSON.
DataType: "JSON",
Data: {
Source:JQWeibo.appKey,
Count:JQWeibo.numWeibo
},
When the Requet completed, then invokes success function.
Success:function (data, Textstatus, XHR) {
Sets HTML structure.
var html =
' <div class= ' Weibo ' > ' +
' <a href= ' http://weibo.com/DOMAIN ' target= ' _blank ' >USER</a> ' +
': Weibo_text<div class= ' time ' >AGO</div> ';
Appends Weibos into HTML page.
for (var i = 0; i < data.length; i++) {
$ (jqweibo.appendto). Append (
Html.replace (' Weibo_text ', JQWeibo.ify.clean (Data[i].text))
Uses regex and declare DOMAIN as global, if found replace all.
. replace (/domain/g, Data[i].user.domain)
. replace (/user/g, Data[i].user.screen_name)
. replace (' AGO ', Jqweibo.timeago (DATA[I].CREATED_AT))
);
}
}
})
}
Figure 8 Request Results
1.1.3 Summary
Caching can greatly improve the performance of your application, so design your application should take into account the application and the differences between the output cache and the data cache in asp.net.
Page caching applies to generated pages that are usually the same or have a fixed time change, for example: The data is updated every hour, so we can set duration to 3600s.
Data caching applies to generated pages that are always changing.
Http://www.codeproject.com/Articles/29899/Exploring-Caching-in-ASP-NET
Http://msdn.microsoft.com/zh-cn/library/aa478965.aspx
http://www.amazon.com/Beginning-ASP-NET-3-5-2008-Professional/dp/1590598911