實例范圍決定了如何在同一服務的請求之間共享實例。 請注意,您應該熟悉生命周期范圍的概念,以便更好地理解此處發生的情況。
當請求服務時,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