Adding SQL Cache Dependencies to the Loosely coupled .NET Cache Provider

This post adds SQL Cache Dependency support to the loosely coupled .NET Cache Provider that I described in the previous post (https://rhamesconsulting.com/2012/09/14/loosely-coupled-net-cache-provider-using-dependency-injection/). The sample code is available on github at https://github.com/RobinHames/CacheProvider.git.

Each time we want to apply a cache dependency to a call to fetch or cache a data item we need to supply an instance of the relevant dependency implementation. This suggests an Abstract Factory will be useful to create cache dependencies as needed. We can then use Dependency Injection to inject the factory into the relevant consumer.

Castle Windsor provides a typed factory facility that will be utilised to implement the cache dependency abstract factory (see http://docs.castleproject.org/Windsor.Typed-Factory-Facility-interface-based-factories.ashx).

Cache Dependency Interfaces

First I created a set of cache dependency interfaces in the domain layer, which can be used to pass a cache dependency into the cache provider.

ICacheDependency

The ICacheDependency interface is simply an empty interface that is used as a parent for the specific cache dependency interfaces. This will allow us to place a generic constraint on the Cache Dependency Factory, and will give us a type that can be passed into the relevant Cache Provider methods.

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ICacheDependency
    {
    }
}

ISqlCacheDependency.cs

The ISqlCacheDependency interface provides specific SQL caching details, such as a Sql Command or a database connection and table. It is the concrete implementation of this interface that will be created by the factory in passed into the Cache Provider.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ISqlCacheDependency : ICacheDependency
    {
        ISqlCacheDependency Initialise(string databaseConnectionName, string tableName);
        ISqlCacheDependency Initialise(System.Data.SqlClient.SqlCommand sqlCommand);
    }
}

If we want other types of cache dependencies, such as by key or file, interfaces may be created to support these (the sample code includes an IKeyCacheDependency interface).

Modifying ICacheProvider to accept Cache Dependencies

Next I modified the exisitng ICacheProvider<T> interface so that cache dependencies may be passed into a Fetch method call. I did this by adding two overloads to the existing Fetch methods, which take an IEnumerable<ICacheDependency> parameter (the IEnumerable allows more than one cache dependency to be included). I also added a method to create cache dependencies. This means that the implementation of the Cache Provider will require a dependency on the Cache Dependency Factory. It is pretty much down to personal choice as to whether this approach is taken, or whether the Cache Dependency Factory is injected directly into the repository or other consumer of Cache Provider. I think, because the cache dependency cannot be used without the Cache Provider, placing the dependency on the factory into the Cache Provider implementation is cleaner.

ICacheProvider.cs

using System;
using System.Collections.Generic;

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ICacheProvider<T>
    {
        T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
        T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry, IEnumerable<ICacheDependency> cacheDependencies);

        IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
        IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry, IEnumerable<ICacheDependency> cacheDependencies);

        U CreateCacheDependency<U>()
            where U : ICacheDependency;
    }
}

Cache Dependency Factory

Next I created the interface for the Cache Dependency Factory in the domain layer.

ICacheDependencyFactory.cs

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ICacheDependencyFactory
    {
        T Create<T>()
            where T : ICacheDependency;

        void Release<T>(T cacheDependency)
            where T : ICacheDependency;
    }
}

I used the ICacheDependency parent interface as a generic constraint on the create and release methods in the factory interface.

Now the interfaces are in place, I moved on to the concrete implementations.

ISqlCacheDependency Concrete Implementation

The concrete implementation of ISqlCacheDependency will need to provide an instance of System.Web.Caching.SqlCacheDependency to the Cache Provider implementation. Unfortunately this class is sealed, so I cannot simply inherit from this. Instead, I created an interface called IAspNetCacheDependency that will provide a Create method to create an instance of the relevant System.Web.Caching Cache Dependency type. This interface is specific to the ASP.NET implementation of the Cache Provider, so it should be defined in the same layer as the concrete implementation of the Cache Provider (the MVC UI layer in the sample code).

IAspNetCacheDependency.cs

using System.Web.Caching;

namespace CacheDiSample.CacheProviders
{
    public interface IAspNetCacheDependency
    {
        CacheDependency CreateAspNetCacheDependency();
    }
}

