50

I have a MVC 3 web application, where I am using the Entity Framework for the data access. Furthermore, I have made a simple use of the repository pattern, where e.g. all Product related stuff is handled in the "ProductRepository" and all User related stuff is handled in the "UserRepository".

Thus, I am using the UNITY container, to make a singleton instance of the DataContext, which I inject into each of the repositories. A quick search on Google, and everyone recommends you to NOT use a singleton instance of the DataContext, as it might give you some memory leaks in the future.

So, inspired by this post, making a singleton instance of the DataContext for each web request is the answer (please correct me if I am wrong!)

http://blogs.microsoft.co.il/blogs/gilf/archive/2010/05/18/how-to-manage-objectcontext-per-request-in-asp-net.aspx

However, UNITY does not support the "Per-web-request" lifetime manager. But, it is possible to implement your own custom lifetime manager, which handles this for you. Actually, this is discussed in this post :

Singleton Per Call Context (Web Request) in Unity

The question is, I have now implemented the custom lifetime manager as described in the above post, but I am unsure if this is the way to do it. I am also wondering about where the datacontext instance is disposed in the provided solution? Am I missing out something?

Is there actually a better way of solving my "issue"?

Thanks!

** Added information about my implementation **

The following is snippets from my Global.asax, Controller and Repository. This gives a clear picture of my implementation.

Global.asax

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

Controller

private ProductsRepository _productsRepository;
private CategoryRepository _categoryRepository;

public ProductsController(ProductsRepository productsRepository, CategoryRepository categoryRepository)
{
   _productsRepository = productsRepository;
   _categoryRepository = categoryRepository;
}

public ActionResult Index()
{
   ProductCategory category = _categoryRepository.GetProductCategory(categoryId);
   . 
   . 
   . 
}

protected override void Dispose(bool disposing)
{
    base.Dispose(disposing);
    _productsRepository.Dispose();
    _categoryRepository.Dispose();
}

Product Repository

public class ProductsRepository : IDisposable
{

private MyEntities _db;

public ProductsRepository(MyEntities db)
{
    _db = db;
}

public Product GetProduct(Guid productId)
{
    return _db.Product.Where(x => x.ID == productId).FirstOrDefault();
}

public void Dispose()
{
    this._db.Dispose();
}

Controller Factory

public class UnityControllerFactory : DefaultControllerFactory
{
    IUnityContainer _container;

    public UnityControllerFactory(IUnityContainer container)
    {
        _container = container;
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            throw new HttpException(404, String.Format("The controller for path '{0}' could not be found" +
                "or it does not implement IController.",
                 requestContext.HttpContext.Request.Path));
        }

        return _container.Resolve(controllerType) as IController;
    }

}

Addition information Hi, I will post additional links that I come across, concerning the related issue and solution suggestions:

  1. http://cgeers.wordpress.com/2009/02/21/entity-framework-objectcontext/#objectcontext
  2. http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in-n-layered-ASP-NET-applications.aspx
  3. attaching linq to sql datacontext to httpcontext in business layer
  4. http://weblogs.asp.net/shijuvarghese/archive/2008/10/24/asp-net-mvc-tip-dependency-injection-with-unity-application-block.aspx
  5. http://msdn.microsoft.com/en-us/library/bb738470.aspx
Community
  • 1
  • 1
Nima
  • 947
  • 1
  • 13
  • 20
  • 1
    Gil is correct; one instance per request is the right way to go. Can't help you with Unity, though. – Craig Stuntz Mar 03 '11 at 22:47
  • @Craig, thanks for your comment. As you can see, there are many different views on the use of a shared ObjectContext per http-request. I am not still fully convinced (yet) though. – Nima Mar 05 '11 at 18:24
  • Don't use sigleton DataContexts: http://j.mp/fi83NV – BritishDeveloper Mar 06 '11 at 09:38

9 Answers9

38

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.

Community
  • 1
  • 1
