In the. NET project, PostSharp is used and MemoryCache is used for cache processing.) The principle of memorycache is as follows:

Source: Internet
Author: User

Use PostSharp In the. NET project, use MemoryCache for cache processing (forwarding), and the principle of memorycache

In the previous article. the use of PostSharp in the NET project to implement AOP Aspect-Oriented Programming processing introduces the use of the PostSharp framework. Using PostSharp can bring me a lot of convenience and advantages, reduce code redundancy and improve readability, in addition, it can implement more elegant processing of common business scenarios such as logs, exceptions, caches, and transactions. This article describes how to use MemoryCache to process cache.

1. Introduction to MemoryCache

The previous article did not mention cache processing. In general, we can use Microsoft's distributed cache component MemoryCache for cache processing. The usage of MemoryCache is not described on the Internet, but this is. the new cache object introduced by NET4.0 is mainly to replace the cache module of the original enterprise library, so that.. NET caches can be everywhere, instead of being used based on a specific version of Windows.

Caching needs to be used in many cases. The rational use of caching can increase the response speed of the program and reduce the access pressure on specific resources. This article mainly introduces your Cache Usage in Winform. I hope you can learn about the Cache Usage scenarios and usage methods. Cache is a medium-and large-sized system that must be considered. To avoid every request from accessing background resources (such as databases), we generally consider some data that can be reused, which is not updated frequently, the stored data can be temporarily stored in a certain way, and subsequent requests can directly access the stored data as needed. This mechanism is called a cache mechanism.

The Cache function of. NET 4.0 is mainly composed of three parts: System. Runtime. Caching, System. Web. Caching. Cache and Output Cache.

System. Runtime. Caching is a cache framework added in. NET 4.0. It mainly uses the MemoryCache object, which exists in the assembly System. Runtime. Caching. dll.

System. web. caching. cache. cache objects that have existed since NET2.0 are generally used in the Web, and can also be used in Winform, but System must be referenced. web. dll.

Output Cache is used in Asp. NET. In versions earlier than ASP. NET 4.0, System. Web. Caching. Cache is used directly to Cache HTML fragments. ASP. NET 4.0 redesigned it and provided an OutputCacheProvider for developers to expand it. However, by default, it still uses System. Web. Caching. Cache for Caching.

In my previous article "Cache Usage in Winform", I introduced the processing of the MemoryCache auxiliary class to facilitate cache data operations. The main code of its helper class is as follows.

/// <Summary> /// cache helper class based on MemoryCache /// </summary> public static class MemoryCacheHelper {private static readonly Object locker = new object (); /// <summary> /// create a cached key value and specify the response time range. If the response expires, the corresponding value is automatically obtained. // </summary> /// <typeparam name = "T"> Object Type </typeparam> /// <param name = "key"> key of the object </param> /// <param name = "cachePopulate"> operation for obtaining the cache value </param> /// <param name = "slidingExpiration"> invalid time range of </param> /// <par Am name = "absoluteExpiration"> absolute expiration time </param> // <returns> </returns> public static T GetCacheItem <T> (String key, func <T> cachePopulate, TimeSpan? SlidingExpiration = null, DateTime? AbsoluteExpiration = null) {if (String. isNullOrWhiteSpace (key) throw new ArgumentException ("Invalid cache key"); if (cachePopulate = null) throw new ArgumentNullException ("cachePopulate "); if (slidingExpiration = null & absoluteExpiration = null) throw new ArgumentException ("Either a sliding expiration or absolute must be provided"); if (MemoryCache. default [key] = null) {lock (locker) {if (Memo RyCache. default [key] = null) {var item = new CacheItem (key, cachePopulate (); var policy = CreatePolicy (slidingExpiration, absoluteExpiration); MemoryCache. default. add (item, policy) ;}}return (T) MemoryCache. default [key];} private static CacheItemPolicy CreatePolicy (TimeSpan? SlidingExpiration, DateTime? AbsoluteExpiration) {var policy = new CacheItemPolicy (); if (absoluteExpiration. hasValue) {policy. absoluteExpiration = absoluteExpiration. value;} else if (slidingExpiration. hasValue) {policy. slidingExpiration = slidingExpiration. value;} policy. priority = CacheItemPriority. default; return policy; }/// <summary> /// clear cache // </summary> public static void sort AchE () {List <string> cacheKeys = MemoryCache. default. select (kvp => kvp. key ). toList (); foreach (string cacheKey in cacheKeys) {MemoryCache. default. remove (cacheKey );}}... // omitting some code}

