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

2023-11-22

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

  2. 如果这是不可能的,我可以让 AutoFac 在我的 sessionScope 之外创建其每个请求的生命周期范围吗?

  3. 或者我在这里走错了路?是否有其他方法可以让 AutoFac 意识到这个层次结构?

任何帮助或其他评论表示赞赏。


回应史蒂文.

我仍处于原型设计的早期阶段,但 sessionScope 中可能有以下内容:

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

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

可能不止这些,但如果我有一个针对 UserPreferences、身份验证和授权的策略,那么该策略也可以应用于稍后创建的其他组件。

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


你需要做的是实现你自己的Autofac.Integration.Mvc.ILifetimeScopeProvider。该接口控制请求生命周期范围的生成方式/位置。默认的,Autofac.Integration.Mvc.RequestLifetimeScopeProvider,根据每个请求处理生命周期范围的创建、处置和维护。

您可以浏览代码RequestLifetimeScopeProvider here,如果您打算这样做,我强烈建议您这样做。这是我能想到的最好的示例,其中包含显示这些事情之一的责任的工作代码。

您的实施ILifetimeScopeProvider将是您获取会话子容器、从中生成请求容器的位置,并在请求结束时清理请求容器。如果会话容器不存在,您可能还想在其中创建它。处理会话容器的清理/处置可能会很棘手,但从设计的角度来看,如果它全部集中在一个地方而不是部分在提供程序中、部分在应用程序类中,那就太好了。

一旦你有了你的ILifetimeScopeProvider当您设置依赖项解析器时,您将使用它。

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

关于会话级作用域概念的几句话警告:

  1. 您的内存占用可能会很大。您最终将获得系统上每个用户的生命周期范围。虽然请求生命周期很快就会弹出并消失,但这些会话级作用域可能会存在很长时间。如果您有很多会话范围的项目,那么每个用户都会有相当大的内存使用量。如果人们在没有正确退出的情况下“放弃”他们的会话,那么这些东西的生存时间就会更长。
  2. 生命周期范围及其内容不可序列化. 查看 LifetimeScope 的代码,没有标记[Serializable]...即使是,存在于其中的已解析对象也不一定全部标记为可序列化。这很重要,因为这意味着您的会话级生命周期范围可能在具有内存会话的单个机器上工作,但如果您部署到具有 SQL 会话或会话服务的场,事情就会崩溃,因为会话无法序列化你的存储范围。如果您选择不序列化范围,那么跨计算机的每个用户都有不同的范围 - 这也是一个潜在的问题。
  3. 会议并不总是补充水分。如果正在访问的处理程序(例如,Web 表单)未实现IRequiresSessionState,会话不会再水化(无论是否在进程中)。网络表格和MvcHandler默认情况下实现它,这样您就不会看到任何问题,但如果您有需要注入的自定义处理程序,您会遇到一些障碍,因为这些请求不存在“会话”。
  4. Session_End 并不总是触发. 根据 SessionStateModule.End 上的文档,如果您使用进程外会话状态,您实际上不会获得 Session_End 事件,因此您将无法进行清理。

考虑到这些限制,通常最好尝试远离会话存储范围。然而...如果这就是你要做的,那么ILifetimeScopeProvider就是这样做的方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