Managing AutoFac lifecycle areas per session and request in asp.net mvc 3

I want to use AutoFac in a web application. I have a root container, a child container per session, and a child container for each request. I'm trying to figure out what is the best way to manage these areas of life time. In Global.asax.cs, I added the following:

protected void Application_Start(object sender, EventArgs e) { var container = ...; } protected void Session_Start(object sender, EventArgs e) { var sessionScope = container.BeginLifetimeScope("session"); Session["Autofac_LifetimeScope"] = sessionScope; } protected void Application_BeginRequest(object sender, EventArgs e) { var sessionScope = (ILifetimeScope) Session["Autofac_LifetimeScope"]; var requestScope = sessionScope.BeginLifetimeScope("httpRequest"); HttpContext.Current.Items["Autofac_LifetimeScope"] = requestScope; } protected void Application_EndRequest(object sender, EventArgs e) { var requestScope = (ILifetimeScope)HttpContext.Current.Items["Autofac_LifetimeScope"]; requestScope.Dispose(); } protected void Session_End(object sender, EventArgs e) { var sessionScope = (ILifetimeScope)Session["Autofac_LifetimeScope"]; sessionScope.Dispose(); } protected void Application_End(object sender, EventArgs e) { container.Dispose(); } 
  • How can I tell AutoFac to use my Scope request as a starting point for getting dependencies, so that implementations that I register as InstancePerLifetimeScope will be resolved with my requestScope?

  • If this is not possible, can I get AutoFac to create my goal for the entire request from my sessionScope?

  • Or am I wrong here? Could there be another way to make AutoFac aware of this hierarchy?

Any help or other comments are appreciated.


In response to Stephen.

I'm still in the early stages of prototyping, but the possible things you might have in a Scope session:

  • Find Page
  • Authentication and authorization context (e.g. user ID and role)

Not related to the application I'm going to create, but in an e-commerce environment, the cart may be busy in sessions. This is probably the best concrete example. This is what you expect to live longer than the request, but shorter than the application.

It may be more, but if I have a strategy for UserPreferences, Authentication and Authorization, this strategy can also be applied to other components that will be created later.

A possible alternative is to get all the necessary information at the beginning of the request and place these customized components in the request area. This will give me the result that I expect, but it does not match the model that I mean about the application-> session-> query hierarchy. I hope to create a system that makes sense, since I'm definitely not the one that will support it.

+4
source share
1 answer

What you need to do is implement your own Autofac.Integration.Mvc.ILifetimeScopeProvider . This interface controls how query runtime regions are generated. By default, Autofac.Integration.Mvc.RequestLifetimeScopeProvider handles the creation, deletion, and maintenance of life expectancy areas for each request.

Here you can view the RequestLifetimeScopeProvider code , which I highly recommend doing if you plan on doing this. This is the best sample I can imagine, containing working code showing the responsibility of one of these things.

Your implementation of ILifetimeScopeProvider will be where you grab the child session container, open the request container and, at the end of the request, clear the request container. You can also create a session container there if it does not exist. Handling cleaning / deleting a session container can be complicated, but from a design point of view, it would be nice if everything was in one place, and not in one of the providers, some in your application class.

Once you have ILifetimeScopeProvider , you will use it when setting up your dependency converter.

 var scopeProvider = new MyCustomLifetimeScopeProvider(container, configAction); var resolver = new AutofacDependencyResolver(container, scopeProvider); DependencyResolver.SetResolver(resolver); 

A few words of warning about the concept of a session level area:

  • Your memory can be huge. . Ultimately, you span a lifetime for every user of your system. Although the service life of the request appears and leaves quite quickly, these session-level areas will live for a long time. If you have many items for the session area, you will have pretty good memory usage for each user. If people "give up" their activities without leaving the system, all this will continue.
  • Time domains and their contents cannot be serialized . Considering the code for LifetimeScope , it is not marked [Serializable] ... and even if that were the case, then the allowed objects living there were not necessarily marked as serializable. This is important because it means that your session-level lifespan can work in the same box as the session in memory, but if you expand the farm with an SQL session or session service, everything will fall apart because the session cannot serialize your saved amount . If you decide not to serialize the area, then you have different options for each user on different machines - this is also a potential problem.
  • The session is not always rehydrated . If the handler accessed (for example, a web form) does not implement IRequiresSessionState , the session will not be rehydrated (whether in proc or not), Web forms and MvcHandler implement this by default, so you will not see any problems, but if if you have custom handlers that require an injection, you will be hit with some errors because a β€œSession” will not exist for these requests.
  • Session_End does not always work . In the docs on SessionStateModule.End , if you use incomplete session state, you will not actually receive the Session_End event, so you cannot clear it.

Given the limitations, it is usually helpful to try to stay away from the session areas. However ... if this is what you are going to do, ILifetimeScopeProvider is the way to do it.

+11
source

All Articles