If caching is required in the program, it is convenient to call this helper class. The code for caching is as follows.

Public static class UserCacheService {/// <summary> /// obtain all simple object information of the user, and put it in the cache /// </summary> /// <returns> </returns> public static List <SimpleUserInfo> GetSimpleUsers () {System. reflection. methodBase method = System. reflection. methodBase. getCurrentMethod (); string key = string. format ("{0}-{1}", method. declaringType. fullName, method. name); return MemoryCacheHelper. getCacheItem <List <SimpleUserInfo> (Key, delegate () {// return CallerFactory <IUserService>. instance. getSimpleUsers (); // simulate obtaining data from the database List <SimpleUserInfo> list = new List <SimpleUserInfo> (); for (int I = 0; I <10; I ++) {var info = new SimpleUserInfo (); info. ID = I; info. name = string. concat ("Name:", I); info. fullName = string. concat ("name:", I); list. add (info) ;}return list ;}, new TimeSpan (0, 10, 0 )); // 10 minutes expired} // <summary> // based on the user ID, Get the user's login name, and put it in the cache /// </summary> /// <param name = "userId"> User ID </param> /// <returns> </returns> public static string GetNameByID (string userId) {string result = ""; if (! String. isNullOrEmpty (userId) {System. reflection. methodBase method = System. reflection. methodBase. getCurrentMethod (); string key = string. format ("{0}-{1}-{2}", method. declaringType. fullName, method. name, userId); result = MemoryCacheHelper. getCacheItem <string> (key, delegate () {// return CallerFactory <IUserService>. instance. getNameByID (userId. toInt32 (); return string. concat ("Name:", userId) ;}, new TimeSpan (0, 30, 0); // 30 minutes expired} return result ;}

In the above case, I simulate the construction of database data to return, otherwise BLLFactory <T> is generally used, or CallerFactory <T> is used in the hybrid framework client to call the interface, it is equivalent to further function encapsulation to achieve the goal.

In this case, you can set the cache invalidation time. After the cache expires, the function of Func <T> cachePopulate is automatically used to retrieve the cached content. In actual situations, it is also a very intelligent way of processing.

2. cache with PostSharp and MemoryCache

The above case uses the MemoryCache auxiliary class to implement cache processing, which can solve the actual problem, but at the same time, the problem also arises. Each cache processing requires writing an additional code for processing, there is a lot of code redundancy, and once the cache is used in many places, maintaining the code becomes a problem.

We hope to introduce PostSharp technology to reduce repeated system code, reduce coupling between modules, and facilitate future operability and maintainability. This kind of AOP code Weaving Technology can well separate the horizontal plane and business processing, so as to simplify the code.

Let's take a look at the above Code. After introducing PostSharp, we can see how our code implements cache processing.

/// <Summary> /// use PostSharp, use MemoryCache to implement cache processing class /// </summary> public class CacheService {/// <summary> /// obtain all the user's simple object information, put it in the Cache /// </summary> /// <returns> </returns> [Cache (ExpirationPeriod = 30)] public static List <SimpleUserInfo> GetSimpleUsers (int userid) {// return CallerFactory <IUserService>. instance. getSimpleUsers (); // simulate obtaining data from the database List <SimpleUserInfo> list = new List <SimpleUserInfo> (); for (int I = 0; I <10; I ++) {var info = new SimpleUserInfo (); info. ID = I; info. name = string. concat ("Name:", I); info. fullName = string. concat ("name:", I); list. add (info) ;}return list ;}/// <summary> /// obtain the user's login name based on the user ID, and put it in the cache /// </summary> /// <param name = "userId"> User ID </param> /// <returns> </returns> [cache] public static string GetNameByID (string userId) {// return CallerFactory <IUserService>. instance. getNameByID (userId. toInt32 (); return string. concat ("Name:", userId );}}

We have noticed the above function code, except calling the business logic (Here we construct a data demonstration), there is actually no additional code. However, we started to identify a feature in the function:

[Cache (ExpirationPeriod = 30)]

Or

[Cache]

This is the function that we declare to use cache for processing. That's all, isn't it very easy.

Let's take a look at the decompilation results of the generated code, as shown below.

This is not the same as our actual code. Here we integrate PostSharp's woven code to implement cache processing operations, but we are transparent during the development process, you only need to maintain your own code.

The CacheAttribute must be used for identification. The code of this class uses the base class PostSharp for processing.

/// <Summary> /// method to implement the cache identity /// </summary> [Serializable] public class CacheAttribute: methodInterceptionAspect {/// <summary> /// cache expiration time setting. The default value is 30 minutes /// </summary> public int ExpirationPeriod = 30; /// <summary> /// PostSharp call processing to implement data cache processing /// </summary> public override void OnInvoke (MethodInterceptionArgs args) {// The default value is 30 minutes. If the expiration time is set, set the value TimeSpan timeSpan = new TimeSpan (0, 0, ExpirationPeri Od, 0); var cache = MethodResultCache. getCache (args. method, timeSpan); var arguments = args. arguments. toList (); var result = cache. getCachedResult (arguments); if (result! = Null) {args. returnValue = result; return;} else {base. onInvoke (args); // update the cache again after calling. cacheCallResult (args. returnValue, arguments );}}}

This CacheAttribute feature class contains a set expiration interval (minutes) to specify the expiration time of the function returned results. By inheriting the MethodInterceptionAspect base class, we override void OnInvoke (MethodInterceptionArgs args) function to intervene in the horizontal plane of the call process:

If the cache result is obtained during the call, the system returns the result directly without calling the function business logic. Otherwise, the system calls the function to obtain the returned value and resets the cache result value.

In the function code, the method cache object is constructed by passing in parameters (including method objects and timeout time.

MethodResultCache.GetCache(args.Method, timeSpan);

In MethodResultCache, we process the method cache. First, we need to declare a MemoryCache object for managing the cache (distributed cache ).

/// <Summary> /// initialize the cache manager /// </summary> private void InitCacheManager () {_ cache = new MemoryCache (_ methodName );}

The function is used to obtain the key of the method and parameter, that is, the unique key.

/// <Summary> /// obtain the cache key based on the call method name and parameters /// </summary> /// <param name = "arguments"> list of parameters of the Method </param> // <returns> </returns> private string GetCacheKey (IEnumerable <object> arguments) {var key = string. format ("{0} ({1})", _ methodName, string. join (",", arguments. select (x => x! = Null? X. ToString (): "<Null>"); return key ;}

To set the cache, we call the MemoryCache Cache Management class to set the key value, as shown in the following code.

/// <Summary> /// cache result content /// </summary> /// <param name = "result"> result to be added to the cache </param>/ // <param name = "arguments"> set of parameters of the method </param> public void CacheCallResult (object result, IEnumerable <object> arguments) {_ cache. set (GetCacheKey (arguments), result, DateTimeOffset. now. add (_ expirationPeriod ));}

In this way, we set a key value cache and specify the cache expiration time. During this period, we do not need to call the external interface again for each data we obtain, it is obtained directly from the cache, which improves the speed and reduces the I/O workload of servers in the distributed architecture.

We can write a short piece of code to test the efficiency, as shown in the following code.

            //First test            DateTime start = DateTime.Now;            var list = CacheService.GetSimpleUsers(1);            int end = (int)DateTime.Now.Subtract(start).TotalMilliseconds;            Console.WriteLine(" first: " + end);            //Second test            start = DateTime.Now;             list = CacheService.GetSimpleUsers(2);            end = (int)DateTime.Now.Subtract(start).TotalMilliseconds;            Console.WriteLine(" Second: " + end);

The result is as follows (the time when the result is obtained is described respectively ).

 first: 519 Second: 501 first: 0 Second: 0 first: 0 Second: 0

From the code above, we can see that there is a certain time difference between the first request data, and the number of milliseconds after the request is directly 0.

Through the integration of PostSharp and MemoryCache above, we can greatly simplify the cache processing code and use a relatively good MemoryCache Cache Management class to implement cache processing, which is very convenient and efficient.

The author has several related articles. By the way, it is really good:

Use PostSharp in the. NET project to implement AOP Aspect-Oriented Programming

Use PostSharp in the. NET project and MemoryCache for cache Processing

Use PostSharp in the. NET project and CacheManager to implement processing of multiple cache frameworks

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.