【问题标题】:Autofac - InstancePerHttpRequest vs InstancePerLifetimeScopeAutofac - InstancePerHttpRequest 与 InstancePerLifetimeScope
【发布时间】:2017-12-08 03:00:18
【问题描述】:

这两种作用域有什么区别?

我在每一层(存储库、服务、MVC 应用程序)中构建 Module(s),但为了拥有 InstancePerHttpRequest,您需要 Autofac.Mvc 程序集。

我应该在我的存储库和服务层中使用哪个范围?

【问题讨论】:

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


    【解决方案1】:

    InstancePerHttpRequestInstancePerApiRequest 本质上是做同样的事情——你会为每个离散的 Web 请求获得一个服务实例。我将使用InstancePerHttpRequest 作为其余答案,但请记住,这两者是可以互换的。

    InstancePerLifetimeScope 表示将为每个需要您的服务的生命周期范围创建一个新的服务实例。每个 Web 请求都有自己的新生命周期范围,因此在实践中,这两个请求通常会做完全相同的事情。

    唯一真正的区别在于,如果您在InstancePerHttpRequest 下注册了一个服务,并且您从另一个注册为SingleInstance 的服务请求其中一个服务。在这种情况下:

    • SingleInstance 组件位于 root 范围内
    • InstancePerHttpRequest 组件位于名为“AutofacWebRequest”的范围内,它是根范围的

    Autofac 不允许从子作用域解析 - 所以本质上,SingleInstance 服务无法找到 InstancePerHttpRequest 服务。

    但是,如果在这种情况下您使用了InstancePerLifetimeScope(而不是InstancePerHttpRequest),那么您的服务将很好地解决。

    我写了一篇相当详尽的文章,其中包含可下载的代码,试图详细解释这一切 - see here。引用文章:

    这里的一个常见误解是,在 WebAPI 应用程序中使用 InstancePerLifetimeScope 注册您的组件意味着您的组件位于 Web 请求的范围内——即“生命周期”是指“网络请求的生命周期”。正如您在此处看到的,这是错误的。

    组件的生命周期由解决它的范围决定。

    由于 SingletonResolvable 从根范围解析其令牌,因此该令牌实例位于根范围内,而不是 Web 请求的范围内。我以前说过,但我再说一遍:这个令牌将一直存在,直到整个应用程序被处理掉(例如,IIS 工作进程被回收)。任何从根作用域请求 ScopeToken 的东西都将获得对该标记的引用。

    希望有所帮助 - 我很感激这个问题现在已经很老了,但它仍然非常相关!

    【讨论】:

    • 那篇文章非常有帮助。很棒的图表和演示应用程序。极大地帮助了我找出自己问题的答案here
    • 如果有人在 asp.net core 中尝试这个,因为它有自己的 DI,使用 autofac 时你必须使用 InstancePerLifetimeScope 而不是 InstancePerRequest。更多信息here
    • 就我而言,我有一个 Web 项目,到目前为止,它一直在使用“InstancePerRequest”进行我的 Autofac 配置。现在,我想重用(大部分)相同的配置以包含在我的 Web 应用程序随附的单独的 Job runner 应用程序中。因此,如果我将“InstancePerRequest”的所有实例更改为“InstancePerLifetimeScope()”,我会看到相同的功能吗?谢谢
    • @CiaranGallagher - 这可能会起作用,但不会完全一样。我们通过创建我们自己命名的生命周期范围标记然后使用InstancePerMatchingLifetimeScope 来处理这种情况,这实际上是InstancePerRequest 在幕后所做的。然后,我们使用我们的生命周期范围标签为每个作业启动一个新的生命周期范围。希望有帮助!
    • 我不是 100% 如何做到这一点,所以我在这里提出了一个问题:stackoverflow.com/questions/47884141/…Thanks
    【解决方案2】:

    您的应用程序中唯一能够完全决定对象生命周期的位置是组合根。

    在这种情况下,您会遇到冲突 - 您有一个通用模块,它不应该访问 MVC 集成提供的扩展方法 - 但是您需要访问它才能正确管理生命周期.在这种情况下,如果您的模块可以提供合理的默认值,例如InstancePerLifetimeScope,那么这就是我在模块级别所做的。然后,您让组合根覆盖该行为。在这种情况下,组合根会将生命周期更改为InstancePerHttpRequest。由于最后一次注册将覆盖之前的注册,因此您应该处于良好状态。

    我实际上已经不再创建与包含给定层的程序集共存的模块,原因如下:

    1. 它引入了对 Autofac 的依赖,除了在我的作文根目录之外我不想要它
    2. 这表明模块知道应该如何管理它的生命周期,这通常不是真的。如果是这样,为什么不提供提供生命周期管理的工厂或其他类?

    相反(在足够大的项目中),我在组合根级别创建模块,因为在这个级别我清楚地知道它们应该如何连接在一起。有时我会创建一个包含模块并充当默认组合根的Ioc 程序集——但这通常在“真正的”组合根(例如,拉入@987654324 的控制台或MVC 应用程序)处被覆盖@大会)。

    【讨论】:

    • 除了项目根目录外,您可能对 Autofac 没有任何依赖关系,但是您将高度依赖任何 IOC,您可以将 Autofac 替换为与 autofac 完全一样的行为。我认为这些隐式依赖比显式依赖更难管理。
    【解决方案3】:

    在 Autofac 中,每个生命周期作用域是一种使用嵌套生命周期创建自定义作用域的通用方法。

    使用InstancePerLifetimeScope 为您提供每个请求 范围,它为单个请求添加组件生命周期,并在内部为此组件使用InstancePerLifetimeScrope

    在您需要的任何地方使用InstancePerLifetimeScope,或者如果在您的服务层中引用Autofac.Integration.Mvc 程序集存在问题 - 在请求的每个开头手动创建嵌套范围并使用InstancePerLifetimeScope

    【讨论】:

    • 那么我应该在我的服务和存储库模块中使用InstancePerLifetimeScope,在我的global.asax 中使用InstancePerHttpRequest
    • 不,如果您不手动创建嵌套范围,则每个生命周期范围将是一个单例范围。所以你最好在任何地方都使用请求范围,或者在每个请求开始时手动创建嵌套范围。
    • 所以我需要在我的服务和存储库模块中使用 InstancePerHttpRequest 吗?您是否有创建仅针对我可以实现的每个请求的范围的示例?谢谢!
    • 是的。正如 Kaleb 在他的回答中提出的那样,其他好的建议是将所有 Autofac 模块移动到 MVC 项目 - 然后您将在多个层中摆脱不必要的 Autofac 依赖项和生命周期逻辑,最好应该在入口点的一个地方你的应用程序。
    • 要为每个请求创建嵌套生命周期,请在 BeginRequest ASP.NET 事件上对当前生命周期使用 BeginLifetimeScope 方法(可以作为 ILifetimeScope 注入您的类型或从 AutofacDependencyResolver.Current.RequestLifetimeScope 获取)。并在 EndRequest 事件中处理您的嵌套生命周期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-27
    相关资源
    最近更新 更多