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);