2012-12-06 171 views
6

我正在開發一個支持外部插件的ASP.NET MVC項目,現在我正在從Unity移植到Autofac,並且需要包裝Autofac的生命週期對象,以便插件不必在Unity中引用它,我可以做這件事。Autofac生命週期管理

public sealed class UnityScopeFactory : IDependencyScopeFactory 
{ 
    private HttpRequestScope _httpRequest; 

    private SingletonScope _singleton; 

    private TransientScope _transient; 

    public IDependencyScope HttpRequest() 
    { 
     return _httpRequest ?? (_httpRequest = new HttpRequestScope()); 
    } 

    public IDependencyScope Singleton() 
    { 
     return _singleton ?? (_singleton = new SingletonScope()); 
    } 

    public IDependencyScope Transient() 
    { 
     return _transient ?? (_transient = new TransientScope()); 
    } 

    private class HttpRequestScope : IDependencyScope 
    { 
     public object CreateScope() 
     { 
      return new HttpPerRequestLifetimeManager(); 
     } 
    } 

    private class SingletonScope : IDependencyScope 
    { 
     public object CreateScope() 
     { 
      return new ContainerControlledLifetimeManager(); 
     } 
    } 

    private class TransientScope : IDependencyScope 
    { 
     public object CreateScope() 
     { 
      return new TransientLifetimeManager(); 
     } 
    } 
} 

我Autofac做過類似的事情,但我不知道它是否做到這一點,我看着Autofac的RegistrationBuilder這是(不幸)內,我想出了這個正確的方法。

public class AutofacScopeFactory : IDependencyScopeFactory 
{ 
    private HttpRequestScope _httpRequest; 

    private SingletonScope _singleton; 

    private TransientScope _transient; 

    public IDependencyScope HttpRequest() 
    { 
     return _httpRequest ?? (_httpRequest = new HttpRequestScope()); 
    } 

    public IDependencyScope Singleton() 
    { 
     return _singleton ?? (_singleton = new SingletonScope()); 
    } 

    public IDependencyScope Transient() 
    { 
     return _transient ?? (_transient = new TransientScope()); 
    } 

    private class HttpRequestScope : IDependencyScope 
    { 
     public object CreateScope() 
     { 
      return new CurrentScopeLifetime(); 
     } 
    } 

    private class SingletonScope : IDependencyScope 
    { 
     public object CreateScope() 
     { 
      return new RootScopeLifetime(); 
     } 
    } 

    private class TransientScope : IDependencyScope 
    { 
     public object CreateScope() 
     { 
      return new CurrentScopeLifetime(); 
     } 
    } 
} 

此外,我得到這個工作後,我該如何使用它傳遞給ContainerBuilder?

在Unity中,我可以做這樣的事情。

public sealed class UnityDependencyContainer : IDependencyContainer 
{ 
    private readonly IUnityContainer _container; 

    public UnityDependencyContainer() 
    { 
     _container = new UnityContainer() 
    } 

    public void Register<TContract, TImplementation>(IDependencyScope scope) where TImplementation : TContract 
    { 
     LifetimeManager manager = scope.CreateScope() as LifetimeManager; 

     if (manager != null) 
     { 
      _container.RegisterType<TContract, TImplementation>(manager); 
     } 
    } 
} 

如何將IComponentLifetime的實例傳遞給方法鏈?這是死路一條嗎?

public class AutofacContainer : IDependencyContainer 
{ 
    private static readonly ContainerBuilder Builder; 

    static AutofacContainer() 
    { 
     Builder = new ContainerBuilder(); 
    } 

    public void RegisterType<TContract, TImplementation>(IDependencyScope scope) where TImplementation : TContract 
    { 
     IComponentLifetime manager = scope.CreateScope() as IComponentLifetime; 

     if (manager != null) 
     { 
      Builder.RegisterType<TImplementation>().As<TContract>(); 
     } 
    } 
} 

回答

9

Autofac不分離範圍相當你有它概括的方式,所以您可能會嘗試在一個圓孔適合方釘。

Autofac範圍更分層。任何生命週期範圍都可以產生一個子瞬態範圍。例如,你可能會看到...

  • 集裝箱/根壽命
    • HttpRequest的範圍
      • 小任務的特定瞬間範圍

