2012-02-24 31 views
4

目前,我正在嘗試Autofac在新的ASP.NET MVC項目有使用Ninject,溫莎城堡等IoC容器在過去的幾年之後。因此,雖然我通常瞭解IoC容器,但對於Autofac而言我還是比較新的,我仍在尋找一些最佳實踐。Autofac:任何解決最內層範圍的方法?

目前我正在試圖找出是否有解決內部嵌套範圍的一種方式。

我有以下情況:註冊爲SingleInstance()的組件具有創建嵌套生命週期作用域的方法,提供將某些組件配置爲InstancePerLifetimeScope的配置操作,並且在此嵌套作用域內解析註冊的組件做一些有用的東西,就像這樣:

ILifetimeScope currentScope = ???; 

using (var scope = currentScope.BeginLifetimeScope(cb => { 
    cb.RegisterType<X>().InstancePerLifetimeScope(); 
    // ... 
})) 
{ 
    var comp = scope.Resolve<X>(); 
    // ... 
} 

的問題是,我想currentScope是最裏面的壽命範圍,因爲我知道,X依賴於最內側範圍內的部件。在最簡單的情況下,例如,當前請求的生命週期範圍。我當然可以用AutofacDependencyResolver.Current.RequestLifetimeScope得到它,但我不希望使用,因爲它是不是真的很好測試。而且,這個終身範圍並不一定是最內在的。

那麼,有沒有辦法找到如給予最裏面的壽命範圍根容器或不同的ILifetimeScope?

回答

4

在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和這樣的裏面的單元測試,而不必實際真正的請求上下文。這也意味着您應該能夠在註冊/解析方法中使用請求生命週期範圍,而不必退回到應用程序容器中。

+0

在我的情況下,「BigComponent」是一個註冊表,它擁有應用程序整個生命週期的某些對象。嵌套作用域在應用程序啓動(第一個HTTP請求)期間用於實例化動態發現的某些類型(插件體系結構)。我當前的解決方案是將Func 注入到當前註冊爲「()=> AutofacDependencyResolver.Current.RequestLifetimeScope」的「BigComponent」中。仍然不是很好,但它將靜態引用留給範圍外的服務定位器。 [編輯] – 2012-02-24 23:50:49

+0

順便說一句:用_innermost_作用域我的意思是嵌套最深的作用域。對我來說,應用程序容器是_outermost_範圍。 – 2012-02-24 23:51:27

+0

我對最內/最外層的引用存在誤解,對不起。無論哪種方式,您都無法在任何一個方向上走棧,所以如果您必須執行服務位置,則會陷入AutofacDependencyResolver。請注意,如果您使用MVC IDependencyResolver,那麼DependencyResolver.Current.GetService將始終走出請求生命週期,因此您可能不需要該lambda ...哦,除非您正在進行註冊。所以,是的,你仍然需要這個。 – 2012-02-25 00:09:28