Home>

preface:

As stated in the previous chapter,To cache data from objectdatasource, simply set some properties.However, it caches data at the presentation layer,This is tightly coupled with asp.net page page caching policies. One of the reasons we layer the system is to break this coupling.Take the business logic layer as an example,Detach business logic from asp.net pages;The data access layer separates the details of the data access from the asp.net page.In a sense,The separation of business logic and data access details is first,This makes the system easier to read, maintain, and modify, and facilitates the division of labor by modules-for example, the developers of the presentation layer do not know the details of the database and do not hinder their development.Of course, separating the caching strategy from the presentation layer has similar benefits.

In this article, we will expand the hierarchy,A new caching layer (cl for short) is added to implement the caching strategy.The cache layer includes a productscl class, which uses similar methods to getproducts (), getproductsbycategoryid (categoryid) to access product information.Retrieve data from memory when calling these methods,If the memory is empty, the corresponding method of the productsbll class in the business logic layer bll is called.The obtained data is returned from the data access layer dal.The productscl method retrieves data from the business logic layer bll and caches the data before returning.

As shown in Figure 1, the cache layer cl is located at the presentation layer and the business logic layer.

Figure 1:The cache layer (cl) is a separate layer in our architecture

Step 1:Create a class for the cache layer

In this article, the cache layer we created contains only a productscl class, which has only a few methods.

The complete cache layer should also include categoriescl, employeescl, and supplierscl classes. With the business logic layer bll and the data access layer dal, the cache layer can be treated as a separate class library project, but we will treat it as a class in the app_code folder.

In order to better distinguish the cache layer class from the dal and bll classes,We create a new subfolder in the app_code folder.Right-click the app_code folder in Explorer, select "New Folder", name it cl, and add a new class productscl.cs

Figure 2:Add a folder named cl and a class named productscl.cs

Like the productsbll class in bll, the productscl class should contain the same data access and modification methods.But in this article,We only create the getproducts () method (in step 3) and the getproductsbycategoryid (categoryid) method (in step 4). You can perfect the productscl class in your free time,And create the corresponding categoriescl, employeescl and supplierscl classes

Step 2:Read and write the data cache

The cache property of objectdatasource uses asp.net data cache to store the data obtained from bll.To access the data cache, you can access it from the code-behind classes or architecture classes of the asp.net page.To read and write the data cache through the code-behind classes of the asp.net page,The following modes are available:

//read from the cache
object value=cache ["key"];
//add a new item to the cache (write)
cache ["key"]=value;
cache.insert (key, value);
cache.insert (key, value, cachedependency);
cache.insert (key, value, cachedependency, datetime, timespan);
</pre>
</div>
<p>
The insert method of the cache class can have many overloads.
cache ["key"]=value and cache.insert (key, value) are the same,All add an item to the cache, but no expiry is specified (can be understood as the cache duration). More representatively,When we add an entry to the cache, we specify an expire, which is either a dependency, a time-based expiry, or both.
For example, the last two expressions above.
</p>
<p>
If the required data is stored in memory,First call the cache layer method to return the data.
If it is not in memory, the corresponding method in bll is called.
The data is cached before returning.
Just as the following flow chart parses:
</p>
<p>
<strong>
Figure 3:The method of the cache layer is called if the data exists in memory.
</strong>
</p>
<p>
<strong>
The above process can be used in the following modes:
</strong>
</p>
<div>
<pre>
type instance=cache ["key"] as type;
if (instance == null)
{
 instance=bllmethodtogetinstance ();
 cache.insert (key, instance, ...);
}
return instance;

Among them, type is the type of data cached in memory-specific to this article,That is, northwind.productsdatatable;in addition, the key is used to uniquely identify each entry in the cache.If the entry with the specified key value is not in memory,Then instance is null, and then use some appropriate method of the bll class to retrieve the data,Cache the obtained data to memory.After the instance is returned, it will contain a reference to the data, and the data will either come from memory,Either the return data from the bll class.

When accessing memory,Be sure to use the above mode.The following pattern,At first glance it looks exactly like the pattern above,But there is a slight difference,It has a race condition (can be understood as an implicit defect that is not easy to detect). race conditions are difficult to debug,Because it happens only occasionally,It is also less likely to happen again.as follows:

if (cache ["key"] == null)
{
 cache.insert (key, bllmethodtogetinstance (), ...);
}
return cache ["key"];