Ladislav Mrnka
  • 349,807
  • 56
  • 643
  • 654
  • @Ladislav - thank you for your reply. My real problem is actually concerning working with multiple ObjectContext instances, because of the structure of my repositories. Initially, each repo was operating on their own ObjectContext instance (within the Using() statement), but this caused some troubles. See also the issue and soultion with Single ObjectContext for each request here: [link](http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in-n-layered-ASP-NET-applications.aspx) – Nima Mar 05 '11 at 18:11
  • @Ladislav : regarding UNITY, thanks for your suggestion. I will use that instead of CallContext (havn't figured out the difference between those). Regarding disposing an ObjectContext instance after the request is finished, how is this done? Should I go for the Application_EndRequest event as described here [link](http://stackoverflow.com/questions/2482220/attaching-linq-to-sql-datacontext-to-httpcontext-in-business-layer)? – Nima Mar 05 '11 at 18:13
  • @Nima: Using single `ObjectContext` per request is correct approach. There should not be big difference between `CallContext` and `HttpContext` implementation because it is most probably stored in `CallContext`. Disposing context is tricky. I'm doing it in controller factory. In `ReleaseController` I dispose controller and it in turns releases its dependencies. – Ladislav Mrnka Mar 05 '11 at 18:20
  • @Ladislav, thanks. I read your answer as, "do not share context", so thanks for clearing that out :) The ObjectContext implements the IDisposable interface, so couldn't I just call its dispose() in the Application_EndRequest event, as described by @Cheeso in [link](http://stackoverflow.com/questions/2482220/attaching-linq-to-sql-datacontext-to-httpcontext-in-business-layer)? – Nima Mar 05 '11 at 18:32
  • @Nima: And do you have access to `ObjectContext` in EndRequest? Are you going to iterate all items in HttpContext to find it? Who is responsible for handling `ObjectContext`? There as two point of views: Unity container is or top object in dependency hiearchy is. Unity container doesn't call dispose for you so you should go with top object in dependency hiearchy which is most probably controller. – Ladislav Mrnka Mar 05 '11 at 18:44
  • @Ladislav: I have now added code snippets to my question, so you can see my actual implementation. I must admit that I am pretty new to MVC/Unity/EF, just so that you are informed :) Can you please outline your last comment, and how/where you recommend me to dispose the ObjectContext? – Nima Mar 05 '11 at 19:21
  • @Ladislav: Could you please outline your comment, based on the new additional code snippets? Thank you very much. – Nima Mar 06 '11 at 18:34
  • @Ladislav: Thank you very much for your edited answer, I really appreciate it! Does this mean, that I dont need to use the PerHttpRequestLifetime anymore? What about disposing the MyEntities ObjectContext? Should I override Dispose on the Controller, and call the dispose on the Repository, which then disposes the _db object? – Nima Mar 06 '11 at 19:23
  • If you only need to call resolve once per request, you don't need PerHttpRequestLifetime. And yes dispose your controller which will dispose repositories, etc. – Ladislav Mrnka Mar 06 '11 at 19:26
  • @Ladislav: Checkout the edited code-snippet, is it correct now? So the repositories are now using the same instance of the ObjectContext (MyEntities), which is a new instance per http- request? And the Object Context is correctly cleared up after being used? – Nima Mar 06 '11 at 19:38
  • @Nima: You also have to dispose controller somewhere. Try controller factory - it has ReleaseController method. – Ladislav Mrnka Mar 06 '11 at 20:47
  • @Ladislav: It seems that the Dispose is automatically called on the Controller. My breakpoint in the Dispose method gets hit. From where, I cannot answer, but it must be standard MVC pipeline handling? – Nima Mar 06 '11 at 21:00
  • @Nima: So in such case it should be ok. – Ladislav Mrnka Mar 06 '11 at 21:01
  • @Ladislav: Great! I guess that we made it :) The only thing that is still unclear in my head, is that we dont use the PerHttpRequestLifetime, and still we manage to do what we intented: Managing a single ObjectContext instance per http-request. Its your phrase, that keeps me wondering: "If you only need to call resolve once per request". When did it make sense in my scenario, to use the custom PerHttpRequestLifetime? – Nima Mar 06 '11 at 21:08
  • @Ladislav, why is that GUID key necessary? Doesn't `HttpContext.Current` already ensure you are dealing with a single, unique request? If I want one DataContext per request, why can't the key name just be something like "DataContext"? Why does it need to be a GUID? – devuxer Jun 12 '11 at 20:45
  • @DanM: Because that is general lifetime manager. You can use it for multiple configurations for the same request and because of that you need generate unique key for each of them otherwise second usage will override object stored by first usage. – Ladislav Mrnka Jun 12 '11 at 20:49
8

As of Unity 3, there is already a built-in lifetime manager per http request.

PerRequestLifetimeManager

A LifetimeManager that holds onto the instance given to it during the lifetime of a single HTTP request. This lifetime manager enables you to create instances of registered types that behave like singletons within the scope of an HTTP request. See remarks for important usage information.

Remarks by MSDN

Although the PerRequestLifetimeManager lifetime manager works correctly and can help in working with stateful or thread-unsafe dependencies within the scope of an HTTP request, it is generally not a good idea to use it when it can be avoided, as it can often lead to bad practices or hard to find bugs in the end-user's application code when used incorrectly.

It is recommended that the dependencies you register are stateless and if there is a need to share common state between several objects during the lifetime of an HTTP request, then you can have a stateless service that explicitly stores and retrieves this state using the Items collection of the Current object.

The remarks say that even you are forced to use a single context per service (facade service), you should keep your service calls stateless.

Unity 3 is for .NET 4.5 by the way.

Community
  • 1
  • 1
Yorro
  • 9,772
  • 3
  • 31
  • 42
5

I believe the sample code shown on NerdDinner: DI in MVC using Unity for its HttpContextLifetimeManager should meet your needs.

neontapir
  • 4,450
  • 3
  • 35
  • 51
  • thanks for your reply. I guess it is the same way as @ladislav writes in his answer? – Nima Mar 05 '11 at 18:15
2

I don't want to unnecessarily discourage you and by all means experiment but if you go ahead and use singleton instances of DataContext make sure you nail it.

It can appear to work fine on your dev environment but it could be failing to close connections properly. This will be hard to see without the load of a production environment. On a production environment with high load, undisposed connections will cause huge memory leaks and then high CPU trying to allocate new memory.

Have you considered what you are gaining from a connection per request pattern? How much performance there is to gain from opening/closing a connection once over say 3-4 times in a request? Worth the hassle? Also this makes lazy loading fails (read database queries in your view) a lot easier offences to make.

Sorry if this came across discouraging. Go for it if you really see the benefit. I'm just warning you that it could backfire quite seriously if you get it wrong so be warned. Something like entity profiler will be invaluable to getting it right - it tells you number of connections opened and closed - amongst other very useful things.

BritishDeveloper
  • 12,481
  • 7
  • 49
  • 59
  • thanks for your answer. Actually, your post got me a bit confused (again), making me search google again. The issue is not performance gain, but more the problem of having multiple ObjectContext instances, which gives some problems as described here [link](http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in-n-layered-ASP-NET-applications.aspx). I am going to check out the Entity Profiler! Thanks. – Nima Mar 05 '11 at 18:18
2

I saw question and answer few times ago. It is dated. Unity.MVC3 has life time manager as HierarchicalLifetimeManager.

    container.RegisterType<OwnDbContext>(
                "",
                new HierarchicalLifetimeManager(),
                new InjectionConstructor(connectionString)
                );

and it works nice.

Nuri YILMAZ
  • 4,183
  • 5
  • 33
  • 41
1

I would propose to solve it like this: http://forums.asp.net/t/1644386.aspx/1

Best regards

Dzendo
  • 179
  • 2
  • 13
1

I solved this by using Castle.DynamicProxy. I needed to have certain dependencies be injected "On Demand" meaning they needed to be resolved at time of use, not at time of "Depender" build up.

To do this I configure my container like so:

 private void UnityRegister(IUnityContainer container)
 {
    container.RegisterType<HttpContextBase>(new OnDemandInjectionFactory<HttpContextBase>(c => new HttpContextWrapper(HttpContext.Current)));
    container.RegisterType<HttpRequestBase>(new OnDemandInjectionFactory<HttpRequestBase>(c => new HttpRequestWrapper(HttpContext.Current.Request)));
    container.RegisterType<HttpSessionStateBase>(new OnDemandInjectionFactory<HttpSessionStateBase>(c => new HttpSessionStateWrapper(HttpContext.Current.Session)));
    container.RegisterType<HttpServerUtilityBase>(new OnDemandInjectionFactory<HttpServerUtilityBase>(c => new HttpServerUtilityWrapper(HttpContext.Current.Server)));
 }