你可以「標記」示波器並將組件註冊到sp ecific命名/標記範圍 - 這就是HttpRequest範圍的工作原理。它被一個特殊的標識符「標記」。

當您解析對象時,它是確定哪個生命週期範圍擁有它。解決方案發生在最嵌套的範圍內。在上面的層次結構中,您可以解決小任務特定的瞬態作用域中的項目,無論它們是單例還是請求作用域等等。當單身人士得到解決後,它將搜索生命週期範圍堆棧並自動將對象的「所有權」分配給根生存期範圍。當每個請求項目得到解決後,它會使用特殊的「HTTP請求」標識符在堆棧中搜索生命週期範圍,並在那裏分配所有權。工廠範圍項目在當前生命週期範圍內解決。

注意:這個討論是如何工作的過於簡單化。There is documentation explaining the lifetime scope mechanism on the Autofac site.

問題在於,我看到上述設計中的某些內容並不真正與Autofac做什麼「攪動」在一起。

DependencyScopeFactory無法創建自己的瞬態或HttpRequest作用域。有特定的生命週期管理組件開始和結束HttpRequest範圍,因此您需要使用這些組件;沒有'全球'的短暫範圍,所以你不能真正創建一個。

HttpRequest的範圍,假設你使用MVC,看起來更像是...

public ILifetimeScope HttpRequestScope 
{ 
    get { return AutofacDependencyResolver.Current.RequestLifetime; } 
} 

有沒有模擬一個短暫的範圍,因爲對使用被認爲是內聯:

using(var transientScope = parentScope.BeginLifetimeScope()) 
{ 
    // Do stuff and resolve dependencies using the transient scope. 
    // The IDisposable pattern here is important so transient 
    // dependencies will be properly disposed at the end of the scope. 
} 

註冊組件時,不要將它們註冊到「生命週期範圍內」。您實際上將它們註冊到組件註冊表中,組件註冊的一部分包含組件生命週期解決後的所有權信息。

var builder = new ContainerBuilder(); 

// This component is factory-scoped and will be "owned" by whatever 
// lifetime scope resolves it. You can resolve multiple of these 
// in a single scope: 
builder.RegisterType<FirstComponent>().As<ISomeInterface>(); 

// This component is a singleton inside any given lifetime scope, 
// but if you have a hierarchy of scopes, you'll get one in each 
// level of the hierarchy. 
builder.RegisterType<SecondComponent>().InstancePerLifetimeScope(); 

// This component will be a singleton inside a specifically named 
// lifetime scope. If you try to resolve it in a scope without that 
// name, it'll search up the scope stack until it finds the scope 
// with the right name. If no matching scope is found - exception. 
builder.RegisterType<ThirdComponent>().InstancePerMatchingLifetimeScope("scopename"); 

// This is a per-HTTP-request component. It's just like the 
// above InstancePerMatchingLifetimeScope, but it has a special 
// tag that the web integration knows about. 
builder.RegisterType<FourthComponent>().InstancePerHttpRequest(); 

如果你想使一個容器/登記無關的接口,它不需要一個「終身範圍管理」 - 相反,你需要傳遞一些參數表明預期壽命範圍並根據傳入的參數進行適當的註冊語法(上述)。

再次,I'd recommend you check out that documentation

另外,如果你使用Unity,Autofac確實有一個企業圖書館配置包,可以讓你在一個統一的風格配置Autofac(因爲這是EntLib怎麼喜歡做的事情)。這可能是要檢查的東西。

如果你根本不需要使用Unity語法... 我建議你只是想把事情做成本土的Autofac方式。試圖讓一個容器外觀和行爲像另一個是一個非常痛苦的努力。

假設您的插件位於獨立的程序集或其他內容中,您可以輕鬆利用一些很好的彙編掃描語法以及Autofac模塊,並以這種方式連接您的插件。

+0

哇!非常感謝您花時間,真的很感激。這是真正的PITA在這個階段改變,然後,我非常渴望改用Autofac並試用它,但是如果我不能使用它,因爲它的工作方式不同,我不得不使用另一個容器或留下來,因爲成本是太大以至於無法改變它。 –

+0

好的解釋+1! –