简体   繁体   English

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

[英]Managing AutoFac lifetime scopes per session and request in asp.net mvc 3

I want to use AutoFac in a web application. 我想在Web应用程序中使用AutoFac。 I have the root container, a child container per session and a child container per request. 我有根容器,每个会话一个子容器和每个请求的子容器。 I'm trying to figure out what the/a best way is to manage these lifetime scopes. 我正在试图找出管理这些生命周期范围的最佳方法。 In the Global.asax.cs I have added the following: 在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. How can I tell AutoFac to use my requestScope as the starting point for getting dependencies, so that the implementations I register as InstancePerLifetimeScope will be resolved using my requestScope? 如何告诉AutoFac使用我的requestScope作为获取依赖项的起点,以便我使用requestScope解析我注册为InstancePerLifetimeScope的实现?

  2. If that is not possible, can I get AutoFac to create its per-request lifetime scope out of my sessionScope? 如果那是不可能的,我可以让AutoFac从我的sessionScope中创建每个请求的生命周期范围吗?

  3. Or am I on the wrong track here? 或者我在这里走错了路? Could there be an other way of making AutoFac aware of this hierarchy? 可以有另一种方法让AutoFac知道这种层次结构吗?

Any help or other comments are appreciated. 任何帮助或其他意见表示赞赏。


In response to Steven. 回应史蒂文。

I'm still in the early stages of prototyping, but possible things you could have in the sessionScope: 我还处于原型设计的早期阶段,但是你可以在sessionScope中找到可能的东西:

  • UserPreferences 使用UserPreferences
  • Authentication and authorization context (eg user identity and roles) 身份验证和授权上下文(例如用户身份和角色)

Not related to the application I'm going to build, but in a e-commerce environment, the shopping cart could be session scoped. 与我要构建的应用程序无关,但在电子商务环境中,购物车可以是会话范围的。 This is probably the best concrete example. 这可能是最好的具体例子。 It is something that you expect to live longer than a request, but shorter than the application. 您希望它比请求更长寿,但比应用程序更短。

There could be more than this, but if I have a strategy for the UserPreferences, Authentication and Authorization, then that strategy could also be applied to other components that will be created later. 可能有更多,但如果我有UserPreferences,身份验证和授权的策略,那么该策略也可以应用于稍后将创建的其他组件。

A possible alternative is to get all the necessary information at the beginning of the request and place these configured components in the request scope. 可能的替代方法是在请求开始时获取所有必要信息,并将这些已配置的组件放在请求范围中。 It will give me the result I expect, but it doesn't match the model I have in my mind about application->session->request hierarchy. 它会给我我期望的结果,但它与我在脑海中关于application-> session-> request hierarchy的模型不符。 I'm hoping to create a system that makes sense, since I'm definitely not the one that is going to maintain it. 我希望创建一个有意义的系统,因为我绝对不是那个要维护它的系统。

What you'll need to do is implement your own Autofac.Integration.Mvc.ILifetimeScopeProvider . 您需要做的是实现自己的Autofac.Integration.Mvc.ILifetimeScopeProvider This interface is what governs how/where request lifetime scopes get generated. 此接口用于控制生成请求生存期范围的方式/位置。 The default one, Autofac.Integration.Mvc.RequestLifetimeScopeProvider , handles creation, disposal, and maintenance of lifetime scopes on a per-request basis. 默认Autofac.Integration.Mvc.RequestLifetimeScopeProvider ,可根据请求处理生命周期范围的创建,处理和维护。

You can browse the code for RequestLifetimeScopeProvider here , which I highly recommend doing if you plan on undertaking this. 您可以在此处浏览RequestLifetimeScopeProvider的代码,如果您计划进行此操作,我强烈建议您这样做。 It's the best sample I can think of containing working code showing the responsibility of one of these things. 这是我能想到的最好的样本,其中包含显示其中一项内容的工作代码。

