Entity Framework DbContext with Unity IoC

In the past, I have attempted a Unit of Work + Repository architecture. There are arguments that this is duplicate work since DbContext is a UnitOfWork and Repository. I have also found I needed to import the EntityFramework references into my application layer projects (which defeated some of my motivation for abstracting the DbContext).

In my most recent projects I have given up on forcing DbContext into my own Unit of Work and Repository. Now, I extract an IDbContext interface so I can test against mocks more easily.

Package and Framework versions in this article

  1. MVC5
  2. WebApi 2
  3. Entity Framework 6
  4. Unity 4
  5. Unity.Mvc
  6. Unity.AspNet.WebApi
  7. Moq 4

IDbContext

I abstract my own interface so I can mock and test without an actual database.

public class MovieDbContext : DbContext, IMovieDbContext
{
    public MovieDbContext(string connectionString)
        : base(connectionString)
    {
        // configuration settings
    }

    public virtual IDbSet<Movie> Movies { get; set; }
    public virtual IDbSet<Genre> Genres { get; set; }

    public override void OnModelCreating(DbModelBuilder modelBuilder) { ... }
}
public interface IMovieDbContext : IDisposable
{
    IDbSet<Movie> Movies { get; set; }
    IDbSet<Genre> Genres { get; set; }

    int SaveChanges();
}

Since I’m extending DbContext, IDisposable and SaveChanges() is implemented for me. I add to the interface if my application requires more of the DbContext’s methods.

I Moq this up on my test class

    protected virtual IMovieDbContext GetMockContext(IList<Movie> movies, IList<Genre> genres)
    {
        var dbSetMovies = GetMockDbSet<Movie>(movies);
        var dbSetGenres = GetMockDbSet<Genre>(genres);

        var mockContext = new Mock<IMovieDbContext>();
        mockContext.Setup(m => m.Movies).Returns(dbSetMovies);
        mockContext.Setup(m => m.Genres).Returns(dbSetGenres);

        return mockContext.Object;
    }

    protected virtual IDbSet<T> GetMockDbSet<T>(IList<T> data) where T : class
    {
        var queryable = data.AsQueryable();
        var mockSet = new Mock<IDbSet<T>>();
        mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
        mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
        mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
        mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
        mockSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => data.Add(s));

        return mockSet.Object;
    }

Service Layer

I now can segregate the query code into a service layer. I usually use AutoMapper, but for this example have manual projections.

public class MovieService : IMovieService
{
    private IMovieDbContext db;

    public MovieService(IMovieDbContext db)
    {
        this.db = db;
    }

    public MovieDto GetMovie(string title)
    {
        var query = db.Movies.Where(m => m.Title == title)
                             .Select(m => new MovieDto { Id = m.Id, Title = m.Title, Year = m.Year });

        var movie = query.FirstOrDefault();

        return movie;
    }
}

The service easily takes a DbContext mock to test the query logic without connecting to a database.

Controllers

The controller doesn’t care about the DbContext nor its query logic. The service is injected with the IoC container (Unity).

public class MovieController : Controller
{
    private IMovieService service;

    public MovieController(IMovieService service)
    {
        this.service = service;
    }

    public ActionResult GetMovie(string title)
    {
        var movie = this.service.GetMovie(title);
        return View("MovieDetail", movie);
    }
}

Unity IoC

I include the Unity.Mvc and Unity.AspNet.WebApi bootstrappers which provide the UnityMvcActivator.cs and UnityWebApiActivator.cs files. I uncomment the lines to get the per request lifetime object management.

// UnityMvcActivator.cs
   // TODO: Uncomment if you want to use PerRequestLifetimeManager
   Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

// UnityWebApiActivator.cs
   // Use UnityHierarchicalDependencyResolver if you want to use a new child container for each IHttpController resolution.
   var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.GetConfiguredContainer());

And finally, register your types with the container in UnityConfig.cs.

public static RegisterTypes(IUnityContainer container)
{
    container.RegisterType<IMovieDbContext, MovieDbContext>(new PerRequestLifetimeManager(),
        new InjectionConstructor("name=MovieDbConnection");
    container.RegisterType<IMovieService, MovieService>(new PerRequestLifetimeManager());
}

Now I have a testable application without a hard dependency on the database. I still need the EntityFramework reference in the Web project but my controllers don’t really know that.