在Autofac,最裏面的範圍始終是容器。使用AutofacDependencyResolver,這將會是 AutofacDependencyResolver.Current.ApplicationContainer
沒有從嵌套的作用域的方式(如果你已經是一個ILifetimeScope
),以「落後走路」才能到容器。無論如何,我不一定確定你想這樣做。
這聽起來像你SingleInstance成分正在做某種服務的位置,基本上,具有手動註冊/分辨率的某些部件。如果被註冊的類型集合是固定的,那麼我可能會建議(如果可能)重新設計系統,所以SingleInstance組件不再註冊爲SingleInstance,而是註冊爲InstancePerDependency,然後讓這些其他項目作爲構造函數參數。
而不是...
// Consuming class like this...
public class BigComponent
{
public void DoSomethingCool()
{
using(var scope = ...)
{
var c = scope.Resolve<SubComponent>();
c.DoWork();
}
}
}
// ...and container registrations like this...
builder.RegisterType<BigComponent>().SingleInstance();
您可以嘗試反轉了一點:
// Consuming class like this...
public class BigComponent
{
private SubComponent _c;
public BigComponent(SubComponent c)
{
_c = c;
}
public void DoSomethingCool()
{
_c.DoWork();
}
}
// ...and container registrations like this...
builder.RegisterType<BigComponent>().InstancePerDependency();
builder.RegisterType<SubComponent>().InstancePerLifetimeScope();
的想法是沒有做對即時登記和立即的分辨率的東西。
如果你堅持做服務的位置,你將需要使用AutofacDependencyResolver.Current.ApplicationContainer
如果你需要絕對的最裏面的範圍,但要記住你註冊作用域爲InstancePerHttpRequest
任何對象將不能被解析,如果你這樣做,所以你可能會陷入困境。真的建議使用AutofacDependencyResolver.Current.RequestLifetimeScope
代替。這將使你的方法:
var requestScope = AutofacDependencyResolver.Current.RequestLifetimeScope;
using (var scope = requestScope.BeginLifetimeScope(cb => {
cb.RegisterType<X>().InstancePerLifetimeScope();
// ...
}))
{
var comp = scope.Resolve<X>();
// ...
}
在測試環境中,AutofacDependencyResolver
讓您在決定要求得到壽命如何生成供應商交換。你可以實現一個簡單/存根一個這樣的:
public class TestLifetimeScopeProvider : ILifetimeScopeProvider
{
readonly ILifetimeScope _container;
private ILifetimeScope _lifetimeScope = null;
public TestLifetimeScopeProvider(ILifetimeScope container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public ILifetimeScope ApplicationContainer
{
get { return _container; }
}
public ILifetimeScope GetLifetimeScope()
{
if (_lifetimeScope == null)
{
_lifetimeScope = ApplicationContainer.BeginLifetimeScope("httpRequest")
}
return _lifetimeScope;
}
public void EndLifetimeScope()
{
if (_lifetimeScope != null)
_lifetimeScope.Dispose();
}
}
再次,只是單元測試存根,而不是你在生產中使用過的東西。
然後,當你線了在測試中DependencyResolver
,你提供你的一生範圍提供商:
var lsProvider = new TestLifetimeScopeProvider(container);
var resolver = new AutofacDependencyResolver(container, lsProvider);
DependencyResolver.SetResolver(resolver);
這可讓您使用InstancePerHttpRequest
和這樣的裏面的單元測試,而不必實際真正的請求上下文。這也意味着您應該能夠在註冊/解析方法中使用請求生命週期範圍,而不必退回到應用程序容器中。
在我的情況下,「BigComponent」是一個註冊表,它擁有應用程序整個生命週期的某些對象。嵌套作用域在應用程序啓動(第一個HTTP請求)期間用於實例化動態發現的某些類型(插件體系結構)。我當前的解決方案是將Func注入到當前註冊爲「()=> AutofacDependencyResolver.Current.RequestLifetimeScope」的「BigComponent」中。仍然不是很好,但它將靜態引用留給範圍外的服務定位器。 [編輯] –
2012-02-24 23:50:49
順便說一句:用_innermost_作用域我的意思是嵌套最深的作用域。對我來說,應用程序容器是_outermost_範圍。 – 2012-02-24 23:51:27
我對最內/最外層的引用存在誤解,對不起。無論哪種方式,您都無法在任何一個方向上走棧,所以如果您必須執行服務位置,則會陷入AutofacDependencyResolver。請注意,如果您使用MVC IDependencyResolver,那麼DependencyResolver.Current.GetService將始終走出請求生命週期,因此您可能不需要該lambda ...哦,除非您正在進行註冊。所以,是的,你仍然需要這個。 – 2012-02-25 00:09:28