2017-08-06 13 views
1

私はASP.NETコアでAutofacを使用しています。異なるパラメータに対して異なって解決するAutofacパラメータ化されたインスタンス化

public class Foo 
{ 
    public Foo(Func<bool, Reporter> reporterFactory) { _reporterFactory = reporterFactory; } 
    private readonly Func<bool, Reporter> _reporterFactory; 
} 

そして、私はそれがこのように解決したい:

_reporterFactory(false) ---> equivalent to ---> new Reporter(false) 
_reporterFactory(true) ---> equivalent to ---> new Reporter(true) 

私が欲しい私はこのようにそれを使用する必要が

public class Reporter { 
    public Reporter (bool doLogging) { DoLogging = doLogging ; } 
    public string DoLogging { get; set; } 
    // other stuff 
} 

私の依存性がReporterですリクエストごとに同じインスタンス(つまり、AutofacのInstancePerLifetimeScope)、同じものについてはboolパラメータ。 _reporterFactory(false)を複数回呼び出すと、同じインスタンスが必要になります。 _reporterFactory(true)を何度も呼び出すと、同じインスタンスが必要になります。しかし、これらの2つのインスタンスは、互いに異なる必要があります。

だから私はこのようにそれを登録します。私は解決したときに、私は関係なく、bool引数の同じインスタンスを取得、しかし

builder 
    .Register<Reporter>((c, p) => p.TypedAs<bool>() ? new Reporter(true): new Person(false)) 
    .As<Reporter>() 
    .InstancePerLifetimeScope(); // gives "per HTTP request", which is what I need 

"Parameterized Instantiation"ため

var reporter   = _reporterFactory(false); 
var reporterWithLogging = _reporterFactory(true); 
Assert.That(reporter, Is.Not.SameAs(reporterWithLogging));  // FAIL! 

ドキュメントは

を語ります

オブジェクトを複数回解決すると、毎回同じオブジェクトインスタンスが取得されますあなたが渡すさまざまなパラメータに関係なく、時間をかけています。異なるパラメータを渡すだけで、ライフタイムスコープの尊重を破ることはありません。

これは動作を説明しています。だから私はそれを正しく登録するのですか?

+1

http://docs.autofac.org/ja/latest/faq/select-by-context.html#option-3-use-keyed-servicesヘルプですか? – mjwills

+0

@mjwillsうーん、私はそれを調べる必要があります、私は私が望むことが可能であり、私は間違った構文や何かを使用していることを望んでいた。 – grokky

+1

あなたの 'Person'はドメインエンティティのようです。アプリケーション_component_ではありません。 DIコンテナは、_components_のオブジェクトグラフを構築するためのものです。これらのオブジェクトグラフの構築中に、エンティティ、DTO、ビューモデル、およびその他のデータオブジェクトなどのランタイムデータの使用を除外した、その依存性に関するあいまい性は存在してはなりません。 – Steven

答えて

2

コメントで述べたように、あなたがあなたの目標を達成するためにキーサービスを使用することができますが:

builder.Register(c => new Reporter(true)).Keyed<IReporter>(true).InstancePerLifetimeScope(); 
builder.Register(c => new Reporter(false)).Keyed<IReporter>(false).InstancePerLifetimeScope(); 

事はあなたが別のクラスにそれを注入する場合、あなたはIIndex<bool, IReporter>でそれを注入しなければならない、です:

public class Foo 
{ 
    public Foo(IIndex<bool, IReporter> reporters) 
    { 
     var withLogging = reporters[true]; 
     var withoutLogging = reporters[false]; 
    } 
} 

IIndexは、密閉容器に連結されたコンポーネントを作るAutofacのインターフェイスであり、これは望ましくないかもしれません。これを避けるには、次のように工場を追加登録することができます。

builder.Register<Func<bool, IReporter>>((c,p) => withLogging => c.ResolveKeyed<IReporter>(withLogging)).InstancePerLifetimeScope(); 

public class Foo 
{ 
    public Foo(Func<bool, IReporter> reporters) 
    { 
     var withLogging = reporters(true); 
     var withoutLogging = reporters(false); 
    } 
} 

これで、コンテナ自体に連結されていない実用的なソリューションが完成しました。

関連する問題