Another one is,The above pattern does not store references to cache entries in local variables,But access the data directly in the conditional statement,Return the data directly in the return statement.Imagine this situation,The cache ["key"] is non-null when the code is started, but the system clears it from memory before running the return statement.Then the code will return a null value instead of some type of object we expect.

Note:If you only read or write access to the data cache,You do not need to synchronize thread access;of course, if you need to perform multiple operations on the data in memory, you should still implement locks or other mechanisms.

If i want to clear an entry from the data cache,You can use the remove method, for example:

cache.remove (key);

Step 3:Return product information from productscl

In this article, we will use two methods in the productscl class to return product information:getproducts () and getproductsbycategoryid (categoryid). Similar to the productsbl class in the business logic layer, the getproducts () method in the cache layer returns a northwind.productsdatatable Object to get information about all products;The getproductsbycategoryid (categoryid) method returns all products in a particular category.

The following code is part of the methods in the productscl class:

[system.componentmodel.dataobject]
public class productscl
{
 private productsbll _productsapi=null;
 protected productsbll api
 {
 get
 {
 if (_productsapi == null)
 _productsapi=new productsbll ();
 return _productsapi;
 }
 }
 [system.componentmodel.dataobjectmethodattribute (dataobjectmethodtype.select, true)]
 public northwind.productsdatatable getproducts ()
 {
 const string rawkey="products";
 //see if the item is in the cache
 northwind.productsdatatable products=_
 getcacheitem (rawkey) as northwind.productsdatatable;
 if (products == null)
 {
 //item not found in cache-retrieve it and insert it into the cache
 products=api.getproducts ();
 addcacheitem (rawkey, products);
 }
 return products;
 }
 [system.componentmodel.dataobjectmethodattribute (dataobjectmethodtype.select, false)]
 public northwind.productsdatatable getproductsbycategoryid (int categoryid)
 {
 if (categoryid<0)
 return getproducts ();
 else
 {
 string rawkey=string.concat ("productsbycategory-", categoryid);
 //see if the item is in the cache
 northwind.productsdatatable products=_
 getcacheitem (rawkey) as northwind.productsdatatable;
 if (products == null)
 {
 //item not found in cache-retrieve it and insert it into the cache
 products=api.getproductsbycategoryid (categoryid);
 addcacheitem (rawkey, products);
 }
 return products;
 }
 }
}

First, pay attention to the attributes dataobject and dataobjectmethodattribute applied to the classes and methods;these attributes serve the objectdatasource setup wizard,Indicate which classes and methods should appear in the setup steps of the wizard.Because the objectdatasource control accesses these classes and methods at the presentation layer,So I added these attributes,Easy wizard setup.Regarding these attributes and their role,See Chapter 2 of this tutorial,Create a business logic layer".

In the getproducts () and getproductsbycategoryid (categoryid) methods, the data returned by getcacheitem (key) is assigned to a local variable.The getcacheitem (key) method finds the corresponding cache entry in memory according to the specified key value;If not found,Then use the corresponding method in the productsbll class to retrieve the data,And use addcacheitem (key, value) method to cache the obtained data to memory.

The getcacheitem (key) and addcacheitem (key, value) methods perform read and write operations on the data cache, respectively. getcacheitem (key) is relatively simple,It returns data from the cache class based on the passed key value.as follows:

private object getcacheitem (string rawkey)
{
 return httpruntime.cache [getcachekey (rawkey)];
}
private readonly string [] mastercachekeyarray={"productscache"};
private string getcachekey (string cachekey)
{
 return string.concat (mastercachekeyarray [0], "-", cachekey);
}

Getcacheitem (key) does not directly use the key value we provided, but instead calls the getcachekey (key) method, because this method returns the key according to "productscache-";in the above code,mastercachekeyarray is used to store the string "productscache". Of course, the addcacheitem (key, value) method will also use the mastercachekeyarray, as we will see later.

