Introduction:
As the previous chapter puts it, caching ObjectDataSource data requires simply setting some properties. However, it is in the presentation layer to the data cache, which is closely coupled with the ASP.net page page caching strategy (caching policies) (tightly couples). One of the reasons we're layering the architecture is to break this coupling. Take the business logic layer as an example, break the business logic out of the ASP.net page, and the data access layer asp.net the details of the data access to the page. In a sense, the separation of business logic and data access details is first, so that the system is easier to read, maintainable, modifiable, and easier to divide by module-for example, the developer of the presentation layer has little knowledge of the details of the database and does not hinder its development efforts. Of course, there are similar benefits from the separation of caching strategies from the presentation layer.
In this article we will expand the hierarchy and add a cache layer (Caching Layer, short for CL) to implement the caching strategy. The cache layer includes a PRODUCTSCL class that accesses product information using methods such as GetProducts (), Getproductsbycategoryid (CategoryID). When these methods are invoked, the data is retrieved from memory, and if the memory is empty, the corresponding method of the PRODUCTSBLL class in the business Logic layer BLL is invoked, and the retrieved data is returned from the data Access layer DAL. The Productscl class method caches data after it has been fetched from the business logic layer BLL before returning.
As shown in Figure 1, the cache layer CL is located in the presentation layer and the business logic layer.
Figure 1: The cache layer (CL) is a separate layer in our architecture
Step One: Create a class for the cache layer
In this article, we create a cache layer that contains only one PRODUCTSCL class, and it has only a few methods.
The full cache layer should also contain CATEGORIESCL, EMPLOYEESCL, and SUPPLIERSCL classes. With the business logic layer BLL and the data Access layer DAL, the caching layer can be considered as a separate class library project (Class Library project), but we treat it as a class in the App_Code folder.
To better separate the cache layer class from the Dal class and the BLL class, we create a new subfolder in the App_Code folder. Right-click the App_Code folder in Explorer, select New folder, name cl, add new class inside ProductsCL.cs
Figure 2: Adding 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. However, in this article, we only create the GetProducts () method (in step 3rd) and the Getproductsbycategoryid (CategoryID) method (in step 4th). You can refine the PRODUCTSCL class in your spare time and create the corresponding CATEGORIESCL, EMPLOYEESCL, and SUPPLIERSCL classes
Step two: Read and write to data cache
The ObjectDataSource cache attribute uses the ASP.net data cache to store data obtained from BLL. To access the data cache, you can access the class from the Code-behind classes class or Architecture layer (architecture) of the ASP.net page. To read and write data cache through the Code-behind classes class of the ASP.net page, you can use the following pattern:
Read from the cache (read)
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);
The Insert method of the Cache class class can have many overloads. cache["Key" = value and Cache.Insert (key, value) are the same, add an item to the cache, but do not specify expiry (which can be understood as cache duration). More typically, when we add an entry to the cache, we specify a expiry, which is either dependency (subordinate), time-based expiry, or both, such as the last 2 expressions above.
If the required data is stored in memory, the method of the cache layer is invoked first to return the data. If you are not in memory, call the corresponding method in BLL. The data is cached before returning. As the following process table resolves:
Figure 3: A method that invokes the cache layer if the data exists in memory.
The processes in the diagram above can be used in the following patterns:
Type instance = cache["key" as type;
if (instance = = null)
{
instance = bllmethodtogetinstance ();
Cache.Insert (key, instance, ...);
}
return instance;
Where type is the kind of data that is cached in memory-specific to this article, that is, northwind.productsdatatable; In addition, key is used to uniquely identify each entry of the cache. If the entry that specifies the key value is not in memory, then instance is null and then retrieves the data using an appropriate method of the BLL class to cache the obtained data into memory. When instance is returned, it will contain a reference to the data (reference to the "data"), either from memory or from the return data of the BLL class.
When accessing memory, be sure to use the above pattern. The following pattern seems to look exactly like the pattern above, but there is a subtle difference between a race condition (an implicit flaw that can be understood as imperceptible). Race condition is difficult to debug because it happens only occasionally and is less likely to happen again. As follows:
if (cache["key"] = = null)
{
Cache.Insert (key, Bllmethodtogetinstance (), ...);
}
return cache["key"];
Again, the above pattern is not a reference to a cached entry in a local variable, but rather a direct access to the data in a conditional statement that returns data directly in the return statement. In this scenario, cache["key" is non-null when the code is started, but before the return statement is run, the system clears it out of memory, and the code returns a null value instead of the type of object we expect.
Note: If you are simply reading or writing access to data cache, you do not need to synchronize access (synchronize thread access); Of course, if you need to do multiple operations on the data in memory (multiple operations), You should still implement locking (lock), or other mechanisms.
If you want to clear an entry from the data cache, you can use the Remove method, such as:
Step Three: Return product information from the PRODUCTSCL class
In this article, we'll use 2 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 in the cache layer () method returns a Northwind.productsdatatable object to obtain information about all products, while the Getproductsbycategoryid (CategoryID) method returns all products for a particular category.
The following code is a partial method 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"; If the item is in the cache northwind.productsdatatable products = _ Getcacheitem (rawkey) as Northwind.productsda
tatable; if (products = null) {//Item not found in Cache-retrieve it and insert it into the cache products = API.
GetProducts ();
Addcacheitem (Rawkey, products);
return to 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); If the item is in the cache northwind.productsdatatable products = _ Getcacheitem (rawkey) as Northwind.productsda
tatable; if (products = null) {//Item not found in Cache-retrieve it and insert it into the cache products = API.
Getproductsbycategoryid (CategoryID);
Addcacheitem (Rawkey, products);
return to Products;
}
}
}
First, note that the attributes DataObject and Dataobjectmethodattribute are applied to classes (class) and methods (methods), and these properties serve the ObjectDataSource Settings Wizard. Indicate that those classes and methods should appear in the wizard's setup step. Because ObjectDataSource controls want to access these classes and methods at the presentation level, I add these properties to facilitate the wizard settings. For these properties and their effects, see the 2nd Chapter of this tutorial, "Creating 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 based on the specified key value and, if not found, retrieves the data using the corresponding method in the Productsbll class and Addcacheitem (key, value) method to cache the acquired data into memory.
The Getcacheitem (key) and the Addcacheitem (key, value) method respectively read and write to the data cache. Getcacheitem (key) is relatively simple, it returns data from the cache class according to the incoming 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 provide, but instead calls the Getcachekey (key) method, because the method returns key according to "Productscache-", and in the above code, Mastercachekeyarray is used to store the string "Productscache". Of course, the Addcacheitem (key, value) method also uses Mastercachekeyarray, which we'll see later.
In the asp.net page background code class (Code-behind Class), we can use the page class cache property to access the data cache, as we did in step 2nd: cache["Key" = value, whereas in the Architecture class ( Note: specifically to this article, is the cache layer Class (PRODUCTSCL), we can access in 2 ways: Httpruntime.cache or HttpContext.Current.Cache; there is an article in Peter Johnson's blog Httpruntime.cache vs. HttpContext.Current.Cache (http://weblogs.asp.net/pjohnson/archive/2006/02/06/437559.aspx) , the advantages of httpruntim and relative to HttpContext.Current are discussed. In this case, our PRODUCTSCL class will use HttpRuntime.
Note: If you are using the Class Library project (class libraries projects), be sure to refer to System.Web to use httpruntime and HttpContext classes.
If the data is not found in memory, the PRODUCTSCL class will fetch the data from the business logic layer BLL and cache the data using Addcacheitem (key, value), which can be cached for 60 seconds using the following code to add cached data to memory:
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);
where DateTime.Now.AddSeconds (cacheduration) specifies the cache time-60 seconds; System.Web.Caching.Cache.NoSlidingExpiration indicates that there is no variable cache time (no sliding expiration). Although the Insert () method can contain 2 input parameters that define the cache time (absolute and sliding expiry), you can specify only one of them, The Insert () method throws a ArgumentException exception if you specify both an absolute time and a variable time 2 parameters.
Note: There are some drawbacks to the direct execution of the Addcacheitem (key, Value) method, which we will explain and fix in step 4th.
Step 4th: Disable caching when data is modified
In addition to data retrieval methods, the caching 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 to invoke the corresponding method of the business logic layer, and then invalidate the cached data. As discussed in the previous section, the Insert, update, or Delete method can be invoked when the ObjectDataSource cache attribute is activated.
The following UpdateProduct method shows how to perform data modification at the cache layer CL:
[System.ComponentModel.DataObjectMethodAttribute (Dataobjectmethodtype.update, false)]
public bool UpdateProduct (string productName, decimal unitprice, int productID)
{
bool = 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) will add entries to memory, And the Getproductsbycategoryid (CategoryID) method adds several entries for each category (because there are several or more products for each category).
To invalidate the cached data, we need to remove all entries that were added to the PRODUCTSCL class. To do this, in the Addcacheitem (key, Value) method, specify a cache slave (cached dependency) for the entry when it is added. In general, a cache slave can be another entry in memory, a file in a file system, or data from a Microsoft SQL Server database databases. When a dependent body changes or is removed from memory, its corresponding cache entry is automatically removed from memory. In this tutorial, when the PRODUCTSCL class adds an entry to memory, we create an additional entry as its subordinate body. From this, to remove the cached entries, simply remove the dependent bodies.
We'll change the Addcacheitem (key, Value) method, and when you add cached data to memory with this method, each entry corresponds to a subordinate body (cache dependency).
private void Addcacheitem (string Rawkey, object value)
{
System.Web.Caching.Cache Datacache = Httpruntime.cache;
Make sure mastercachekeyarray[0] are 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, and assign a value to it with the current date and time. Then, create a subordinate body. The constructor for the CacheDependency class (constructor) can have many overloads (overloads), and the overloads used in this article accept 2 string arrays as input parameters. The first parameter specifies the file as a subordinate, but we do not count the file as a subordinate, so we set the first input parameter to null and the second parameter specifies the cache key as a subordinate, which we specify as Mastercachekeyarray. The cachedependency is then passed to the Insert method.
After making the above modifications to the Addcacheitem (key, Value) method, to invalidate the cache, it is simple to remove the subordinate body:
[System.ComponentModel.DataObjectMethodAttribute (Dataobjectmethodtype.update, false)]
public bool UpdateProduct (string productName, decimal unitprice, int productID)
{
bool = API. UpdateProduct (ProductName, UnitPrice, ProductID);
Invalidate the Cache
Invalidatecache ();
return result;
}
public void Invalidatecache ()
{
//Remove the cache dependency
HttpRuntime.Cache.Remove ( Mastercachekeyarray[0]);
}
Step Fifth: Call the cache layer at the presentation layer
Save the changes to the PRODUCTSCL class, open the Fromthearchitecture.aspx page in the Caching 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 in the following figure:
Figure 4: Class PRODUCTSCL included in the Drop-down list
After you select the Productscl class, click Next. We can see that there are 2 options in the Select tab: the GetProducts () and the Getproductsbycategoryid (CategoryID) method, while in the Update tab there is only one updateproduct () method. Select the GetProducts () method in the Select tab, and in the Update tab, select the unique UpdateProduct () method, and the last point finish.
Figure the 5:productscl class method is included in the Drop-down list.
When you finish the wizard, Visual Studio sets the ObjectDataSource OldValuesParameterFormatString property to Original_{0} and adds the appropriate column to the GridView. The default value of {0} is oldvaluesparameterformatstring, and the GridView control's paging, sorting, and editing features are enabled. Because the Uploadproducts () method of the cache layer CL edits only the name and price of the product, you need to modify the GridView accordingly to limit the 2 columns that can be edited.
In the previous tutorial, we specified that the GridView control contains ProductName, CategoryName, and UnitPrice3 columns. Be sure to copy it boldly so that the GridView and ObjectDataSource declaration code should look like this:
<asp:gridview id= "Products" 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 id= "ProductName" runat= "server" text= ' <%# Bind ("ProductName")%> '/> <asp: RequiredFieldValidator id= "RequiredFieldValidator1" controltovalidate= "ProductName" display= "Dynamic" errormessage
= "You are must provide a name for the product." Setfocusonerror= "True" runat= "Server" >*</asp:RequiredFieldValidator> </EditItemTemplate> < itemtemplate> <asp:label id= "Label2" runat= "server" text= ' <%# Bind ("ProductName")%> ' ></asp:label&
Gt
</ItemTemplate> </asp:TemplateField> <asp:boundfield datafield= "CategoryName" headertext= "Category" Readonly= "True" sortexpression= "CategoryName"/> <asp:templatefield headertext= "Price" sortexpression= "UnitPrice" > < edititemtemplate> $<asp:textbox id= "UnitPrice" runat= "Server" columns= "8" text= ' <%# ' Bind ("UnitPrice", "{0:N2 ")%> ' ></asp:TextBox> <asp:comparevalidator id=" CompareValidator1 "runat=" Server "ControlToValidate = "UnitPrice" display= "Dynamic" errormessage= "You must enter a valid currency value with no currency symbols.
Also, the value must is greater than or equal to zero. " Operator= "Greaterthanequal" setfocusonerror= "True" type= "Currency" valuetocompare= "0" >*</asp: comparevalidator> </EditItemTemplate> <itemstyle horizontalalign= "right"/> <ItemTemplate> < Asp:label id= "Label1" runat= "server" text= ' <%# Bind ("UnitPrice", "{0:c}")%> '/> </ItemTemplate> </a sp:templatefield> </Columns> </asp:GridView> <asp:objectdatasource id= "Productsdatasource" 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:o
Bjectdatasource>
In this way, we use the cache layer on the page. For field demo caching, set breakpoints (breakpoints) in the GetProducts () and UpdateProduct () methods of the PRODUCTSCL class, access the page in the browser, and execute the code when sorting or paging, fetching data from memory. A record is then updated, noting that due to a cache failure, the data is fetched 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 perfect. It contains only one PRODUCTSCL class, and it contains only a few methods. In addition, only one asp.net page (~/caching/fromthearchitecture.aspx) uses the cache layer cl, while the other pages are directly calling the business logic layer BLL. If you intend to use the cache layer CL in your application, all calls to the page layer should first access the cache layer CL.
Summarize:
Although caching for SqlDataSource and ObjectDataSource controls can be performed at the performance layer of ASP.net 2.0, it is more desirable that the system be layered separately to achieve the purpose of caching. In this article, we create a cache layer between the presentation layer and the business Logic layer, which contains classes and methods similar to those contained in the existing business logic layer. Of course, is also called in the presentation layer.
This example and the previous tutorial dealt with trigger mount (reactive loading)-that is, the data is loaded into memory when it is found that the requested data is not in memory. In fact, the data can also be "preloaded" (proactively loaded) into memory-that is, preload it into memory before the data is actually requested. In the next article we'll look at the preloaded scenario-how to load static values into memory when the application starts.
I wish you a happy programming!
Author Introduction
The author of this series of tutorials, Scott Mitchell, has six asp/asp. NET book, is the founder of 4GuysFromRolla.com, has been applying Microsoft Web technology since 1998. You can click to see all Tutorials "[translation]scott Mitchell asp.net 2.0 data tutorial," I hope to learn asp.net help.