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

In an MVC 4 application that uses Unity for dependency injection and Automapper for automatically mapping objects to DTOs, I'm having trouble with Entityframework. I keep running into problems, and since EF occasionally returns outdated information, I believe my design is inadequate.

What I have is:

To set up Unity, I have the following in my Application Start:

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

According to UnityConfig.RegisterTypes:

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

The resources I manage employ constructor dependency injection.

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

Additionally, my controller also employs constructor dependency injection

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

Automapper settings

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

Problems: I occasionally receive outdated data from the initial request.

EF's returned object doesn't reflect the changes when I manually update the data in the SQL server.

I experimented with various options. I also experienced a context-related error (due to Automapper)

My inquiries:

  • What is the ideal way to use Automapper, MVC4, and EF 6 repositories?
  • Where should the code go, for instance in UnityWebApiActivator's global.asax.c or UnitiConfig.cs?
  • Should I explicitly dispose of the database context, and if so, where should I do it?

Although much has been said about the issue, nothing fully covers it.

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

Accepted Answer

Wiktor was able to assist me in figuring it out.

First things first: I only need to use the PerRequestLifeTimeManager that the Unity MVC bootstrapper provides, as explained by Wiktor Zychla (thank you!).

Next: The phrase:

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

application begin request is a requirement (Globas.asax.cs). It was only once at starting because I put it in Application Start. It's different from the one Automapper uses because a new context was being created in response to an incoming request. The resolve is performed on each request when it is placed in the BeginRequest block, using the same context as the repository.

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

Popular Answer

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

This is not good because it removes a singleton from the context. By doing so, you run the danger of concurrency problems caused by many requests sharing the same context, as well as uncontrollable memory consumption from the shared context.

Instead, you prefer a "per-request" life time, in which a new context is created for each distinct 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'm unsure of what yourAutoMapperConfig what a repository is injected into the class for. It's possible that this is a problem from a previous existence, but I need more information 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