MVC, EF - instance of SingleContextContext Per-Web-Request in Unity

I have an MVC 3 web application where I use the Entity Framework to access data. In addition, I made a simple use of the repository template, where, for example, all product-related materials are processed in the "ProductRepository", and all user-related materials are processed in the "UserRepository".

Thus, I use the UNITY container to create one instance of the DataContext, which I insert into each of the repositories. A quick google search and everyone recommends NOT using a single instance of the DataContext, as this may give you some memory leaks in the future.

So, inspired by this post, one 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 lifecycle manager. But you can implement your own lifetime manager that handles this for you. Actually, this message says:

Singleton Per Call context (web request) in Unity

The question is, I have now implemented a user-defined lifetime manager, as described above, but I'm not sure if this is the way to do this. I also wonder where the datacontext instance is in the provided solution? Am I missing something?

Is there a better way to solve my problem?

Thank!

** Added information about my implementation **

Below are 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(); } 

Factory Controller

 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; } } 

Additional Information Hi, I will post additional links that I come across regarding relevant issues and solutions:

+49
ioc-container asp.net-mvc-3 entity-framework unity-container
Mar 03 '11 at 22:44
source share
9 answers

Yes, do not exchange context and use one context for the request. You can also check related issues in this post to see all issues caused by the general context.

Now about Unity. The idea of PerCallContextLifetimeManager works, but I think the 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); } } 

Remember that Unity will not use context for you. Also keep in mind that the default implementation of UnityContainer will never call the RemoveValue method.

If your implementation allows all repositories in a single Resolve call (for example, if your controllers receive instances of repositories in the constructor and you allow controllers), you do not need this lifetime manager. In this case, use the built-in (Unity 2.0) PerResolveLifetimeManager .

Edit:

I see a pretty big problem in your UnityContainer configuration. You register both stores with the ContainerControllerLifetimeManager . This lifetime manager means a Singleton instance for the lifetime of the container. This means that both repositories will be created only once, and the instance will be saved and reused for subsequent calls. Because of this, it doesn’t matter how long you assigned MyEntities . It is introduced into the repository constructors, which will be called only once. Both repositories will use another single instance of MyEntities created during their construction = they will use one instance for the entire life of your AppDomain . This is the worst option you can achieve.

Rewrite the configuration as follows:

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

Why is this enough? You allow a controller that is dependent on repeaters, but the repository instance is not required more than once, so you can use default TransientLifetimeManager , which will create a new instance for each call. Because of this, a repository constructor is created and the MyEntities instance must be allowed. But you know that several repositories may need this instance, so you install it with PerResolveLifetimeManager => only one instance of MyEntities will be created with each resolution of the controller.

+38
Mar 04 2018-11-11T00:
source share

Like Unity 3, there is already a built-in lifetime manager for each HTTP request.

PerRequestLifetimeManager

A LifetimeManager, which is stored in the instance provided to it throughout the life cycle of a single HTTP request. This lifetime manager allows you to create instances of registered types that behave as single points within an HTTP request. See Notes for important usage information.

MSDN Notes

Although the PerRequestLifetimeManager lifecycle manager works correctly and can help you work with state-dependent or thread-unsafe frames as part of an HTTP request , it is generally not recommended to use it when it can be avoided , as this often leads to bad practice or is difficult to find Errors in the end-user application code if used improperly.

It is recommended that the dependencies that depend on you be void and if there is a need to share a common state between several objects throughout the life cycle of an HTTP request, then you can have a stateless service that explicitly saves and retrieves this state using the Collection of elements of the current object.

The comments say that even you are forced to use the same context for the service (facade service), you must maintain that your service calls are idle.

Unity 3 for .NET 4.5, by the way.

+8
Dec 20 '13 at 7:18
source share

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

+5
Mar 03 2018-11-11T00:
source share

I don’t want to dissuade you too much and, by all means, experiment, but if you go ahead and use instances of the Singleton DataContext, make sure you nail it.

It may seem like it works fine in your developer's environment, but it might be wrong to close the connections. It will be difficult to see without a workload environment. In a production environment with a high load, unshared connections will cause huge memory leaks, and then a high processor, trying to allocate new memory.

Do you consider what you get from the connection to the request template? How much do you want to get from opening / closing a connection once, say, 3-4 times in a request? Is it worth the trouble? Furthermore, this makes lazy loading unsuccessful (reading database queries in your view) is much easier to do.

Sorry if this came across discouragement. Go for it if you really see the benefit. I am simply warning you that this can seriously affect you if you make a mistake, so be careful. Something like an entity profiler will be invaluable for the right choice - it tells you that the number of connections is open and closed - among other very useful things.

+2
Mar 03 '11 at 23:51
source share

I saw the question and answer several times ago. It is dated. Unity.MVC3 has a lifetime manager like the HierarchicalLifetimeManager.

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

and it works well.

+2
Dec 14 '11 at 9:05
source share

I would suggest solving it like this: http://forums.asp.net/t/1644386.aspx/1

Regards

+1
Jan 16 '13 at 9:29
source share

I solved this using Castle.DynamicProxy. I needed to introduce certain "On Demand" dependencies, that is, they should have been resolved during use, and not when creating a "Depender".

To do this, I configure my container as follows:

  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 is that I am providing a method for retrieving an on-demand instance. The lambda is called whenever any of the instance methods is used. The Dependent object actually contains a reference to the proxy object, without 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
Mar 30 '15 at 18:53
source share

In Unity3, if you want to use

 PerRequestLifetimeManager 

You need to register UnityPerRequestHttpModule

I am doing this with WebActivatorEx, the code is as follows:

 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(); } } } 
+1
Aug 17 '15 at 23:58
source share

The PerRequestLifetimeManager and UnityPerRequestHttpModule classes are in the Unity.Mvc package , which has a dependency on ASP.NET MVC. If you do not want this dependency (for example, you use the Web API), you will have to copy them to the application.

If you do, be sure to register the HttpModule.

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

Edit: I will include 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 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); } } } 
0
Feb 24 '17 at 12:50
source share



All Articles