实例范围决定了如何在同一服务的请求之间共享实例。 请注意,您应该熟悉生命周期范围的概念,以便更好地理解此处发生的情况。
当请求服务时,Autofac可以返回单个实例(单实例作用域),新实例(每个依赖作用域)或某种上下文中的单个实例,例如 线程或HTTP请求(每个生命周期范围)。
这适用于从显式Resolve()
调用返回的实例以及容器内部创建的实例,以满足另一个组件的依赖关系。
选择正确的生命周期范围将有助于避免组件寿命过长或不够长的俘获依赖和其他陷阱。 开发人员需要为每个应用程序组件做出正确的选择。
1.Instance Per Dependency
每次都会返回一个新的实例,并且这是默认的生命周期。
var builder = new ContainerBuilder();
// This...
builder.RegisterType<Worker>();
// 此句代码的效果同上
builder.RegisterType<Worker>().InstancePerDependency();
当您解析每个依赖项的实例组件时,每次都会得到一个新组件。
using(var scope = container.BeginLifetimeScope())
{
for(var i = 0; i < 100; i++)
{
// Every one of the 100 Worker instances
// resolved in this loop will be brand new.
var w = scope.Resolve<Worker>();
w.DoWork();
}
}
2.Single Instance
单例,所有服务请求都将会返回同一个实例。
var builder = new ContainerBuilder();
builder.RegisterType<Worker>().SingleInstance();
当您解析单个实例组件时,无论您请求何处,都始终获得相同的实例。
// It's generally not good to resolve things from the
// container directly, but for singleton demo purposes
// we do...
var root = container.Resolve<Worker>();
// We can resolve the worker from any level of nested
// lifetime scope, any number of times.
using(var scope1 = container.BeginLifetimeScope())
{
for(var i = 0; i < 100; i++)
{
var w1 = scope1.Resolve<Worker>();
using(var scope2 = scope1.BeginLifetimeScope())
{
var w2 = scope2.Resolve<Worker>();
// root, w1, and w2 are always literally the
// same object instance. It doesn't matter
// which lifetime scope it's resolved from
// or how many times.
}
}
}
3.Instance Per Lifetime Scope
在一个嵌套语句块中,只会返回一个实例。
var builder = new ContainerBuilder();
builder.RegisterType<Worker>().InstancePerLifetimeScope();
在解决每个生命周期实例作用域组件时,每个嵌套作用域将获得一个实例(例如,每个工作单元)。
using(var scope1 = container.BeginLifetimeScope())
{
for(var i = 0; i < 100; i++)
{
// 每次从这里解析它
// 你会得到相同的实例。
var w1 = scope1.Resolve<Worker>();
}
}
using(var scope2 = container.BeginLifetimeScope())
{
for(var i = 0; i < 100; i++)
{
//每次从这里解析它
//每次解析都会得到一个同样的实例,但是这个示例和上面的循环的实例不是同一个
var w2 = scope2.Resolve<Worker>();
}
}
4.Instance Per Matching Lifetime Scope
这与上面的'每个生命周期的实例范围'概念类似,但允许更精确地控制实例共享。
当您创建嵌套的生存期范围时,您可以“标记”或“命名”范围。具有每匹配生命周期范围的组件每个嵌套生命周期范围最多只有一个实例与给定名称匹配。这允许您创建一种“范围单例”,其中嵌套的生命周期范围可以在不声明全局共享实例的情况下共享某个组件的实例。
这对于特定于单个工作单元的对象是有用的,例如,一个HTTP请求,作为一个嵌套的生命周期可以创建每个工作单元。如果每个HTTP请求都创建一个嵌套的生命周期,那么每个具有每个生命周期范围的组件都将为每个HTTP请求创建一个实例。 (有关每个请求生命周期范围的更多信息。)
在大多数应用中,只有一层容器嵌套足以代表工作单元的范围。如果需要更多级别的嵌套(例如像global-> request-> transaction这样的东西),组件可以配置为使用标签在层次结构中的特定级别共享。
var builder = new ContainerBuilder();
builder.RegisterType<Worker>().InstancePerMatchingLifetimeScope("myrequest");
提供的标记值在启动时与生存期范围关联。 如果在没有正确命名的生命周期范围时尝试解析每个匹配生命周期范围的组件,则会得到一个异常。
//使用标签创建生命周期
using(var scope1 = container.BeginLifetimeScope("myrequest"))
{
for(var i = 0; i < 100; i++)
{
var w1 = scope1.Resolve<Worker>();
using(var scope2 = scope1.BeginLifetimeScope())
{
var w2 = scope2.Resolve<Worker>();
// w1和w2始终是同一个对象
//实例,因为该组件是每个匹配生命周期范围的,
//所以它实际上是一个单例
//命名范围
}
}
}
//使用标签创建另一个生命周期作用域
using(var scope3 = container.BeginLifetimeScope("myrequest"))
{
for(var i = 0; i < 100; i++)
{
// w3 will be DIFFERENT than the worker resolved in the
// earlier tagged lifetime scope.
var w3 = scope3.Resolve<Worker>();
using(var scope4 = scope3.BeginLifetimeScope())
{
var w4 = scope4.Resolve<Worker>();
// w3和w4始终是同一个对象,因为
//他们在相同的标记范围内,但他们是
//与之前的w1,w2不一样。
}
}
}
//你无法解析每个匹配生命周期的组件
//如果没有匹配的范围。
using(var noTagScope = container.BeginLifetimeScope())
{
//因为这个范围没有,所以抛出一个异常
//有预期的标签,也没有任何父范围!
var fail = noTagScope.Resolve<Worker>();
}
5.Instance Per Request
某些应用程序类型自然适用于“请求”类型语义,例如ASP.NET Web Forms和MVC应用程序。 在这些应用程序类型中,有能力为每个请求提供一种“单例”。
通过提供众所周知的生命周期范围标记,注册便利方法以及针对常见应用程序类型的集成,每个请求的实例基于每个匹配生命周期范围的实例构建。 但在幕后,它仍然只是每个匹配生命周期范围的实例。
这意味着如果您尝试解析注册为每个请求实例但没有当前请求的组件,那么您将得到一个异常。
var builder = new ContainerBuilder();
builder.RegisterType<Worker>().InstancePerRequest();
6.Instance Per Owned
拥有的隐式关系类型创建新的嵌套生命周期作用域。 可以使用每个拥有实例的注册来将依赖关系限定到拥有的实例。
var builder = new ContainerBuilder();
builder.RegisterType<MessageHandler>();
builder.RegisterType<ServiceForHandler>().InstancePerOwned<MessageHandler>();
在这个例子中,ServiceForHandler
服务将被限制在拥有的MessageHandler
实例的生命周期中。
using(var scope = container.BeginLifetimeScope())
{
//消息处理程序本身以及
//解析依赖的ServiceForHandler服务
//在一个小小的生命周期范围内
// “范围。” 请注意解析一个拥有的<T>
//表示您负责处理。
var h1 = scope.Resolve<Owned<MessageHandler>>();
h1.Dispose();
}
原文:http://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html