2017-03-20 3 views
1

私はこの問題がAutofac: Resolving dependencies with parametersと重複しないと思います。下記の目的のセクションをお読みください。ヘルプが必要です。依存するコンポーネントにパラメータを渡したい

私はIContentProviderを宣言し、実装がコンストラクタのパラメータとしてurlWebContentProviderの名前。

interface IContentProvider 
{ 
    string Content { get; } 
} 

class WebContentProvider { 
    public WebContentProvider(string url) { ... } 
    public string Content => GetHtmlFrom(this.url); 
} 

ここで、2つのコンシューマクラスには、異なるURLのコンテンツを提供するWebContentProvderが必要です。それらはすべてインターフェイスIContentUserを実装しています。

class FirstContentUser : IContentUser 
{ 
    IContentProvider provider; 

    public FirstContentUser(IContentProvider provider) 
    { 
     this.provider = provider; 
    } 

    public void Use() 
    { 
     Console.WriteLine("[First Content User]"); 
     Console.WriteLine(provider.Content); 
    } 
} 

クラスSecondContentUserと同様です。

public AttempAutofac() 
{ 
    var builder = new ContainerBuilder(); 

    builder.RegisterType<WebContentProvider>() 
     .As<IContentProvider>(); 
     // HERE!!! how can I use `url` metadata given below, 
     // or some other way to get the url while resolving 

    builder.RegisterType<FirstContentUser>() 
     .As<IContentUser>() 
     .WithMetadata("url", "http://the.1st.url"); 

    builder.RegisterType<SecondContentUser>() 
     .As<IContentUser>() 
     .WithMetadata("url", "http://the.2nd.url"); 

    container = builder.Build(); 
} 

その後、私はすべての消費者のインスタンスを取得するためにscope.Resolve<IEnumerable<IContentUser>>()を使用したい:

は、ここに私の登録コードです。

近い将来、新しい登録クラスFasterWebContentProviderWebContentProviderの代わりに1つの登録行を変更するだけで簡単に設定できたら幸いです。

  1. Autofacはインターフェースに従って実装を構成するために使用される:

    はここに私の目的です。私はすべてのものが登録段階で決定されることを望み、決議段階では決定しません。つまり、コンシューマがリソースの場所を指定し、次にAutofacがIContentProviderの実装を選択して、その場所からコンテンツ(リソース)をロードし、特定のコンシューマにコンテンツを提供します。

  2. すべてのインターフェイスと実装はあらかじめ定義されているため、変更することはできません(「Func暗黙の関係」の方法は使用できません)。

  3. を解決するためのパラメータは、動的であり、設定値だけでなく、消費されることもあります。だから私はその答えに記載されている "ラムダ式登録"の方法を使用することはできません。

  4. おそらく、Autofacモジュールは問題を解決することができますが、どうすればいいのかわかりません。

正しく設計されているかどうかわかりません。私はデザインを改善する方法を指摘できる人に感謝します。

+1

側の注意点としては:

'How do I pick a service implementation by context?'後、私は解決策を得ました。 –

+2

[Autofac:パラメータによる依存関係の解決]の可能な複製(http://stackoverflow.com/questions/26327177/autofac-resolving-dependencies-with-parameters) –

答えて

0

私は、一つのことを把握この問題の上に熟考:IContentProviderのインスタンスは彼らの消費者なしで作成する必要があります

ので、彼らは消費者からの情報を取得することはできません。したがって、別のIContentProviderインスタンスまたはクリエイターを登録しなければならず、消費者はキーまたは名前で1つを見つけることができます。あなたは手動でサービスロケータアンチパターンの罠に落ちたんだあなたのコードの中でいくつかの点でscope.Resolveを呼び出している場合は、

private void Register() 
{ 
    var builder = new ContainerBuilder(); 

    builder.Register(c => new WebContentProvider("http://the.1st.url")) 
     .Keyed<IContentProvider>(typeof(FirstContentUser)); 

    builder.Register(c => new WebContentProvider("http://the.2nd.url")) 
     .Keyed<IContentProvider>(typeof(SecondContentUser)); 

    builder.RegisterType<FirstContentUser>() 
      .As<IContentUser>() 
      .WithParameter(
      CreateResolvedParameter<IContentProvider, FirstContentUser>()); 

    builder.RegisterType<SecondContentUser>() 
     .As<IContentUser>() 
      .WithParameter(
      CreateResolvedParameter<IContentProvider, SecondContentUser>()); 

    container = builder.Build(); 
} 

private static ResolvedParameter CreateResolvedParameter<ParamType, KeyType>() 
{ 
    return new ResolvedParameter(
     (pi, ctx) => pi.ParameterType == typeof(ParamType), 
     (pi, ctx) => ctx.ResolveKeyed<ParamType>(typeof(KeyType))); 
} 
関連する問題