Home > C#, WCF > Caching in WCF Services: Part 1

Caching in WCF Services: Part 1

This is the first part of a two part article about caching in WCF services. In this part I will explain the in-process memory cache available in .NET 4.0. In the second part I will describe the Windows AppFabric distributed memory cache.

The .NET framework has provided a cache for ASP.NET applications since version 1.0. For other types of applications like WPF applications or console application, caching was never possible out of the box. Only WCF services were able to use the ASP.NET cache if they were configured to run in ASP.NET compatibility mode. But this mode has some performance drawbacks and only works when the WCF service is hosted inside IIS and uses an HTTP-based binding.

With the release of the .NET 4.0 framework this has luckily changed. Microsoft has now developed an in-process memory cache that does not rely on the ASP.NET framework. This cache can be found in the “System.Runtime.Caching.dll” assembly.

In order to explain the working of the cache, I have a created a simple sample application. It consists of a very slow repository called “SlowRepository”.

public class SlowRepository
{
    public IEnumerable GetPizzas()
    {
        Thread.Sleep(10000);

        return new List() { "Hawaii", "Pepperoni", "Bolognaise" };
    }
}

This repository is used by my sample WCF service to gets its data.

public class PizzaService : IPizzaService
{
    private const string CacheKey = "availablePizzas";

    private SlowRepository repository;

    public PizzaService()
    {
        this.repository = new SlowRepository();
    }

    public IEnumerable GetAvailablePizzas()
    {
        ObjectCache cache = MemoryCache.Default;

        if(cache.Contains(CacheKey))
            return (IEnumerable)cache.Get(CacheKey);
        else
        {
            IEnumerable availablePizzas = repository.GetPizzas();

            // Store data in the cache
            CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
            cacheItemPolicy.AbsoluteExpiration = DateTime.Now.AddHours(1.0);
            cache.Add(CacheKey, availablePizzas, cacheItemPolicy);

            return availablePizzas;
        }
    }
}

When the WCF service method GetAvailablePizzas is called, the service first retrieves the default memory cache instance

ObjectCache cache = MemoryCache.Default;

Next, it checks if the data is already available in the cache. If so, the cached data is used. If not, the repository is called to get the data and afterwards the data is stored in the cache.

For my sample service, I also choose to restrict the maximum memory to 20% of the total physical memory. This can be done in the web.config.

<system.runtime.caching>
 <memoryCache>
  <namedCaches>
   <add name="Default" physicalMemoryLimitPercentage="20"/>
  </namedCaches>
 </memoryCache>
