2012-12-06 11 views
6

外部プラグインをサポートするASP.NET MVCプロジェクトに取り組んでいますが、今はUnityからAutofacに移行しています.Autofacのライフタイムオブジェクトをラップする必要があります。それを参照して、私はUnityで何かこれをすることができました。Autofac Lifetime Management

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では、このようなことができます。

メソッドチェーンに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はない、別のスコープにあなたは丸い穴の広場ペグに合うようにしようとするかもしれないそれは概説持っているので、かなりの方法を行います。

オートファックスコープは、より階層的です。生涯スコープでは、子過渡スコープを生成できます。たとえば、あなたは...表示される場合がありますコンテナ/ルート寿命

  • HttpRequestの範囲
    • 小さなタスク固有の過渡範囲

  • ますスコープに「タグ付け」してコンポーネントをspに登録できますHttpRequestスコープがどのように機能するかを示しています。それは特別な識別子で "タグ付け"されます。

    オブジェクトを解決するときは、どのライフタイムスコープがオブジェクトを所有しているかを判断するときです。解決は、最もネストされたスコープから発生します。上記の階層では、シングルトン、スコープの要求など、小さなタスク固有の一時的なスコープからアイテムを解決します。シングルトンが解決されると、ライフタイムスコープスタックを検索し、オブジェクトの "所有権"をルートライフタイムスコープに自動的に割り当てます。リクエストごとの項目が解決されると、特別な「HTTPリクエスト」識別子を使用してライフタイムスコープのスタックを検索し、そこに所有権を割り当てます。ファクトリスコープのアイテムは、現在の有効期間スコープで解決されます。

    注:この説明は、それがどのように機能するかを過度に単純化したものです。There is documentation explaining the lifetime scope mechanism on the Autofac site.

    ポイントは、私は上記のデザインで、オートファックのやり方と実際には「噛み合わない」ことがあります。

    DependencyScopeFactoryは、独自の一時的またはHttpRequestスコープを作成できません。 HttpRequestスコープを開始および終了する特定のライフタイム管理コンポーネントがあるため、それらを使用する必要があります。 「グローバル」な一時的なスコープはないので、実際には作成できません。

    HttpRequestの範囲、その上の使用はインラインことになっているので、過渡的範囲のためのアナログはありません

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

    ...のようなより多くのを見て、あなたはMVCを使用しているだろうと仮定:

    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。また

    、あなたがユニティを使用している場合は、Autofac(つまりEntLibは、物事を行うには好きな方法ですので)あなたはユニティスタイルでAutofacを設定することを可能にするエンタープライズライブラリコンフィギュレータパッケージを持っています。それはチェックアウトするものかもしれません。

    Unity構文を使用する必要がない場合は... ネイティブのAutofacのやり方をやり直すことをお勧めします。 1つの容器を他の容器と同じように見せたり、動作させたりするのはかなり苦労します。

    あなたのプラグインが別々のアセンブリなどであると仮定すると、Autofacモジュールと一緒に素敵なアセンブリスキャン構文を簡単に利用してプラグインをそのようにすることができます。

+0

うわー!本当にありがとう、時間を割いていただきありがとうございます。本当にこの段階でPITAを変更すると、私はAutofacに変更して試してみたいと思っていましたが、別のものを使用するために使用できない場合は、別のコンテナを使用するか、それをatmに変更するには大きすぎます。 –

+0

ニースの説明+1! –