2012-07-30 60 views
4

我想在Web应用程序中使用AutoFac。我有根容器,每个会话有一个子容器,每个请求有一个子容器。我试图找出管理这些生命周期范围的最佳方法。在Global.asax.cs中我已经添加了以下内容:在asp.net中管理每个会话和请求的AutoFac生命周期范围mvc 3

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(); 
} 
  1. 我怎么能告诉AutoFac用我的requestScope为出发点越来越依赖关系,让我注册为InstancePerLifetimeScope的实现将是使用我的requestScope解决?

  2. 如果这是不可能的,我可以让AutoFac创建它的per-request生存期范围吗?

  3. 或者我在错误的轨道上吗?有没有其他的方法让AutoFac知道这个层次结构?

任何帮助或其他意见表示赞赏。


回应史蒂文。

我仍然在原型的早期阶段,但有可能的事情,你可以有在sessionScope:

  • 使用UserPreferences
  • 身份验证和授权范围内(例如,用户身份和角色)

与我将要构建的应用程序无关,但在电子商务环境中,购物车可以是会话范围。这可能是最好的具体例子。这是你期望寿命比请求更长的事情,但比应用程序更短。

可能还有更多,但如果我有UserPreferences,Authentication和Authorization的策略,那么这个策略也可以应用到稍后创建的其他组件。

可能的替代方法是在请求开始时获取所有必要的信息,并将这些配置的组件放在请求范围中。它会给我我期望的结果,但它与我在脑海中关于应用程序 - >会话 - >请求层次结构的模型不匹配。我希望创建一个合理的系统,因为我绝对不是要维护它的系统。

+0

您希望在每个会话范围注册哪些服务?这对于我们在问题3“我在错误的轨道上吗?”给出了一个很好的答案是需要的。 – Steven 2012-07-31 20:16:49

回答

11

你需要做的是实现你自己的Autofac.Integration.Mvc.ILifetimeScopeProvider。该接口管理如何/在哪里生成请求生存期范围。缺省值Autofac.Integration.Mvc.RequestLifetimeScopeProvider按照每个请求处理生命周期范围的创建,处理和维护。

You can browse the code for RequestLifetimeScopeProvider here,如果您打算进行此操作,我强烈建议您这样做。这是我能想到的最好的示例,其中包含显示这些事情之一的责任的工作代码。

您的实施ILifetimeScopeProvider将抓取会话子容器,从中产生请求容器,并在请求结束时清理请求容器。如果不存在,您可能还想在其中创建会话容器。处理会话容器的清理/处理可能会非常棘手,但从设计的角度来看,如果它们全都在一个地方,而不是提供者中的某些地方,那么应用程序类中的某些地方会更好。

一旦你有你的ILifetimeScopeProvider你会设置你的依赖解析器时使用它。

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

一对夫妇的警告有关的会话级范围的概念的话:

  1. 你的内存占用量是巨大的。您将最终为系统中的每个用户提供生命周期范围。虽然请求生命期很快就会弹出并消失,但这些会话级作用域可能会存在很长时间。如果你有很多会话范围的项目,你将有一个相当不错的内存使用量为每个用户。如果人们在没有正确注销的情况下“放弃”他们的会话,那么这些事情就会持续下去。
  2. 终身范围及其内容不可序列化Looking at the code for LifetimeScope,它没有标记为[Serializable] ......即使是这样,生活在那里的解析对象也不一定都是标记为可序列化的。这很重要,因为这意味着您的会话级生存期范围可能在具有内存中会话的单个框上工作,但是如果您使用SQL会话或会话服务部署到服务器场,则事情将分崩离析,因为会话无法序列化您的存储范围。如果你选择不序列化范围,那么你在每台机器上的每个用户都有不同的范围 - 这也是一个潜在的问题。
  3. 会话不总是被重新水化。如果正在访问的处理程序(如Web表单)未实现IRequiresSessionState,则会话将不会被重新组合(不管它是否处于进程中)。 Web表单和MvcHandler实现默认情况下,所以你不会看到任何问题,但如果你有需要注入的自定义处理程序,你会遇到一些障碍,因为这些请求不存在“会话”。
  4. Session_End并不总是激发Per the docs on SessionStateModule.End,如果你使用out-of-proc会话状态,你实际上不会得到Session_End事件,所以你将无法清理。

鉴于这些限制,通常尽量远离会话存储范围。但是......如果这就是你要做的事情,那么ILifetimeScopeProvider就是这样做的。

+0

Nicholas Blumhardt在CodeProject上发表了一篇文章[描述这个层次结构](http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac#using-scope-to-control-visibility)。但那篇文章只是给出了一些不好的建议?我可以想象会有一些组件与会话具有相同的生命周期,所以它看起来是一个很好的方法。应用程序不会有很多用户,并且不需要将其部署到场中。但你提出了一些有效的观点。 – Jeroen 2012-07-31 08:10:58

+0

而2b,当扩展到Web场时,您的应用程序中将会出现内存泄漏,因为在使用out-pro-pro会话状态时,Session_End永远不会被调用。 – Steven 2012-07-31 13:53:58

+0

在那篇文章中,我不认为尼克是“提供建议”,而是使用session来提供更具体的例子来解释嵌套层次结构如何工作。 – 2012-07-31 15:01:12