MVC, EF – DataContext singleton instance Per-Web-Request in Unity

Yes do not share context and use one context per request. You can also check linked questions in that post to see all problems which a shared context caused.

Now about Unity. Idea of PerCallContextLifetimeManager works but I think provided implementation will not work for more than one object. You should use PerHttpRequestLifetimeManager directly:

public class PerHttpRequestLifetime : LifetimeManager
{
    // This is very important part and the reason why I believe mentioned
    // PerCallContext implementation is wrong.
    private readonly Guid _key = Guid.NewGuid();

    public override object GetValue()
    {
        return HttpContext.Current.Items[_key];
    }

    public override void SetValue(object newValue)
    {
        HttpContext.Current.Items[_key] = newValue;
    }

    public override void RemoveValue()
    {
        var obj = GetValue();
        HttpContext.Current.Items.Remove(obj);
    }
}

Be aware that Unity will not dispose context for you. Also be aware that default UnityContainer implementation will never call RemoveValue method.

If your implementation resolves all repositories in single Resolve call (for example if your controllers receives instances of repositories in constructor and you are resolving controllers) you don’t need this lifetime manager. In such case use build-in (Unity 2.0) PerResolveLifetimeManager.

Edit:

I see pretty big problem in your provided configuration of UnityContainer. You are registering both repositories with ContainerControllerLifetimeManager. This lifetime manager means Singleton instance per container lifetime. It means that both repositories will be instantiated only once and instance will be stored and reused for subsequent calls. Because of that it doesn’t matter what lifetime did you assign to MyEntities. It is injected to repositories’ constructors which will be called only once. Both repositories will use still that single instance of MyEntities created during their construction = they will use single instance for whole lifetime of your AppDomain. That is the worst scenario you can achieve.

Rewrite your configuration this way:

var container = new UnityContainer();
container
  .RegisterType<ProductsRepository>()
  .RegisterType<CategoryRepository>()
  .RegisterType<MyEntities>(new PerResolveLifetimeManager(), dbConnectionString);

Why this is enough? You are resolving controller which is dependent on repsitories but no repository instance is needed more then once so you can use default TransientLifetimeManager which will create new instance for each call. Because of that repository constructor is called and MyEntities instance must be resolved. But you know that multiple repositories can need this instance so you will set it with PerResolveLifetimeManager => each resolving of controller will produce only one instance of MyEntities.

Leave a Comment