在asp.net mvc 3中管理每个会话的AutoFac生命周期范围和请求

时间:2012-07-30 12:48:09

标签: c# asp.net-mvc-3 autofac

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

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作为获取依赖关系的起点,以便我使用requestScope解析我注册为InstancePerLifetimeScope的实现?

  2. 如果无法做到这一点,我是否可以让AutoFac从我的sessionScope中创建每个请求的生命周期范围?

  3. 或者我在错误的轨道上?是否有其他方法可以让AutoFac了解这种层次结构?

  4. 感谢任何帮助或其他评论。


    回应史蒂文。

    我还处于原型设计的早期阶段,但是你可以在sessionScope中找到可能的东西:

    • 使用UserPreferences
    • 身份验证和授权上下文(例如用户身份和角色)

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

    可能有更多,但如果我有UserPreferences,身份验证和授权的策略,那么该策略也可以应用于稍后将创建的其他组件。

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

1 个答案:

答案 0 :(得分:13)

您需要做的是实施自己的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默认实现,因此您不会看到任何问题,但如果您有需要注入的自定义处理程序,您将遇到一些障碍,因为这些请求不会存在“Session”。 / LI>
  4. Session_End并不总是触发Per the docs on SessionStateModule.End,如果你使用了进程外会话状态,你实际上不会得到Session_End事件,所以你将无法清理。
  5. 鉴于这些限制,尝试远离会话存储的范围通常是好的。但是......如果这就是你要做的事情,ILifetimeScopeProvider就是这样做的。