The idea being that I provide a method to retrieve the instance "on demand." The lambda gets invoked whenever any of the methods of the instance are used. The Dependent object is actually holding a reference to a proxied object, no the object itself.

OnDemandInjectionFactory:

internal class OnDemandInjectionFactory<T> : InjectionFactory
{
    public OnDemandInjectionFactory(Func<IUnityContainer, T> proxiedObjectFactory) : base((container, type, name) => FactoryFunction(container, type, name, proxiedObjectFactory))
    {
    }

    private static object FactoryFunction(IUnityContainer container, Type type, string name, Func<IUnityContainer, T> proxiedObjectFactory)
    {
        var interceptor = new OnDemandInterceptor<T>(container, proxiedObjectFactory);
        var proxyGenerator = new ProxyGenerator();
        var proxy = proxyGenerator.CreateClassProxy(type, interceptor);
        return proxy;
    }
}

OnDemandInterceptor:

internal class OnDemandInterceptor<T> : IInterceptor
{
    private readonly Func<IUnityContainer, T> _proxiedInstanceFactory;
    private readonly IUnityContainer _container;

    public OnDemandInterceptor(IUnityContainer container, Func<IUnityContainer, T> proxiedInstanceFactory)
    {
        _proxiedInstanceFactory = proxiedInstanceFactory;
        _container = container;
    }

    public void Intercept(IInvocation invocation)
    {
        var proxiedInstance = _proxiedInstanceFactory.Invoke(_container);

        var types = invocation.Arguments.Select(arg => arg.GetType()).ToArray();

        var method = typeof(T).GetMethod(invocation.Method.Name, types);

        invocation.ReturnValue = method.Invoke(proxiedInstance, invocation.Arguments);
    }
}
1

In Unity3, if you want to use

PerRequestLifetimeManager

You need to register UnityPerRequestHttpModule

I do this by using WebActivatorEx, the code is as below:

using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;
using MyNamespace;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(UnityWebActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(UnityWebActivator), "Shutdown")]

namespace MyNamespace
{
    /// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
    public static class UnityWebActivator
    {
        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start() 
        {
            var container = UnityConfig.GetConfiguredContainer();

            FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
            FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));

            DependencyResolver.SetResolver(new UnityDependencyResolver(container));

            // TODO: Uncomment if you want to use PerRequestLifetimeManager
            Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
        }

        /// <summary>Disposes the Unity container when the application is shut down.</summary>
        public static void Shutdown()
        {
            var container = UnityConfig.GetConfiguredContainer();
            container.Dispose();
        }
    }
}
Yang Zhang
  • 4,140
  • 3
  • 34
  • 32
0

PerRequestLifetimeManager and UnityPerRequestHttpModule classes are in Unity.Mvc package which has a dependency on ASP.NET MVC. If you don't want to have that dependency (e.g. you are using Web API) you will have to copy-paste them in to your app.

If you do that, don't forget the register the HttpModule.

Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

Edit: I'll include the classes here before CodePlex shuts down:

// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Web;
using Microsoft.Practices.Unity.Mvc.Properties;
using Microsoft.Practices.Unity.Utility;

namespace Microsoft.Practices.Unity.Mvc
{
    /// <summary>
    /// Implementation of the <see cref="IHttpModule"/> interface that provides support for using the
    /// <see cref="PerRequestLifetimeManager"/> lifetime manager, and enables it to
    /// dispose the instances after the HTTP request ends.
    /// </summary>
    public class UnityPerRequestHttpModule : IHttpModule
    {
        private static readonly object ModuleKey = new object();

        internal static object GetValue(object lifetimeManagerKey)
        {
            var dict = GetDictionary(HttpContext.Current);