Next, I created the concrete implementation of the ISqlCacheDependency interface. This class also implements the IAspNetCacheDependency interface. This concrete implementation also is defined in the same layer as the Cache Provider implementation.

AspNetSqlCacheDependency.cs

using System.Web.Caching;
using CacheDiSample.Domain.CacheInterfaces;

namespace CacheDiSample.CacheProviders
{
    public class AspNetSqlCacheDependency : ISqlCacheDependency, IAspNetCacheDependency
    {
        private string databaseConnectionName;

        private string tableName;

        private System.Data.SqlClient.SqlCommand sqlCommand;

        #region ISqlCacheDependency Members

        public ISqlCacheDependency Initialise(string databaseConnectionName, string tableName)
        {
            this.databaseConnectionName = databaseConnectionName;
            this.tableName = tableName;
            return this;
        }

        public ISqlCacheDependency Initialise(System.Data.SqlClient.SqlCommand sqlCommand)
        {
            this.sqlCommand = sqlCommand;
            return this;
        }

        #endregion

        #region IAspNetCacheDependency Members

        public System.Web.Caching.CacheDependency CreateAspNetCacheDependency()
        {
            if (sqlCommand != null)
                return new SqlCacheDependency(sqlCommand);
            else
                return new SqlCacheDependency(databaseConnectionName, tableName);
        }

        #endregion

    }
}

ICacheProvider Concrete Implementation

The ICacheProvider interface is implemented by the CacheProvider class. This implementation is modified to include the changes to the ICacheProvider interface.

First I needed to inject the Cache Dependency Factory into the Cache Provider:

private ICacheDependencyFactory cacheDependencyFactory;

public CacheProvider(ICacheDependencyFactory cacheDependencyFactory)
{
    if (cacheDependencyFactory == null)
        throw new ArgumentNullException("cacheDependencyFactory");

    this.cacheDependencyFactory = cacheDependencyFactory;
}

Next I implemented the CreateCacheDependency method, which simply passes on the create request to the factory:

public U CreateCacheDependency<U>() where U : ICacheDependency
{
    return this.cacheDependencyFactory.Create<U>();
}

The signature of the FetchAndCache helper method was modified to take an additional IEnumerable<ICacheDependency> parameter:

private U FetchAndCache<U>(string key, Func<U> retrieveData, 
    DateTime? absoluteExpiry, TimeSpan? relativeExpiry, IEnumerable<ICacheDependency> cacheDependencies)
and the following code added to create the relevant System.Web.Caching.CacheDependency object for any dependencies and pass them to the HttpContext Cache:
CacheDependency aspNetCacheDependencies = null;

if (cacheDependencies != null)
{
    if (cacheDependencies.Count() == 1)
        // We know that the implementations of ICacheDependency will also implement IAspNetCacheDependency
        // so we can use a cast here and call the CreateAspNetCacheDependency() method
        aspNetCacheDependencies = 
            ((IAspNetCacheDependency)cacheDependencies.ElementAt(0)).CreateAspNetCacheDependency();
    else if (cacheDependencies.Count() > 1)
    {
        AggregateCacheDependency aggregateCacheDependency = new AggregateCacheDependency();
        foreach (ICacheDependency cacheDependency in cacheDependencies)
        {
            // We know that the implementations of ICacheDependency will also implement IAspNetCacheDependency
            // so we can use a cast here and call the CreateAspNetCacheDependency() method
            aggregateCacheDependency.Add(
                ((IAspNetCacheDependency)cacheDependency).CreateAspNetCacheDependency());
        }
        aspNetCacheDependencies = aggregateCacheDependency;
    }
}

HttpContext.Current.Cache.Insert(key, value, aspNetCacheDependencies, absoluteExpiry.Value, relativeExpiry.Value);

The full code listing for the modified CacheProvider class is shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using CacheDiSample.Domain.CacheInterfaces;

namespace CacheDiSample.CacheProviders
{
    public class CacheProvider<T> : ICacheProvider<T>
    {
        private ICacheDependencyFactory cacheDependencyFactory;

        public CacheProvider(ICacheDependencyFactory cacheDependencyFactory)
        {
            if (cacheDependencyFactory == null)
                throw new ArgumentNullException("cacheDependencyFactory");

            this.cacheDependencyFactory = cacheDependencyFactory;
        }

