3

HTTPヘッダーの値に基づいてサービスを注入したいとします。だから私は2つのクラス - DbDataProviderとInMemDataProviderを持っています。どちらもIDataProviderから実装されています。 API呼び出しが行われるたびに、DbDataProviderが必須かInMemDataProviderが必要かを判断するヘッダーがクライアントから渡されます。どのように達成するのですか?つまり、私は、ミドルウェアの1つにあるServiceCollectionにサービスを注入する必要があります。それは可能ですか?ASP.NETコアのミドルウェアでサービスを注入

問題は、スタートアップクラスのConfigureServiceメソッドでは、私はHttpContextを取得できないということです。 HTTPコンテキストを取得できるミドルウェアを作成しましたが、そこにサービスを挿入するにはどうすればいいですか?

+1

ランタイム条件に基づいてサービスを注入しないようにする(実行時データ自体を注入しないようにする)(https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99)コンポーネント。代わりに、両方の実装で注入され、実行時に呼び出しを実装に転送する複合コンポーネントを使用します。工場は決して正しいソリューションではありません。 – Steven

答えて

4

これを行う方法は簡単ではありません。 ConfigureServicesメソッド以外のIServiceCollectionは変更できません。しかし、可能であれば、それは無用です。コンテナは、Configureが呼び出される前に既に構築されているためです。

あなたができることは、ファクトリクラスを作成してスコープとして登録することです。

あなたのミドルウェアで次に
public interface IDataProviderFactory 
{ 
    bool UseInMemoryProvider { get; set; } 
    IDataProvider Create(); 
} 

public class DataProviderFactory : IDataProviderFactory 
{ 
    private readonly IServiceProvider provider; 

    public bool UseInMemoryProvider { get; set; } 

    public DataProviderFactory(IServiceProvider provider) 
    { 
     this.provider = provider; 
    } 

    public IDataProvider Create() 
    { 
     if(UseInMemoryProvider) 
     { 
      return provider.RequestService<InMemoryDataProvider>(); 
     } 

     return provider.RequestService<DbDataProvider>(); 
    } 
} 

public class MyMiddleware 
{ 
    public void Invoke(HttpContext context) 
    { 
     var dataProviderFactory = context.RequestServices.RequestService<IDataProviderFactory>(); 

     // Your logic here 
     if(...) 
     { 
      dataProviderFactory.UseInMemoryStore = true; 
     } 
    } 
} 

とあなたのコントローラ/サービス中:

public class MyController : Controller 
{ 
    private readonly IDataProvider dataProvider; 

    public MyController(IDataProviderFactory dataProviderFactory) 
    { 
     dataProvider = dataProviderFactory.Create(); 
    } 
} 
1

TSENから上記の答えが正解です。ファクトリを実装する必要があります。

さらに、ファクトリメソッドをサービスコレクションに登録することもできます。同様に:

Services.AddTransient(serviceProvider => serviceProvider.GetService<IDataProviderFactory>().Create()) 

IDataProviderを登録します。 Createでは、そのHTTPヘッダー値を評価して、正しいIDataProviderインスタンスを返すようにする必要があります。次に、どのクラスでもコンストラクタを使用してIDataProviderを要求するだけで、正しい実装がコンテナによって提供されます。

+0

これはシングルトンであるため、常に同じインスタンスを返すことになります;)この場所の別の問題は、あなたが 'HttpContext'に直接アクセスできず、' IHttpContextAccessor'がデフォルトで登録されていないということです)、各リクエストでそれを作成するのは少しオーバーヘッドがあり、彼の他のサービスがコントローラの外でHttpContextを必要としないならば、彼はただ一つの理由でそれを登録すべきではありません。 https://github.com/aspnet/Announcements/issues/190 – Tseng

+0

私は一時的な(更新された回答)を意味します。私たちは実際にIHttpContextAccessorを手動で登録しました。それぞれ自分自身に私は言うだろう。 –

関連する問題