            if (dict != null)
            {
                object obj = null;

                if (dict.TryGetValue(lifetimeManagerKey, out obj))
                {
                    return obj;
                }
            }

            return null;
        }

        internal static void SetValue(object lifetimeManagerKey, object value)
        {
            var dict = GetDictionary(HttpContext.Current);

            if (dict == null)
            {
                dict = new Dictionary<object, object>();

                HttpContext.Current.Items[ModuleKey] = dict;
            }

            dict[lifetimeManagerKey] = value;
        }

        /// <summary>
        /// Disposes the resources used by this module.
        /// </summary>
        public void Dispose()
        {
        }

        /// <summary>
        /// Initializes a module and prepares it to handle requests.
        /// </summary>
        /// <param name="context">An <see cref="HttpApplication"/> that provides access to the methods, properties,
        /// and events common to all application objects within an ASP.NET application.</param>
        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated with Guard class")]
        public void Init(HttpApplication context)
        {
            Guard.ArgumentNotNull(context, "context");
            context.EndRequest += OnEndRequest;
        }

        private void OnEndRequest(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;

            var dict = GetDictionary(app.Context);

            if (dict != null)
            {
                foreach (var disposable in dict.Values.OfType<IDisposable>())
                {
                    disposable.Dispose();
                }
            }
        }

        private static Dictionary<object, object> GetDictionary(HttpContext context)
        {
            if (context == null)
            {
                throw new InvalidOperationException(Resources.ErrorHttpContextNotAvailable);
            }

            var dict = (Dictionary<object, object>)context.Items[ModuleKey];

            return dict;
        }
    }
}

// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.

using System;
using Microsoft.Practices.Unity.Mvc;

namespace Microsoft.Practices.Unity
{
    /// <summary>
    /// A <see cref="LifetimeManager"/> that holds onto the instance given to it during
    /// the lifetime of a single HTTP request.
    /// This lifetime manager enables you to create instances of registered types that behave like
    /// singletons within the scope of an HTTP request.
    /// See remarks for important usage information.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Although the <see cref="PerRequestLifetimeManager"/> lifetime manager works correctly and can help
    /// in working with stateful or thread-unsafe dependencies within the scope of an HTTP request, it is
    /// generally not a good idea to use it when it can be avoided, as it can often lead to bad practices or
    /// hard to find bugs in the end-user's application code when used incorrectly. 
    /// It is recommended that the dependencies you register are stateless and if there is a need to share
    /// common state between several objects during the lifetime of an HTTP request, then you can
    /// have a stateless service that explicitly stores and retrieves this state using the
    /// <see cref="System.Web.HttpContext.Items"/> collection of the <see cref="System.Web.HttpContext.Current"/> object.
    /// </para>
    /// <para>
    /// For the instance of the registered type to be disposed automatically when the HTTP request completes,
    /// make sure to register the <see cref="UnityPerRequestHttpModule"/> with the web application.
    /// To do this, invoke the following in the Unity bootstrapping class (typically UnityMvcActivator.cs):
    /// <code>DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));</code>
    /// </para>
    /// </remarks>
    public class PerRequestLifetimeManager : LifetimeManager
    {
        private readonly object lifetimeKey = new object();

        /// <summary>
        /// Retrieves a value from the backing store associated with this lifetime policy.
        /// </summary>
        /// <returns>The desired object, or null if no such object is currently stored.</returns>
        public override object GetValue()
        {
            return UnityPerRequestHttpModule.GetValue(this.lifetimeKey);
        }

        /// <summary>
        /// Stores the given value into the backing store for retrieval later.
        /// </summary>
        /// <param name="newValue">The object being stored.</param>
        public override void SetValue(object newValue)
        {
            UnityPerRequestHttpModule.SetValue(this.lifetimeKey, newValue);
        }

        /// <summary>
        /// Removes the given object from the backing store.
        /// </summary>
        public override void RemoveValue()
        {
            var disposable = this.GetValue() as IDisposable;

            if (disposable != null)
            {
                disposable.Dispose();
            }

            UnityPerRequestHttpModule.SetValue(this.lifetimeKey, null);
        }
    }
}
Ufuk Hacıoğulları
  • 36,026
  • 11
  • 106
  • 149