        public T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            return FetchAndCache<T>(key, retrieveData, absoluteExpiry, relativeExpiry, null);
        }

        public T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry, 
            IEnumerable<ICacheDependency> cacheDependencies)
        {
            return FetchAndCache<T>(key, retrieveData, absoluteExpiry, relativeExpiry, cacheDependencies);
        }

        public IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            return FetchAndCache<IEnumerable<T>>(key, retrieveData, absoluteExpiry, relativeExpiry, null);
        }

        public IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry, 
            IEnumerable<ICacheDependency> cacheDependencies)
        {
            return FetchAndCache<IEnumerable<T>>(key, retrieveData, absoluteExpiry, relativeExpiry, cacheDependencies);
        }

        public U CreateCacheDependency<U>() where U : ICacheDependency
        {
            return this.cacheDependencyFactory.Create<U>();
        }

        #region Helper Methods

        private U FetchAndCache<U>(string key, Func<U> retrieveData, 
            DateTime? absoluteExpiry, TimeSpan? relativeExpiry, IEnumerable<ICacheDependency> cacheDependencies)
        {
            U value;
            if (!TryGetValue<U>(key, out value))
            {
                value = retrieveData();
                if (!absoluteExpiry.HasValue)
                    absoluteExpiry = Cache.NoAbsoluteExpiration;

                if (!relativeExpiry.HasValue)
                    relativeExpiry = Cache.NoSlidingExpiration;

                CacheDependency aspNetCacheDependencies = null;

                if (cacheDependencies != null)
                {
                    if (cacheDependencies.Count() == 1)
                        // We know that the implementations of ICacheDependency will also implement IAspNetCacheDependency
                        // so we can use a cast here and call the CreateAspNetCacheDependency() method
                        aspNetCacheDependencies = 
                            ((IAspNetCacheDependency)cacheDependencies.ElementAt(0)).CreateAspNetCacheDependency();
                    else if (cacheDependencies.Count() > 1)
                    {
                        AggregateCacheDependency aggregateCacheDependency = new AggregateCacheDependency();
                        foreach (ICacheDependency cacheDependency in cacheDependencies)
                        {
                            // We know that the implementations of ICacheDependency will also implement IAspNetCacheDependency
                            // so we can use a cast here and call the CreateAspNetCacheDependency() method
                            aggregateCacheDependency.Add(
                                ((IAspNetCacheDependency)cacheDependency).CreateAspNetCacheDependency());
                        }
                        aspNetCacheDependencies = aggregateCacheDependency;
                    }
                }

                HttpContext.Current.Cache.Insert(key, value, aspNetCacheDependencies, absoluteExpiry.Value, relativeExpiry.Value);

            }
            return value;
        }

        private bool TryGetValue<U>(string key, out U value)
        {
            object cachedValue = HttpContext.Current.Cache.Get(key);
            if (cachedValue == null)
            {
                value = default(U);
                return false;
            }
            else
            {
                try
                {
                    value = (U)cachedValue;
                    return true;
                }
                catch
                {
                    value = default(U);
                    return false;
                }
            }
        }

        #endregion
    }
}

Wiring up the DI Container

Now the implementations for the Cache Dependency are in place, I wired them up in the existing Windsor CacheInstaller. First I needed to register the implementation of the ISqlCacheDependency interface:

container.Register(
    Component.For<ISqlCacheDependency>()
    .ImplementedBy<AspNetSqlCacheDependency>()
    .LifestyleTransient());

Next I registered the Cache Dependency Factory. Notice that I have not implemented the ICacheDependencyFactory interface. Castle Windsor will do this for me by using the Type Factory Facility. I do need to bring the Castle.Facilities.TypedFacility namespace into scope:

using Castle.Facilities.TypedFactory;

Then I registered the factory:

container.AddFacility<TypedFactoryFacility>();

container.Register(
    Component.For<ICacheDependencyFactory>()
    .AsFactory());

The full code for the CacheInstaller class is:

using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Castle.Facilities.TypedFactory;

using CacheDiSample.Domain.CacheInterfaces;
using CacheDiSample.CacheProviders;

namespace CacheDiSample.WindsorInstallers
{
    public class CacheInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For(typeof(ICacheProvider<>))
                .ImplementedBy(typeof(CacheProvider<>))
                .LifestyleTransient());

            container.Register(
                Component.For<ISqlCacheDependency>()
                .ImplementedBy<AspNetSqlCacheDependency>()
                .LifestyleTransient());

            container.Register(
                Component.For<IKeyCacheDependency>()
                .ImplementedBy<AspNetKeyCacheDependency>()
                .LifestyleTransient());

            container.AddFacility<TypedFactoryFacility>();

            container.Register(
                Component.For<ICacheDependencyFactory>()
                .AsFactory());
        }
    }
}

Configuring the ASP.NET SQL Cache Dependency

There are a couple of configuration steps required to enable SQL Cache Dependency for the application and database. From the Visual Studio Command Prompt, the following commands should be used to enable the Cache Polling of the relevant database tables:

aspnet_regsql -S <servername> -E -d <databasename> –ed
aspnet_regsql -S <servername> -E -d CacheSample –et –t <tablename>

(The –t option should be repeated for each table that is to be made available for cache dependencies).

Finally the SQL Cache Polling needs to be enabled by adding the following configuration to the <system.web> section of web.config:

    <caching>
        <sqlCacheDependency pollTime="10000" enabled="true">
            <databases>
                <add name="BloggingContext" connectionStringName="BloggingContext"/>
            </databases>
        </sqlCacheDependency>
    </caching>

(obviously the name and connection string name should be altered as required).

Using a SQL Cache Dependency

Now all the coding is complete. To specify a SQL Cache Dependency, I can modify my BlogRepositoryWithCaching decorator class (see the earlier post) as follows:

public IList<Blog> GetAll()
{
    var sqlCacheDependency = cacheProvider.CreateCacheDependency<ISqlCacheDependency>()
        .Initialise("BloggingContext", "Blogs");

    ICacheDependency[] cacheDependencies = new ICacheDependency[] { sqlCacheDependency };

    string key = string.Format("CacheDiSample.DataAccess.GetAll");

    return cacheProvider.Fetch(key, () =>
    {
        return parentBlogRepository.GetAll();
    },
        null, null, cacheDependencies)
    .ToList();
}

This will add a dependency of the “Blogs” table in the database. The data will remain in the cache until the contents of this table change, then the cache item will be invalidated, and the next call to the GetAll() repository method will be routed to the parent repository to refresh the data from the database.

Advertisement

Loosely coupled .NET Cache Provider using Dependency Injection

I have recently been reading the excellent book “Dependency Injection in .NET”, written by Mark Seemann, which I strongly recommend.

Reading the ideas around Dependency Injection made me realise that the Cache Provider code I wrote about earlier (see http://geekswithblogs.net/Rhames/archive/2011/01/10/using-the-asp.net-cache-to-cache-data-in-a-model.aspx) could be refactored to use Dependency Injection, which should produce cleaner code.

The goals are to:

  • Separate the cache provider implementation (using the ASP.NET data cache) from the consumers (loose coupling). This will also mean that the dependency on System.Web for the cache provider does not ripple down into the layers where it is being consumed (such as the domain layer).
  • Provide a decorator pattern to allow a consumer of the cache provider to be implemented separately from the base consumer (i.e. if we have a base repository, we can decorate this with a caching version). Although I used the term repository, in reality the cache consumer could be just about anything.
  • Use constructor injection to provide the Dependency Injection, with a suitable DI container (I use Castle Windsor).

The sample code for this post is available on github, https://github.com/RobinHames/CacheProvider.git

ICacheProvider

In the sample code, the key interface is ICacheProvider, which is in the domain layer.

using System;
using System.Collections.Generic;

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ICacheProvider<T>
    {
        T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
        IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
    }
}

This interface contains two methods to retrieve data from the cache, either as a single instance or as an IEnumerable. the second paramerter is of type Func<T>. This is the method used to retrieve data if nothing is found in the cache.

The ASP.NET implementation of the ICacheProvider interface needs to live in a project that has a reference to system.web, typically this will be the root UI project, or it could be a separate project. The key thing is that the domain or data access layers do not need system.web references adding to them.

