0

I am working on a C# MVC5 project using EF6. Currently the context is created in the UnityConfig.cs class, which is called from the Application_Start() in Global. See some of use UnityConfig class below:

public static void RegisterComponents()
{
   var container = new UnityContainer();
   BlogSite.Domain.BlogSiteModelContainer context = new Domain.BlogSiteModelContainer();
   container.RegisterType<IBlogRepository, BlogRepository>(new InjectionConstructor(context));
}

The problem with this is that the database may be updated directly and so the EF context will become inconsistent. So I need to change it so that it is re-loaded each time there is a new http request.

I have found that PerRequestLifetimeManager may be the solution for this, however, I can't find a good example of how I should use this.

How should I go about implementing this? Or is there a better way?


So I have tried a few things but still not getting anywhere. I realise I can add in a lifetime manager with the container.RegisterType() method, but I assume that only applies to the repository and not the Entity Framework context.

e.g.

container.RegisterType<IBlogRepository, BlogRepository>(new PerRequestLifetimeManager(), new InjectionConstructor(context));

I'm still not sure how set the lifetime of the context. I realise I'll probably have to re-format the code a bit but I can't find an example of this situation anywhere.


I've been doing more research, and have looked at the idea of creating a Unit of Work to create the context within and pass it to the repositories. Not sure if its the best way forward, but it seems to be one that might work. Any thoughts on that?

AndrewPolland
  • 3,041
  • 4
  • 28
  • 39
  • 1
    Not only will your dbcontext become stale, but it will bloat up as it caches more and more crap from previous interactions. It's not meant to be long-lived. Generally I try to keep the lifetime of the context to an absolute minimum by newing one up inline with a `using` statement around the required scope. I don't know how this will play with your DI though. – spender Apr 28 '14 at 14:31
  • The method above, or a similar method needs to be exposed in a way that you can call it via each request, for example ReRegisterComponents(). However, this kind of negates some of the advantages of di. – Ross Bush Apr 28 '14 at 14:31
  • 1
    Couldn't you just instantiate your context in your controller base class? Wouldn't that solve your problem without over-engineering? – mambrow Apr 28 '14 at 14:34
  • I should mention that it will need to still be possible to mock the repositories for my unit tests. – AndrewPolland Apr 28 '14 at 14:36
  • Your problem is that you're newing up your context outside of your DI framework, so it's always injecting the same instance. You need to configure your DI to instantiate your context. – Erik Funkenbusch Apr 30 '14 at 13:50
  • possible duplicate of [Unity Lifetime Managers & EF Data Context --> Best Practice](http://stackoverflow.com/questions/18253100/unity-lifetime-managers-ef-data-context-best-practice) – Erik Funkenbusch Apr 30 '14 at 13:55

1 Answers1

0

Found the solution. I needed to create a UnitOfWork class which I created the context within and the repositories. I then used Unity to inject the UnitOfWork class into the controllers with the PerRequestLifetimeManager lifetime manager.

So my UnitOfWork class (which is stored in my DAL project) is:

public class UnitOfWork : IDisposable
{
    private static BlogSite.Domain.BlogSiteModelContainer context;
    public IBlogRepository blogRepository;

    public UnitOfWork()
    {
        context = new BlogSite.Domain.BlogSiteModelContainer();;
        blogRepository = new BlogRepository(context);
    }

    public void Save()
    {
        context.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

And I register this simply in my UnityConfig class with the following:

container.RegisterInstance<UnitOfWork>(new UnitOfWork(), new PerRequestLifetimeManager());

In my controllers I then just had a few small changes to make to the constructors so that they would accept the UnitOfWork rather than the repositories.

E.g.

IBlogRepository blogRepo;

public BlogController(UnitOfWork unitOfWork)
{
   blogRepo = unitOfWork.blogRepository;
}
AndrewPolland
  • 3,041
  • 4
  • 28
  • 39
  • The context is already a unit of work. You're simply wrapping functionality that already exists and creating a layer of indirection that isn't required. – spender May 08 '14 at 22:18
  • @spender It's the only way I found which would work while keeping the DI and allowing me to mock everything in my unit tests. Do you have an alternative? I would be interested in improving my code if I can. – AndrewPolland May 09 '14 at 13:03
  • Missed the "mocking" bit. Ignore me. – spender May 11 '14 at 00:34