Your implementation of ILifetimeScopeProvider will be where you grab the session child container, spawn the request container from that, and, at the end of the request, clean up the request container. 您实现ILifetimeScopeProvider将获取会话子容器,从中生成请求容器,并在请求结束时清理请求容器。 You may also want to create the session container in there if it doesn't exist. 如果它不存在,您可能还想在那里创建会话容器。 Handling cleanup/disposal of the session container may be tricky in there, but from a design perspective, it'd be nice if it was all in one place rather than some in the provider, some in your application class. 处理会话容器的清理/处理可能很棘手,但从设计的角度来看,如果它只在一个地方而不是在提供程序中的某些地方,有些在你的应用程序类中,那就太好了。

Once you have your ILifetimeScopeProvider you'll use it when you set up your dependency resolver. 拥有ILifetimeScopeProvider您将在设置依赖项解析器时使用它。

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

A couple of words of warning about the notion of a session-level scope: 关于会话级范围概念的几句警告:

  1. Your memory footprint could be huge. 你的记忆足迹可能很大。 You're going to end up with a lifetime scope for every user on your system. 您将最终为系统中的每个用户提供终身范围。 While a request lifetime pops up and goes away pretty quickly, these session-level scopes will live potentially a long time. 虽然请求生命周期会弹出并快速消失,但这些会话级范围可能会存在很长时间。 If you have a lot of session-scoped items, you're going to have a pretty good sized memory usage for each user. 如果你有很多会话范围的项目,那么你将为每个用户提供相当大的内存使用量。 If people "abandon" their sessions without properly logging out, that's all the longer these things will live. 如果人们在没有正确退出的情况下“放弃”他们的会话,那么这些事情就会存在。
  2. Lifetime scopes and their contents aren't serializable . 生命周期范围及其内容不可序列化 Looking at the code for LifetimeScope , it's not marked [Serializable] ... and even if it was, the resolved objects living in there are not necessarily all marked serializable. 查看LifetimeScope的代码 ,它没有标记为[Serializable] ...即使它是,生活在那里的已解析对象也不一定都标记为可序列化。 This is important because it means your session-level lifetime scope might work on a single box with in-memory session, but if you deploy to a farm with SQL session or a session service, things will fall apart because the session can't serialize your stored scope. 这很重要,因为这意味着会话级生命周期范围可能适用于具有内存中会话的单个框,但如果您使用SQL会话或会话服务部署到服务器场,则会因为会话无法序列化而崩溃你存储的范围。 If you choose not to serialize the scope, then you have a different scope for each user across machines - also a potential problem. 如果您选择不对作用域进行序列化,那么跨机器的每个用户都有不同的作用域 - 这也是一个潜在的问题。
  3. Session isn't always rehydrated . 会话并不总是被重新水化 If the handler being accessed (eg, the web form) doesn't implement IRequiresSessionState , the session won't be rehydrated (whether it's in-proc or not). 如果被访问的处理程序(例如,Web表单)没有实现IRequiresSessionState ,则会话将不会被重新水合(无论它是否在进程中 )。 Web forms and the MvcHandler implement that by default so you won't see any issues, but if you have custom handlers that require injection you'll hit some snags since "Session" won't exist for those requests. Web表单和MvcHandler默认实现,因此您不会看到任何问题,但如果您有需要注入的自定义处理程序,您将遇到一些障碍,因为这些请求不存在“Session”。
  4. Session_End doesn't always fire . Session_End并不总是触发 Per the docs on SessionStateModule.End , if you use out-of-proc session state you won't actually get the Session_End event, so you won't be able to clean up. 根据SessionStateModule.End上的文档 ,如果使用进程外会话状态,则实际上不会获得Session_End事件,因此您将无法清理。

Given the restrictions, it's generally good to try to stay away from session-stored scopes. 鉴于这些限制,尝试远离会话存储的范围通常是好的。 However... if that's what you're going to do, the ILifetimeScopeProvider is the way to do it. 但是......如果这就是你要做的事情,那么ILifetimeScopeProvider就是这样做的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM