. NET Cache Module Design Practice _ Practical skills

Source: Internet
Author: User

Last article on the concept of caching, the framework of understanding and views, this undertaking on my own cache module design practice.

Basic Cache Module Design
The most basic caching module must have a unified cachehelper, as follows:

  Public interface Icachehelper
  {   
    T get<t> (string key);
        
    void set<t> (String key, T value);   

    void Remove (string key);        
  

And then the business layer is called like this

  Public User get (int id)
    {
      if (id <= 0)
        throw new ArgumentNullException ("id");

      The var key = string. Format (User_cache_key, id);
      var user = _cachehelper.get<user> (key);
      if (user!= null) return
        user;

      Return _repository. Get (ID);
    }  

There is nothing wrong with the above code, but the actual use of the time is questionable, because I always stressed that the cache to save "hot data", so "hot data" must have expired, we can not write another to set. So it's more appropriate to simply combine it with writing.

Public User GetV2 (int id)
{
  if (id <= 0)
    throw new ArgumentNullException ("id");

  The var key = string. Format (User_cache_key, id);
  var user = _cachehelper.get<user> (key);
  if (user!= null) return
    user;
    user = _repository. Get (ID);
  if (user!= null)
    _cachehelper.set (key, user);
    return user;
}

The code above is actually just adding a set, so the design, each time a get need to repeat the code is too much, then should be more streamlined? It is necessary to eat some C # grammar sugar at this time, the grammar sugar occasionally eat point to improve efficiency, why not?

Public User GetV3 (int id)
{
   if (id <= 0)
     throw new ArgumentNullException ("id");

   The var key = string. Format (User_cache_key, id);
    Return _cachehelperv2.get<user> (Key, () => _repository. Get (ID));      
}

Icache get<t> Implementation public
T get<t> (string key, func<t> fetch = null)
{
  t result = default (t );
  var obj = cache.get (key);
  if (obj is T)
  {result
    = (T) obj;
  }

  if (result = = null)
  {result
    = Fetch ();

    if (result!= null)
      Set (key, result);
  }

  return result;
}      

Here I package the set method directly into the ICACHE.GET<T>, with the fetch Func. In this way, the common operations are abstracted together, simplifying the cache call, which is perfectly in line with my idea.

Cache Module Design Advanced
the Icache V3 in the previous section was almost the most streamlined, but after referring to Servicestack.redis, I found a much more abstract approach. Obviously, all the code in the previous section is manually managed key, for the usual object cache, does this key need to be manual? to the last improvement.

Public T get<t> (object ID, func<t> fetch = null)
{
  var type = typeof (T);
  The var key = string. Format (' urn:{1}:{2} ', type. Name, ID. ToString ());//Here is the key, directly using TypeName to act as key return get

  (key, Fetch);
}

Public T get<t> (string key, func<t> fetch = null)
{
  t result = default (t);

  var obj = cache.get (key);
  if (obj is T)
  {result
    = (T) obj;
  }

  if (result = = null)
  {result
    = Fetch ();

    if (result!= null)
      Set (key, result);
   }

   return result;
}

The Get method completely automates the management of the key, and then calls the way again to be streamlined.

Public User GetV4 (int id)
{
   if (id <= 0)
    throw new ArgumentNullException ("id");

   return _cachehelperv3.get<user> (ID, () => _repository. Get (ID));
}

It's obvious that the most important set is missing, set, when this key gets to cost a little bit, the most need to solve is how to get the value of this primary key ID.

public class User
{
    [PrimaryKey]//This attribute is the most important thing public
    int UserId {get; set;}

    public string UserName {get; set;}

    public string Cellphone {get; set;}
}
public void set<t> (T obj)
{
   //here should be cached to increase the efficiency of reflection
   var type = typeof (T);
   var PrimaryKey = type. GetProperties ()
        . FirstOrDefault (t => t.getcustomattributes (FALSE)
          . Any (c => c is primarykeyattribute);//This gets the value var keyvalue of ID by taking Primarykeyattribute
    = Primarykey.getvalue ( obj, null);      
    The var key = string. Format (' Urn:{0}:{1} ', type. Name, keyvalue);

    var dt = DateTime.UtcNow.AddDays (1);//Suppose the default cache is 1 days
    var offset = new DateTimeOffset (DT);
    Cache.set (key, obj, offset);
}

Here, I think of the final version of the Icache is done. It also needs to be explained that in fact PrimaryKey can be more flexible and changeable. Many times the PrimaryKey of an object is complex, and when you design a cache entity you can work with it:

public class usercacheentity
{
    [PrimaryKey] public
    int ID
    {get
      {return
        string. Format ("{0}:{1}", UserId, UserName);
      }

    public int UserId {get; set;}

    public string UserName {get; set;}

    public string Cellphone {get; set;}
}

The above way can almost automatically manage the common data cache, the only trouble is to customize a cacheobject, which brings the problem of entity conversion, this time it depends on how to choose.
Again, I want the Icache design:

1. Always only cache heat data, which means that each key must have an expiration time
2. Icache Automatic Management Get/set, it is best to automatically manage key.
3. Icache streamlining while not losing flexibility.
Detailed code demo can refer to: Git

more flexible Implementation
Before I write this summary, I have been thinking about the cache should be put on what layer, normal three floor where to put? Where does DDD go when it's layered? Google the next, see some references.
Http://stackoverflow.com/questions/15340173/in-which-layer-implement-the-cache
I think this is more in line with my idea, cache should be global arbitrary, of course, the realization of course is INTERFACE+IOC, so that the more independent reference.
In addition to the cache more advanced use, AOP combined with Icache V4 such a design, is not better? Here I have not yet to implement the attributes of AOP, this is a big topic, the next time to achieve it.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.