Silverlight and WCF caching

There are scenarios where Silverlight client calls WCF (or REST) service for data.

Now, if the data is cached on the WCF layer, the calls can take considerable resources at the server if NOT cached. Keeping that in mind along with the fact that cache is an cross-cutting aspect, and therefore it should be as easy as possible to put Cache wherever required.

The good thing about the solution is that it caches based on the inputs. The input can be basic type of any complex type. If input changes the data is fetched and then cached for further used. If same input is provided again, data id fetched from the cache. The cache logic itself is implemented as PostSharp aspect, and it is as easy as putting an attribute over service call to switch on cache. Notice how clean the code is:

       [OperationContract]
      [CacheOnArgs(typeof(int))] // based on actual value of cache
       public string DoWork(int value)
       {
           return string.Format("You entered: {0} @ cached time {1}", value, System.DateTime.Now);
       }

The cache is implemented as POST Sharp as below

   1:  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
   2:          {
   3:              try
   4:              {
   5:                  object value = new object();
   6:                  object[] args = eventArgs.GetArgumentArray();
   7:                  if (args != null || args.Count() > 0)
   8:                  {
   9:   
  10:                      string key = string.Format("{0}_{1}", eventArgs.Method.Name, XMLUtility<object>.GetDataContractXml(args[0], null));// Compute the cache key (details omitted).
  11:   
  12:                  
  13:                      value = GetFromCache(key);
  14:                      if (value == null)
  15:                      {
  16:                          eventArgs.Proceed();
  17:                          value = XMLUtility<object>.GetDataContractXml(eventArgs.ReturnValue, null);
  18:                          value = eventArgs.ReturnValue;
  19:                          AddToCache(key, value);
  20:                          return;
  21:                      }
  22:   
  23:   
  24:                      Log(string.Format("Data returned from Cache {0}",value));
  25:                      eventArgs.ReturnValue = value;
  26:                  }
  27:              }
  28:              catch (Exception ex)
  29:              {
  30:                  //ApplicationLogger.LogException(ex.Message, Source.UtilityService);
  31:              }
  32:          }
  33:   
  34:  private object GetFromCache(string inputKey) { if (ServerConfig.CachingEnabled) { return WCFCache.Current[inputKey]; } return null; }private void AddToCache(string inputKey,object outputValue)
  35:         {
  36:             if (ServerConfig.CachingEnabled)
  37:             {
  38:                 if (WCFCache.Current.CachedItemsNumber < ServerConfig.NumberOfCachedItems)
  39:                 {
  40:                     if (ServerConfig.SlidingExpirationTime <= 0 || ServerConfig.SlidingExpirationTime == int.MaxValue)
  41:                     {
  42:                         WCFCache.Current[inputKey] = outputValue;
  43:                     }
  44:                     else
  45:                     {
  46:                         WCFCache.Current.Insert(inputKey, outputValue, new TimeSpan(0, 0, ServerConfig.SlidingExpirationTime), true); 
  47:   
  48:                        // _bw.DoWork += bw_DoWork;
  49:                         //string arg = string.Format("{0}|{1}", inputKey,outputValue);
  50:                         //_bw.RunWorkerAsync(inputKey );
  51:                     }
  52:                 }
  53:             }
  54:         } 
 
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The cache class  can be extended to support Velocity / memcahe / Nache.
the attribute can be used over REST services as well.
Hope the above helps. Here is the code base for the same.
 
Please do provide your inputs / comments.
 
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s