24
votes

I use the Entity Framework database-first approach to generate a DbContext / POCO model for an MVC application. I want to avoid having dependencies on DbContext in my controllers to enable me to switch to another persistence provider as I need to (for example for unit testing purposes).

To do this I want to use the Castle Windsor IoC container. I plan to register DbContext as an IUnitOfWork service and to register a generic IRepository service, implementations of which I will use to access and work with aggregate roots in the model.

I'm new to Windsor and haven't been able to find much info about using it with EF, and I have a couple of questions:

  • is this a reasonable approach if I want to decouple EF from the application?
  • how do I install / register the IUnitOfWork and generic IRepository services?
1
To whoever marked this down ... would you like to provide a comment saying why? If you think I have missed the point somewhere, you might help me by explaining why.Paul Taylor
I think it was down voted because this is a discussion question, not really appropriate for StackOverflow, especially the first point. The second point can be found at the Castle Windsor site, they have excellent documentation. Wrt the content of your question: mocking DbContext for unit tests is virtually impossible. I use 'unit test' projects against a database for DAL testing besides pure unit test projects for other BL. Caste Windsor injects contexts from a context factory, not interfaced, and interfaced services, validators etc.Gert Arnold
Thanks for your comment @GertArnold. Regarding the mocking issue, I'm not wanting to unit test the DAL, but to be able to provide mock repositories to the application layer (eg controllers), to test it. The Castle documentation is good in general, but deals with NHibernate integration, and is pretty sketchy in that area.Paul Taylor
I can't believe this was marked down. A couple of perfectly interesting questions there.Ackroydd
Before you start creating a IUnitOfWork and a generic Repository you might want to read this: ayende.com/blog/3955/repository-is-the-new-singleton. (I hope I don't get flamed for this one). The blog might give you more interesting ideas about unit testing and NHibernate as wellMarwijn

1 Answers

25
votes

So, some conclusions. I thought I'd write this up in case it is of use to someone else trying to use / unit test EF, Windsor and MVC together.

First of all, as DbContext implements both the Repository and Unit of Work patterns, you need to take view on whether these implementations will serve or whether you need to create your own.

I chose to create my own Repository, following the DDD pattern: one per aggregate root. The reasons: to encapsulate query code, to prevent it from leaking into the application layer, and to be able to mock more easily when testing the application controllers. I created a generic repository based on IRepository<TEntity>. There are plenty of examples out there. I found this a good one: http://architects.dzone.com/articles/implementing-repository

On the other hand I decided to drop the IUnitOfWork service, opting for the default implementation instead. However, I created an IDbContext abstraction (don't know why Microsoft didn't do this themselves), so that I could mock the DbContext when testing the Repository services.

I gave IDbContext only the members of DbContext that I wanted to use in the repository. So:

public interface IDbContext: IDisposable
{
    Database Database { get; }
    DbEntityEntry Entry(object entity);
    IDbSet<TEntity> Set<TEntity>() where TEntity : class;
    int SaveChanges();
}

I then created a Windsor facility and installer for my IDbContext and IRepository services:

public class EntityFrameworkFacility: AbstractFacility
{
    protected override void Init()
    {
        Kernel.Register(Component.For<IDbContext>()
                                 .ImplementedBy<MyEntities>()
                                 .LifestylePerWebRequest(),
                        Component.For(typeof(IRepository<>))
                                 .ImplementedBy(typeof(Repository<>))
                                 .LifestylePerWebRequest());
    }
}

public class PersistenceInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.AddFacility<EntityFrameworkFacility>();
    }
}

The final piece was to extend the Entity Framework context class to implement IDbContext, and to shadow the Set() method to return IDbSet rather than DbSet:

public partial class MyEntities : IDbContext
{
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }
}

With all this in place (and the ControllerFactory registration illustrated in the Windsor docs), it becomes trivial to get Windsor to inject IRepository objects (or IDbContext) into controller constructors, as required:

public ControllerBase(IRepository<Contact> repo)
{
    _repo = repo;
}

In the Repository unit tests, a real repository instance can be backed with a mock IDbContext:

mocks = new MockRepository();
context = mocks.StrictMock<IDbContext>();
repo = new Repository<Contact>(context);

In Controller unit tests, a mock repository can be used:

mocks = new MockRepository();
repo = mocks.StrictMock<IRepository<Contact>>();
ContactController controller = new ContactController(repo);