What is best practice for using Unity with Entity Framework in a MVC 4 application

asp.net-mvc-4 c# dependency-injection entity-framework unity-container

Question

I'm struggling with Entityframework in a MVC 4 app, making use of Unity for Dependency injection and Automapper for automapping object to DTO. I run from one issue to the other, EF is sometimes returning old data, so I think my design is not good enough.

What do I have:

To configure Unity I have in my Application_Start:

var UnityContainer = UnityConfig.GetConfiguredContainer();
Mapper.Initialize(cfg => cfg.ConstructServicesUsing(type => UnityContainer.Resolve(type)));
UnityContainer.Resolve<AutoMapperConfig>().MapAutoMapper();
...

In UnityConfig.RegisterTypes:

container.RegisterType<IMyContext, MyContext>(new ContainerControlledLifetimeManager())
...

My respositories use constructor depencency injection:

public class MSSQLTenantRepository : IDalTenantRepository
{
   private readonly IMyContext _Db;
   public MSSQLTenantRepository(IMyContext db)
   {
      Db = db;
   }
...

And my controller use constructor dependency injection too:

public class TenantController : Controller
{
   private readonly ITenantRepository _TenantRepository;
   public TenantController(ITenantRepository tenantRepository,
   {
      _TenantRepository = tenantRepository;
   }
...

Automapper config:

public class AutoMapperConfig
{
    private readonly ITenantRepository _TenantRepository;
    public AutoMapperConfig(ITenantRepository tenantRepository)
    {
        _TenantRepository = tenantRepository;
    }
...

Issues: I sometimes get old data, from the first request.

When I manually update the data in de SQL server, EF's returning object don't reflect the changes

When I tried different options I also got error about multiple context (due to Automapper)

My questions:

  • What is best practice using Unity, MVC4, EF 6, repositories and Automapper?
  • Where to put the code (e.g. in global.asax.c or in UnitiConfig.cs of UnityWebApiActivator?
  • Do I need to explicit dispose the dbcontext, and if so: Where to do this?

There is a lot said about this subject, but nothing covers all.

1
4
1/27/2014 12:30:54 PM

Accepted Answer

I figured it out with some help of Wiktor.

First: I must just a PerRequestLifeTimeManager (as stated by Wiktor Zychla, thank you for that), which is available in de Unity for MVC bootstrapper.

Second: The line:

UnityContainer.Resolve<AutoMapperConfig>().MapAutoMapper();

must be in Application_BeginRequest (Globas.asax.cs). I've put it in Application_Start, so this was only resolved once at startup. An incoming request was creating a new context, so it differs from the one that Automapper uses. When putting it in BeginRequest the resolve is done on every request, with the same context as the repositories.

3
1/27/2014 3:50:53 PM

Popular Answer

 container.RegisterType<IMyContext, MyContext>(
     new ContainerControlledLifetimeManager())

This is rather bad, it makes a singleton out of your context. This way not only multiple requests share the same context and you risk concurrency issues but also the memory consumption of such shared context grows without control.

Rather, you would like to have a "per-request" life time, where a new context is established for each separate request:

http://www.wiktorzychla.com/2013/03/unity-and-http-per-request-lifetime.html

public class PerRequestLifetimeManager : LifetimeManager
{
  private readonly object key = new object();

  public override object GetValue()
  {
    if (HttpContext.Current != null && 
        HttpContext.Current.Items.Contains(key))
        return HttpContext.Current.Items[key];
    else
        return null;
  } 

  public override void RemoveValue()
  {
    if (HttpContext.Current != null)
        HttpContext.Current.Items.Remove(key);
  }

  public override void SetValue(object newValue)
  {
    if (HttpContext.Current != null)
        HttpContext.Current.Items[key] = newValue;
  }
}

and

container.RegisterType<IMyContext, MyContext>(new PerRequestLifetimeManager())

I am not sure what your AutoMapperConfig class does and why a repository is injected into it. This is a possible another lifetime issue but I need a clarification on that.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow