2016-12-02 18 views
1

私はDI問題に遭遇しました。 このソリューションは、クラスライブラリとWebApi2アプリケーション(クラスライブラリを消費し、APIを公開します)で構成されています。クラスライブラリ内の依存関係注入

私は、プロジェクトのすべてのDIを設定するクラスライブラリにAutofac.moduleを定義しました。

WebApi2プロジェクトでは、(Autofac.WebApi2を使用して)DIコンテナを作成し、モジュールをクラスライブラリからロードします。 WepApi2プロジェクトのapiコントローラがクラスライブラリのサービスを要求すると、すべての依存関係が作成されます。このすべてがうまくいきます!

問題は、私は今、私がリフレクションを使ってこれを行う唯一の方法を知っている限り、クラスライブラリが文字列からいくつかのクラスをインスタンス化する必要があることです。このように:

var ruleType = Type.GetType(rule.RuleImplementation.Implementation); 
var rule = (IRule)Activator.CreateInstance(ruleType,param1,param2); 

問題はiRuleのインタフェースを実装するクラスも解決を取得する必要がある依存関係を持っており、これが今の私はしばらくの間、私のキーボード上の私を叩いて作ったものであるということです。

反射とautoFacを併用してオブジェクトをインスタンス化することはできますか?私はまだオブジェクトに私のparamsを渡すことができる必要があります。

...または(webApi2アセンブリで作成された)コンテナに何らかの形でアクセスして解決する方法がありますか?私はこれがアンチパターンと考えられるサービスパターンの一種だろうと思う。

どうすればいいですか?すべての入力は非常に感謝しています。

答えて

2

Activator.CreateInstanceを使用してコンポーネントを作成することは、DIライブラリが提供する機能と安全ガードがなく、基本的にコンテナが実行しているロジックを再実装することを意味するため、悪い考えです。

私は、プロジェクトのすべてのDIを設定するAutofac.moduleをクラスライブラリに定義しました。

これはあなたの問題の原因です。アプリケーションには、オブジェクトグラフが作成(登録)される場所が1つだけあり、これはアプリケーションのComposition Rootです。このコンポジションルートは、プレゼンテーションレイヤー(Web API)の上にある別のレイヤーと見なすことができますが、同じプロジェクト内にコンポジションルート(レイヤー)とプレゼンテーションレイヤーの両方を配置することは非常に一般的です。

これを行うと、コンポジションルート内に既にコンテナにアクセスできるため、問題は解決します。

データベースからの定義を使用してルールを作成できるようにするには、IRuleActivator抽象を定義するのが良い方法です。この抽象化は、ライブラリ内で定義し、コンポジションルート内で実装することができます。ライブラリは、コンテナの存在に気づかないままにしながら、これには、コンテナをラップするために実装することができます:

// Defined in the library 
public interface IRuleActivator 
{ 
    IRule GetRule(RuleData rule); 
} 

// Defined in the Compostion Root 
public sealed class AutofacRuleActivator : IRuleActivator 
{ 
    private readonly IComponentContext context; 
    public AutofacRuleActivator(IComponentContext context) { 
     this.context = context; 
    } 

    public IRule GetRule(RuleData rule) { 
     Type ruleType = Type.GetType(rule.RuleImplementation.Implementation); 
     return (IRule)this.context.Resolve(ruleType); 
    } 
} 
あなたはiRuleの作成するためのファクトリを作成することができ
1

:私はいくつかに行くだろうなパラメータについては

public IRuleFactory 
{ 
    IRule CreateRule(params); 
} 

その後、IRuleFactoryの実装に注入することができるIParamsProvidersの種類は、RuleImplは、オブジェクト構築のちょうどあなたの実装である、同様に反射することができます:

public class RuleFactory : IRuleFactory 
{ 
    public RuleFactory(IParamsProvider provider) 
    { 
     ... 
    } 

    public IRule CreateRule() 
    { 
     return new RuleImpl(provider.Param1, provider.Param2); 
    } 
} 

これらのインターフェイスをIocに登録し、サービスハンドラに挿入します。

+0

私はこの解決策が好きです。私が唯一の欠点を見る限り、実行時に私がDBに照会するときに最初に知っているので、それらが必要であるかどうかにかかわらず、すべてのルールを私のサービスに注入しなければならないということです。 – iCediCe

関連する問題