In my sample MVC application, the CacheProvider is implemented in the UI project, in a folder called “CacheProviders”:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using CacheDiSample.Domain.CacheInterfaces;

namespace CacheDiSample.CacheProviders
{
    public class CacheProvider<T> : ICacheProvider<T>
    {
        public T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            return FetchAndCache<T>(key, retrieveData, absoluteExpiry, relativeExpiry);
        }

        public IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            return FetchAndCache<IEnumerable<T>>(key, retrieveData, absoluteExpiry, relativeExpiry);
        }

        #region Helper Methods

        private U FetchAndCache<U>(string key, Func<U> retrieveData, 
            DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            U value;
            if (!TryGetValue<U>(key, out value))
            {
                value = retrieveData();
                if (!absoluteExpiry.HasValue)
                    absoluteExpiry = Cache.NoAbsoluteExpiration;

                if (!relativeExpiry.HasValue)
                    relativeExpiry = Cache.NoSlidingExpiration;

                HttpContext.Current.Cache.Insert(key, value, null, absoluteExpiry.Value, relativeExpiry.Value);

            }
            return value;
        }

        private bool TryGetValue<U>(string key, out U value)
        {
            object cachedValue = HttpContext.Current.Cache.Get(key);
            if (cachedValue == null)
            {
                value = default(U);
                return false;
            }
            else
            {
                try
                {
                    value = (U)cachedValue;
                    return true;
                }
                catch
                {
                    value = default(U);
                    return false;
                }
            }
        }

        #endregion
    }
}

The FetchAndCache helper method checks if the specified cache key exists, if it does not, the Func<U> retrieveData method is called, and the results are added to the cache.

Using Castle Windsor to register the cache provider

In the MVC UI project (my application root), Castle Windsor is used to register the CacheProvider implementation, using a Windsor Installer:

using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

using CacheDiSample.Domain.CacheInterfaces;
using CacheDiSample.CacheProviders;

namespace CacheDiSample.WindsorInstallers
{
    public class CacheInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For(typeof(ICacheProvider<>))
                .ImplementedBy(typeof(CacheProvider<>))
                .LifestyleTransient());
        }
    }
}

Note that the cache provider is registered as a open generic type.

Consuming a Repository

I have an existing couple of repository interfaces defined in my domain layer:

IRepository.cs

using System;
using System.Collections.Generic;

using CacheDiSample.Domain.Model;

namespace CacheDiSample.Domain.Repositories
{
    public interface IRepository<T>
        where T : EntityBase
    {
        T GetById(int id);
        IList<T> GetAll();
    }
}

IBlogRepository.cs

using System;
using CacheDiSample.Domain.Model;

namespace CacheDiSample.Domain.Repositories
{
    public interface IBlogRepository : IRepository<Blog>
    {
        Blog GetByName(string name);
    }
}

These two repositories are implemented in the DataAccess layer, using Entity Framework to retrieve data (this is not important though). One important point is that in the BaseRepository implementation of IRepository, the methods are virtual. This will allow the decorator to override them.

The BlogRepository is registered in a RepositoriesInstaller, again in the MVC UI project.

using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

using CacheDiSample.Domain.CacheDecorators;
using CacheDiSample.Domain.Repositories;
using CacheDiSample.DataAccess;

namespace CacheDiSample.WindsorInstallers
{
    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(Component.For<IBlogRepository>()
                .ImplementedBy<BlogRepository>()
                .LifestyleTransient()
                .DependsOn(new 
                                {
                                    nameOrConnectionString = "BloggingContext"
                                }));
        }
    }
}

Now I can inject a dependency on the IBlogRepository into a consumer, such as a controller in my sample code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using CacheDiSample.Domain.Repositories;
using CacheDiSample.Domain.Model;

namespace CacheDiSample.Controllers
{
    public class HomeController : Controller
    {
        private readonly IBlogRepository blogRepository;

        public HomeController(IBlogRepository blogRepository)
        {
            if (blogRepository == null)
                throw new ArgumentNullException("blogRepository");

            this.blogRepository = blogRepository;
        }

        public ActionResult Index()
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            var blogs = blogRepository.GetAll();

            return View(new Models.HomeModel { Blogs = blogs });
        }

        public ActionResult About()
        {
            return View();
        }
    }
}

Consuming the Cache Provider via a Decorator

I used a Decorator pattern to consume the cache provider, this means my repositories follow the open/closed principle, as they do not require any modifications to implement the caching. It also means that my controllers do not have any knowledge of the caching taking place, as the DI container will simply inject the decorator instead of the root implementation of the repository.

The first step is to implement a BlogRepository decorator, with the caching logic in it. Note that this can reside in the domain layer, as it does not require any knowledge of the data access methods.

BlogRepositoryWithCaching.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CacheDiSample.Domain.Model;
using CacheDiSample.Domain.CacheInterfaces;
using CacheDiSample.Domain.Repositories;

namespace CacheDiSample.Domain.CacheDecorators
{
    public class BlogRepositoryWithCaching : IBlogRepository
    {
        // The generic cache provider, injected by DI
        private ICacheProvider<Blog> cacheProvider;
        // The decorated blog repository, injected by DI
        private IBlogRepository parentBlogRepository;

        public BlogRepositoryWithCaching(IBlogRepository parentBlogRepository, ICacheProvider<Blog> cacheProvider)
        {
            if (parentBlogRepository == null)
                throw new ArgumentNullException("parentBlogRepository");

            this.parentBlogRepository = parentBlogRepository;

            if (cacheProvider == null)
                throw new ArgumentNullException("cacheProvider");

            this.cacheProvider = cacheProvider;
        }

        public Blog GetByName(string name)
        {
            string key = string.Format("CacheDiSample.DataAccess.GetByName.{0}", name);
            // hard code 5 minute expiry!
            TimeSpan relativeCacheExpiry = new TimeSpan(0, 5, 0);
            return cacheProvider.Fetch(key, () =>
            {
                return parentBlogRepository.GetByName(name);
            },
                null, relativeCacheExpiry);
        }

        public Blog GetById(int id)
        {
            string key = string.Format("CacheDiSample.DataAccess.GetById.{0}", id);

            // hard code 5 minute expiry!
            TimeSpan relativeCacheExpiry = new TimeSpan(0, 5, 0);
            return cacheProvider.Fetch(key, () =>
            {
                return parentBlogRepository.GetById(id);
            },
                null, relativeCacheExpiry);
        }

        public IList<Blog> GetAll()
        {
            string key = string.Format("CacheDiSample.DataAccess.GetAll");

            // hard code 5 minute expiry!
            TimeSpan relativeCacheExpiry = new TimeSpan(0, 5, 0);

            return cacheProvider.Fetch(key, () =>
            {
                return parentBlogRepository.GetAll();
            },
                null, relativeCacheExpiry)
            .ToList();
        }
    }
}

The key things in this caching repository are:

  1. I inject into the repository the ICacheProvider<Blog> implementation, via the constructor. This will make the cache provider functionality available to the repository.
  2. I inject the parent IBlogRepository implementation (which has the actual data access code), via the constructor. This will allow the methods implemented in the parent to be called if nothing is found in the cache.
  3. I override each of the methods implemented in the repository, including those implemented in the generic BaseRepository. Each override of these methods follows the same pattern. It makes a call to the CacheProvider.Fetch method, and passes in the parentBlogRepository implementation of the method as the retrieval method, to be used if nothing is present in the cache.

Configuring the Caching Repository in the DI Container

The final piece of the jigsaw is to tell Castle Windsor to use the BlogRepositoryWithCaching implementation of IBlogRepository, but to inject the actual Data Access implementation into this decorator. This is easily achieved by modifying the RepositoriesInstaller to use Windsor’s implicit decorator wiring:

using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

using CacheDiSample.Domain.CacheDecorators;
using CacheDiSample.Domain.Repositories;
using CacheDiSample.DataAccess;

namespace CacheDiSample.WindsorInstallers
{
    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {

            // Use Castle Windsor implicit wiring for the blog repository decorator
            // Register the outermost decorator first
            container.Register(Component.For<IBlogRepository>()
                .ImplementedBy<BlogRepositoryWithCaching>()
                .LifestyleTransient());
            // Next register the IBlogRepository implementation to inject into the outer decorator
            container.Register(Component.For<IBlogRepository>()
                .ImplementedBy<BlogRepository>()
                .LifestyleTransient()
                .DependsOn(new 
                                {
                                    nameOrConnectionString = "BloggingContext"
                                }));
        }
    }
}

This is all that is needed. Now if the consumer of the repository makes a call to the repositories method, it will be routed via the caching mechanism. You can test this by stepping through the code, and seeing that the DataAccess.BlogRepository code is only called if there is no data in the cache, or this has expired.

The next step is to add the SQL Cache Dependency support into this pattern, this will be a future post.

Using JQuery Ajax method to pass Json to a MVC3 Action and return a partial view

ASP.NET MVC3 provides out of the box support for binding a Json data object into a Model on postback. This maybe used with a JQuery Ajax function call to post selected data back to an action. It is also possible to return a partial view from the same action, and refresh this from the ajax success callback function. For example:

In my MVC3 Razor project, I create two model classes:

public class NameResponseModel
{
    public string Name { get; set; }
    public DateTime CurrentDateTime { get; set; }
    public IList<int> Numbers { get; set; }
}
public class UpdateNameModel
{
    public string Name { get; set; }
    public IEnumerable<int> Numbers { get; set; }
}

The UpdateNameModel will be used to retrieve data submitted by the Ajax method call. It is this model that the Json object will bind to. The NameResponseModel class is used to pass information back to the UI via a template view.

In the Views/Shared/DisplayTemplates folder, I created a template that is strongly typed to the NameResponseModel class, called NameResponseModel.cshtml:

@model MvcJQuery.Models.NameResponseModel

<div>
<div class="display-label">
    Name: @Html.DisplayFor(m => m.Name)
</div>
<div class="display-label">
    Current Date Time: @Html.DisplayFor(m => m.CurrentDateTime)
</div>
@{
    var numbersCount = Model.Numbers.Count;

    for(int numberIndex = 0; numberIndex < numbersCount; numberIndex++)
    {
        <div class="display-label">
            Number: @numberIndex = @Html.DisplayFor(m => m.Numbers[numberIndex])
        </div>
    }
}
</div>

This template simply displays the contents of the associated NameResponseModel object.

Next, in the Home Controller, I added the following action:

public ActionResult UpdateName(UpdateNameModel updateNameModel)
{
    return PartialView("DisplayTemplates/NameResponseModel", new NameResponseModel
    {
        Name = updateNameModel.Name,
        CurrentDateTime = DateTime.Now,
        Numbers = updateNameModel.Numbers.ToList()
    });
}

This action takes a UpdateNameModel object as a parameter and simply copies this into a new instance of the NameResponseModel. It then returns the display template as a partial view.

Finally, my Home/Index.cshtml view looks like this:

@{
    ViewBag.Title = "Home Page";
}

<script type="text/javascript">
    $(function () {
        $('#UpdateName').click(function () {
            var inputName = $('#Name').val();
            var dataResponse = { Name: inputName, Numbers: [1, 45, 67, 89] };
            $.ajax({
                type: 'POST',
                contentType: 'application/json; charset=utf-8', 
                data: JSON.stringify(dataResponse),
                dataType: 'html',
                url: '@Url.Action("UpdateName")',
                success: function(result) {
                    $('#Response').html(result);
                }
            });
        });
    });
</script>

<h2>@ViewBag.Message</h2>
<p>
    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>

<div id="Response"></div>

<input type="text" id="Name" />
<button type="button" id="UpdateName">Update</button>

I’ve added a div with the Id=”Response”. This will be used to display the partial view following an Ajax update. When the “Update” button is clicked, the click event creates a Json object with the contents of the “Name” text input and an array of integers. Note that the names of the Json items must match exactly the names within the data model that the Json will be bound to. MVC3 will quite happily handle complex data binding, so the array of integers will be bound successfully to the Numbers IEnumerable<int> parameter in the UpdateNameModel class.

Other points to note are the contentType parameter of the Ajax call is set to ‘application/json; charset=utf-8’. This indicates that the parameter passed by the Ajax call will be a Json object. The Json object itself needs to be converted to a string, JSON.stringify will perform this function for us. The dataType parameter in the Ajax call is set to ‘html’. This indicates that the data returned by the server is expected to be html (the rendered partial view in this case). The success callback then simply loads this returned html into the “Response” div.

Hope this helps somebody! It took me a while, and a lot of googling, to figure it out!