In the asp.net page code-behind class, we can use the cache property of the page class to access the data cache, just like our expression in step 2:cache ["key"]=value;And in the architecture class (Note:specific to this article,It is the cache layer class (productscl), which we can access in two ways:httpruntime.cache or httpcontext.current.cache;there is an article "httpruntime.cache vs. httpcontext.current.cache" in the peter johnson's blog , Explores the advantages of httpruntim and httpcontext.current;here, our productscl class will use httpruntime.

Note:If you are using class library projects, you must remember to reference system.web to use the httpruntime and httpcontext classes.

If no data is found in memory,The productscl class will get data from the business logic layer bll,And use addcacheitem (key, value) to cache the data,You can add cached data to memory with the following code,Its cache time is 60 seconds:

const double cacheduration=60.0;
private void addcacheitem (string rawkey, object value)
{
 httpruntime.cache.insert (getcachekey (rawkey), value, null, datetime.now.addseconds (cacheduration), caching.cache.noslidingexpiration);
}

Among them, datetime.now.addseconds (cacheduration) specifies the cache time—60 seconds;and system.web.caching.cache.noslidingexpiration indicates that there is no sliding expiration. Although the insert () method can contain absolute Time and variable time (absolute and sliding expiry) 2 input parameters that define the cache time,But you can only specify one of them,If you specify both absolute time and variable time parameters,The insert () method will throw an argumentexception.

Note:There are some disadvantages to directly executing the addcacheitem (key, value) method.We will explain and correct in step 4.

Step 4:Invalidate the cache when data is modified

In addition to data retrieval methods,The cache layer should also contain methods for inserting, updating, and deleting data.The data modification method of the cache layer is not to modify the cached data.But call the corresponding method of the business logic layer,Then invalidate the cached data.As discussed in the previous chapter,When the cache property of objectdatasource is activated,You can call its insert, update, or delete methods.

The following updateproduct method illustrates how to perform data modification methods in the cache layer cl:

[system.componentmodel.dataobjectmethodattribute (dataobjectmethodtype.update, false)]
public bool updateproduct (string productname, decimal?unitprice, int productid)
{
 bool result=api.updateproduct (productname, unitprice, productid);
 //todo:invalidate the cache
 return result;
}

Before the method of the business logic layer returns data,We need to invalidate the cached data.However, this is not easy.Whether productscl class "s getproducts () or getproductsbycategoryid (categoryid) adds entries to memory,And the getproductsbycategoryid (categoryid) method will add several entries for each category (because there are several or more products for each category).

To invalidate cached data,We need to delete all entries added by the productscl class.To do this, in the addcacheitem (key, value) method, specify a cache dependency for the entry when adding it. Generally speaking,The cache slave can be another entry in memory;A file in the file system;Or the data in the microsoft sqlserver database database.When the slave changes,Or when removed from memory,The corresponding cache entry is automatically deleted from memory.In this tutorial,When the productscl class adds entries to memory,We create an additional entry as its slave.Therefore, to delete the cache entry,Just remove these slaves.

Let's change the addcacheitem (key, value) method. When using this method to add cached data to memory,Correspond each entry with a cache dependency.

private void addcacheitem (string rawkey, object value)
{
 system.web.caching.cache datacache=httpruntime.cache;
 //make sure mastercachekeyarray [0] is in the cache-if ​​not, add it
 if (datacache [mastercachekeyarray [0]] == null)
 datacache [mastercachekeyarray [0]]=datetime.now;
 //add a cachedependency
 system.web.caching.cachedependency dependency =
 new cachedependency (null, mastercachekeyarray);
 datacache.insert (getcachekey (rawkey), value, dependency, datetime.now.addseconds (cacheduration), system.web.caching.cache.noslidingexpiration);
}

Mastercachekeyarray is an array of strings,Used to store "productscache". First check the mastercachekeyarray. If it is null, assign a value to it using the current date and time.Then, create a slave.The constructor of the cachedependency class can have many overloads. The overload used in this article accepts 2 arrays of strings as input parameters.The first parameter specifies the file as a slave,But in this article, we don't really use files as slaves.So we set the first input parameter to null;the second parameter specifies cache keys as slaves,In this article we designate it as mastercachekeyarray. This cachedependency is then passed to the insert method.

After making the above modifications to the addcacheitem (key, value) method,To invalidate the cache,It's easy, just remove the slave:

[system.componentmodel.dataobjectmethodattribute (dataobjectmethodtype.update, false)]
public bool updateproduct (string productname, decimal?unitprice, int productid)
{
 bool result=api.updateproduct (productname, unitprice, productid);
 //invalidate the cache
 invalidatecache ();
 return result;
}
public void invalidatecache ()
{
 //remove the cache dependency
 httpruntime.cache.remove (mastercachekeyarray [0]);
}

Step 5:Call the cache layer in the presentation layer

Save the modifications to the productscl class,Open the fromthearchitecture.aspx page in the cache folder and add a gridview control. Create a new objectdatasource from the smart tag of the gridview control. In the first step of the wizard,Select productscl from the drop-down list, as shown below:

Figure 4:The productscl class is included in the drop-down list

After selecting the productscl class, click next. We can see that there are 2 options in the select tag:getproducts () and getproductsbycategoryid (categoryid);there is only one updateproduct () method in the update tag. Select the getproducts () method in the select tab;select the only updateproduct () method in the update tab, and click finish.

Figure 5:The methods of the productscl class are included in the drop-down list.

After completing the wizard,visual studio will set the oldvaluesparameterformatstring property of the objectdatasource to original_ {0} and add the corresponding column to the gridview.Set the oldvaluesparameterformatstring to the default value of {0}, and enable the paging, sorting, and editing functions of the gridview control.Since the uploadproducts () method of the cache layer cl only edits the product name and price,Therefore, the gridview needs to be modified accordingly to restrict it to edit only these two columns.

In the previous tutorial,We specify that the gridview control contains productname, categoryname, and unitprice3 columns. Copy it safely and boldly,Thus, the gridview and objectdatasource declaration code should look like this:

<asp:gridview runat="server" autogeneratecolumns="false"
 datakeynames="productid" datasourceid="productsdatasource"
 allowpaging="true" allowsorting="true">
 <columns>
 <asp:commandfield showeditbutton="true" />
 <asp:templatefield headertext="product" sortexpression="productname">
 <edititemtemplate>
 <asp:textbox runat="server"
  text="<%#bind (" productname ")%>" />
 <asp:requiredfieldvalidator
  controltovalidate="productname" display="dynamic"
  errormessage="you must provide a name for the product."
  setfocusonerror="true"
  runat="server">*</asp:requiredfieldvalidator>
 </edititemtemplate>
 <itemtemplate>
 <asp:label runat="server"
  text="&%;bind (" productname ")%>"</asp:label>
 </itemtemplate>
 </asp:templatefield>
 <asp:boundfield datafield="categoryname" headertext="category"
 readonly="true" sortexpression="categoryname" />
 <asp:templatefield headertext="price" sortexpression="unitprice">
 <edititemtemplate>
 $<asp:textbox runat="server" columns="8"
  text="<%#bind (" unitprice "," {0:n2} ")%>"></asp:textbox>
 <asp:comparevalidator runat="server"
  controltovalidate="unitprice" display="dynamic"
  errormessage="you must enter a valid currency value with
  no currency symbols. also, the value must be greater than
  or equal to zero. "
  operator="greaterthanequal" setfocusonerror="true"
  type="currency" valuetocompare="0"&​​gt;*</asp:comparevalidator>
 </edititemtemplate>
 <itemstyle horizontalalign="right" />
 <itemtemplate>
 <asp:label runat="server"
  text="<%#bind (" unitprice "," {0:c} ")%>" />
 </itemtemplate>
 </asp:templatefield>
 </columns>
</asp:gridview>
<asp:objectdatasource runat="server"
 oldvaluesparameterformatstring="{0}" selectmethod="getproducts"
 typename="productscl" updatemethod="updateproduct">
 <updateparameters>
 <asp:parameter name="productname" type="string" />
 <asp:parameter name="unitprice" type="decimal" />
 <asp:parameter name="productid" type="int32" />
 </updateparameters>
</asp:objectdatasource>

So, we use the cache layer for this page.For field demonstration caching,Set breakpoints in the getproducts () and updateproduct () methods of the productscl class, visit the page in a browser,This code is executed when sorting or paginating,Get data from memory.Then update a record,Note that due to cache invalidation,The data will be obtained from the business logic layer bll and bound to the gridview.

Note:The cache layer downloaded from the download link in this article is not complete.It only contains a productscl class, which contains only a few methods.In addition, only one asp.net page (~/caching/fromthearchitecture.aspx) uses the cache layer cl, and other pages call the business logic layer bll directly. If you plan to use the cache layer cl in your application, all calls to the page layer should access the cache layer cl first.

to sum up:

Although sqldatasource and objectdatasource controls can be cached in the presentation layer of asp.net 2.0,But the more ideal approach is to separate the layers in the system to achieve the purpose of caching.In this article, we created a cache layer between the presentation layer and the business logic layer.The caching layer contains classes and methods that are similar to the existing business logic layer.Of course, it is also called at the presentation layer.

This example and the previous tutorial deal with "reactive loading" —that is, loading the data into memory when it is found that the requested data is not in memory.In fact, data can also be "proactively loaded" into memory-that is, data is preloaded into memory before it is actually requested.In the next article we will see the situation of preloading-how to load static values ​​into memory when the application starts.

Happy programming!

About the Author

  • Previous Use DOM to control HTML elements in JS
  • Next AngularJS ng-blur instruction detailed and simple examples