</system.runtime.caching>
Advertisements
Categories: C#, WCF
  1. August 10, 2012 at 12:24

    Please blog the Appfabric thingy fast…. 🙂

  2. August 14, 2012 at 12:57

    Hi Pieter,
    Is it possible to use ObjectCache in a Multi Server hosting environment? Or by any method is it possible to acheive this?

    • pieterderycke
      August 14, 2012 at 13:02

      Hello Abin,

      It is possible to use this in a multi server hosting environment, but every server will have its own dedicated cache. It is not possible to share a cache between severs with this solution. If you want to share the cache between servers you need to use the AppFabric cache.

      • August 14, 2012 at 14:09

        The Problem for me to use Appfabric is that, Objects that I am trying to Cache with Appfabric cannot be serialized. Because I am trying with SharePoint Client Object Model based objects to cache. That is why I am asking for Distributed Cache solution.

  3. August 14, 2012 at 14:10

    Abin Jaik Antony :
    The Problem for me to use Appfabric is that, Objects that I am trying to Cache with Appfabric cannot be serialized. Because I am trying with SharePoint Client Object Model based objects to cache. That is why I am asking for Distributed Cache solution which is capable of caching non CLR/ non serializable objects

    • pieterderycke
      August 15, 2012 at 06:54

      What you ask is impossible. A cache will store the objects for reuse, if an object is non serialize, it cannot be stored. So no .NET cache will offer you such functionality. What do you want to cache exactly?

  4. Swapna
    October 4, 2012 at 02:20

    Thank you so much. This is really useful!!

  5. October 31, 2012 at 10:43

    Hi Pieter,

    Thanks for your post. I need one help/suggestion from you. I have implemented a similar code as you have. But the problem I am facing in my visual studio debugging process is that my existing cache becomes empty with no keys in it after some seconds i return to fetch the catched data. I tried the same solution in iis hosting in my machine but the same results. Please can you help where I might have done a mistake. Also I have check thoroughly for all the possibilities but still stuck.

    • Gisela
      November 1, 2012 at 21:29

      Hi Pieter,

      i have the same problem. The WCF service is hosted under IIS7.5 and after a few of minutes the cache is empty. Have you found a solution? It’s very urgent. Please help.

  6. pieterderycke
    November 1, 2012 at 22:00

    You are using an in-process cache. So if you restart/recycle the IIS pool, the content of the cache is lost (so you have an empty cache). The same with the Visual Studio web server: if you restart it, you will loose your cache.

    If you want a cache that can survive this, you need an out-of-process cache like the one of AppFabric:
    https://pieterderycke.wordpress.com/2012/08/28/caching-in-wcf-services-part-2-appfabric-distributed-cache/

  7. January 8, 2013 at 13:03

    Hey, this is great stuff. thanks! In the Web.Cache, I am able to clear (iterate all the cache items) with things like:

    For Each voCacheItem As DictionaryEntry In Current.Cache
    If voCacheItem.Value.GetType().FullName = GetType(AppDomain).FullName Then
    AppDomain.Unload(CType(voCacheItem.Value, AppDomain))
    End If
    Current.Cache.Remove(voCacheItem.Key)
    Next

    How can this be done on the MemoryCache? Appreciate your help. cheers!

  8. umaarr
    April 13, 2013 at 10:26

    What is thread.sleep(10000) for?

    • pieterderycke
      April 13, 2013 at 18:38

      just to simulate something slow. It means hold the execution for 10 seconds.

  9. umaarr
    April 13, 2013 at 10:38

    and what i require to do if need to add pizzaes i.e set pizzas in list dynamically?
    p.s Im new to WCF and having difficulties with cashing.

    • pieterderycke
      April 13, 2013 at 18:39

      The pizzas are just an example 🙂
      Can you explain your question in more detail? I do not understand it completely.

      • umaarr
        April 13, 2013 at 19:42

        Good to hear from you Pieter,
        Well I guess i understand the scenario and thank you very much it’s really helpful 🙂

  10. john doe
    January 9, 2014 at 19:44

    This code will not work properly as it is not thread-safe. Since there is no lock around the read/write of the cache there is at least one race condition. For example (exaggerated to show a point): if repository.GetPizzas() takes a full second to execute and if 5 requests come in with in that second – all five requests will call repository.GetPizzas() because the cache was empty when they entered. Now the cache will be set 5 times as each request is finished. So in other words, while repository.GetPizzas() is executing more requests are coming in which makes repository.GetPizzas() run even slower – so more and more threads (requests) are likely to come in during this time and you can see where this is going…

    That is just the first race condition (bug) I’ve found with this code. It needs to be locked and/or async-ed properly to make it thread safe and avoid performance / logical bugs when the cache is empty/expired.

  11. Lloyd
    February 11, 2014 at 12:36

    Hey John, MemoryCache is thread safe..so is there any need to lock that further?

  12. Issa
    January 25, 2015 at 14:52

    Hi Lloyd,

    The memory cache is thread safe, but the data you put in it is not thread Safe, meaning that the internal state of objectCache is consistent in a multi thread scenario
    The explanation of John Doe is right, and you should locking your cache.

    I think you should read the interesting article of eric lippert about thead safety.

    http://blogs.msdn.com/b/ericlippert/archive/2009/10/19/what-is-this-thing-you-call-thread-safe.aspx

  1. No trackbacks yet.

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

%d bloggers like this: