Adding support for a single connection string with multiple Entity Framework models using Dependency Injection

Recently I was working on a project that used more than one Entity Framework model to access different sections of the same database. The Entity Framework models were created using Model first to create edmx model files. The problem with this approach is that the connection string are unique to each model, as they contain model meta-data. This means that we have the same database connection string in several places.

Using our IoC container, we can create a dependency that will inject a single database connection string into each database context, which means that we can have a single database connection stored in our config file (web.config or app.config).

Creating a Entity Framework connection string

An Entity Framework connection string may be created in code using the EntityConnectionStringBuilder class (located in the System.Data.Entity.Core.EntityClient namespace). We will be using Castle Windsor to inject this connection string into our DbContext objects, so we should create an interface in a common project (i.e. a project that all the Entity Framework models will be able to access). We will call this interface IEntityFrameworkConnectionBuilder

    /// <summary>
    /// This interface allows the connection for an entity framework context to be determined from the model name. This will allow different EF models to use a single connection string
    /// </summary>
    public interface IEntityFrameworkConnectionBuilder
    {
        /// <summary>
        /// Create a EF connection string from the mode name
        /// </summary>
        /// <param name="modelName"></param>
        /// <returns></returns>
        string createEntityFrameworkConnection(string modelName);
    }

We can create the implementation of this interface in a project that has references to the EntityFramework libraries (installed by NuGet). The EntityFrameworkConnectionBuilder class is shown below:

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

using System.Data.Entity.Core.EntityClient;

namespace EF.Demo.Common
{
    /// <summary>
    /// This allows the connection for an entity framework context to be determined from the model name. This will allow different EF models to use a single connection string
    /// </summary>
    public class EntityFrameworkConnectionBuilder : IEntityFrameworkConnectionBuilder
    {

        public string _providerName;
        public string _dbConnectionstring;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="providerName"></param>
        /// <param name="dbConnectionstring"></param>
        public EntityFrameworkConnectionBuilder(string providerName, string dbConnectionstring)
        {
            _providerName = providerName;
            _dbConnectionstring = dbConnectionstring;
        }


        public string createEntityFrameworkConnection(string modelName)
        {
            var entityConnectionStringBuilder = new EntityConnectionStringBuilder();
            entityConnectionStringBuilder.Provider = _providerName;
            entityConnectionStringBuilder.ProviderConnectionString = _dbConnectionstring;
            entityConnectionStringBuilder.Metadata = string.Format(@"res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl", modelName);

            return entityConnectionStringBuilder.ToString();
        }
    }
}

As the provider and database connection string will be the same for all Entity Framework models, we can pass these into the EntityFrameworkConnectionBuilder as constructor parameters, which will be set by the IoC container.

The implementation of the createEntityFrameworkConnection method uses the EntityConnectionStringBuilder to build the correct entity framework connection string based on the supplied model name and the injected database provider and connection string.

Injecting the IEntityFrameworkConnectionBuilder into the Entity Framework context

We will use our IoC container to inject the IEntityFrameworkConnectionBuilder object into our Entity framework DB context classes. As the context classes are automatically generated by the Entity Framework model, we do not really want to manually alter these, as any changes would be lost if the model was regenerated. We can use partial classes to get around this problem.

When you created the model, you would have specified the EntityContainerName property. A class that inherits from DbContext will have been created in the model as the custom context for your model. In the same namespace, we can create a new class with this same name, and mark it as partial so that it will be merged with the generated class when compiled.

For example, if we created the Entity framework model with the EntityContainerName “MyModel”, we can create a MyModel partial class:

using EF.Demo.Common;

namespace EF.Demo.Common.Domain.Models
{
    /// <summary>
    /// A DB Context for the data model
    /// </summary>
    /// <remarks>
    /// This partial class allows a specific constructor to be specified for use with the IoC container
    /// As it is a partial file, the auto generated context may be re-generated without breaking this IoC specific bit
    /// </remarks>
    public partial class MyModel
    {
        /// <summary>
        /// Construct db context with the injected IEntityFrameworkConnectionBuilder and model name
        /// </summary>
        /// <param name="entityFrameworkConnectionBuilder"></param>
        /// <param name="modelName"></param>
        /// <remarks>
        /// This constructor is intended for use with an IoC container (e.g. Castle Windsor) to inject the properties
        /// and generate the correct connection string, using IEntityFrameworkConnectionBuilder
        /// </remarks>
        public MyModel(IEntityFrameworkConnectionBuilder entityFrameworkConnectionBuilder, string modelName)
            : base(entityFrameworkConnectionBuilder.createEntityFrameworkConnection(modelName))
        {
            
        }
    }
}

This class contains a constructor for the context that receives an instance of the IEntityFrameworkConnectionBuilder interface and the relevant model name. This constructor will be called by the IoC container, and the parameters will be resolved automatically (this will be described later when we configure the IoC container).

The connection string for the context is passed to the base DbContext by calling the base constructor and passing in the connection string generated from the IEntityFrameworkConnectionBuilder.createEntityFrameworkConnection(modelName) method.

Creating DbContext instances

Typically the Db Context objects are created with a using statement, to ensure that they are dispose of correctly when finished with.

using (var dbContext = new Models.OnlineFinances_Common())
{

}

However, we need a mechanism to create our context objects by resolving them through our IoC container so that the IEntityFrameworkConnectionBuilder object and model name may be passed to it, via the new constructor that we created. As we are going to use castle Windsor, we can make use of the Typed Factory Facility.

In order to create a typed factory, we need to create an interface with a Create<> and a Release<> method:

using System;
using System.Data.Entity;

namespace EF.Demo.Common
{
    /// <summary>
    /// A factory for creating and removing data base contexts
    /// </summary>
    /// <remarks>
    /// The purpose of this factory is to allow us to create dbContext instances 
    /// within code (probably in a using statement so it is disposed of correctly)
    /// but allow any dependencies in the context class to be resolved. The main dependency is
    /// the IEntityFrameworkConnectionBuilder, which will be added to a partial class for each specific
    /// DbContext based class. This interface will allow use to specify a single DB connection
    /// string for multiple Entity Framework models
    /// 
    /// This factory interface is not actually implemented anywhere. Instead
    /// we use Castle Windsor's Typed Factory Facility to auto create the abstract factory
    /// see http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx   
    /// and http://docs.castleproject.org/Windsor.Typed-Factory-Facility-interface-based-factories.ashx
    /// </remarks>
    public interface IEntityFrameworkContextFactory
    {
        T Create<T>()
            where T : DbContext;

        void Release<T>(T context)
            where T : DbContext;

    }
}

Wherever we are making use of the DbContext (e.g. a repository, a unit of work, or some other pattern), we can inject the IEntityFrameworkContextFactory and then use this to create our DbContext objects.

    public class MyRepository : IMyRepository
    {
        #region IoC injected dependencies

        private IEntityFrameworkContextFactory _entityFrameworkContextFactory;

        public MyRepository(IEntityFrameworkContextFactory entityFrameworkContextFactory)
        {
            if (entityFrameworkContextFactory == null)
                throw new ArgumentNullException("entityFrameworkContextFactory");

            _entityFrameworkContextFactory = entityFrameworkContextFactory;
        }

        #endregion

        public List<Models.SomeModel> getAllSomeModels()
        {
            // Use the IEntityFrameworkContextFactory to create the context. This will allow the IoC container to inject dependencies, such as the single connection string
            using (var dbContext = _entityFrameworkContextFactory.Create<Models.MyModel>())
            {
                return dbContext.SomeModel.ToList();
            }
        }
    }
}

Note that we are not calling the Release method from the factory, as in this case the context objects will be created with a transient lifecycle, which I believe means that they will be released when the using statement completes.

Castle Windsor Configuration

The final step is to register our various interfaces and classes with Castle Windsor.

In our root project, we can create an installer. The mechanism to run this installer will depend on the type of project, but for example in an ASP.NET MVC project, it would be installed from the Application_Start event in Global.asax.

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

using EF.Demo.Common;
using EF.Demo.Common.Domain;
using EF.Demo.Common.Domain.Models;


namespace EF.Demo.Web
{
    public class EntityFrameworkInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            // Register the IEntityFrameworkConnectionBuilder implementation
            // with the OnlineFinances db connection string
            container.Register(Component.For<IEntityFrameworkConnectionBuilder>()
                .ImplementedBy<EntityFrameworkConnectionBuilder>()
                .DependsOn(new
                    {
                        providerName = "System.Data.SqlClient",
                        dbConnectionString = System.Configuration.ConfigurationManager
                            .ConnectionStrings["MyConnectionString"]
                            .ConnectionString
                    })
                .LifestyleSingleton()
                );

            // Register the IEntityFrameworkContextFactory as a Typed Factory
            container.AddFacility<TypedFactoryFacility>()
                .Register(
                    Component.For<IEntityFrameworkContextFactory>()
                    .AsFactory());

            // Register the MyModel Entity framework context, with the correct model name
            container.Register(Component.For<MyModel>()
                .DependsOn(new
                    {
                        modelName = "Models.MyModel"
                    })
                .LifestyleTransient()
                );

        }
    }
}

In this installer, we are first registering the IEntityFrameworkConnectionBuilder interface with its implementation, and retrieving the database connection string from the configuration with the name MyConnectionString. We are also passing the provider type, which in this case is System.Data.SqlClient.

Next we register the IEntityFrameworkContextFactory as a Typed Factory.

Finally, we register all of the Entity Framework context objects. It is important that the correct model name is configured here, as this will be passed to the database context. To check what the model name should be, when you created the Entity Framework model, a connection string will have been created in the configuration file, this will have the model name embedded in it.

  <connectionStrings>
	  <add name="MyModel" connectionString="metadata=res://*/Models.MyModel.csdl|res://*/Models.MyModel.ssdl|res://*/Models.MyModel.msl;provider= ..
          />
  </connectionStrings>

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.

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.