1. ホーム
  2. c#

[解決済み] ConfigureServices内からASP.NET Core DIでインスタンスを解決する

2022-03-20 22:13:04

質問

ASP.NET Core MVC 内蔵の依存性注入フレームワークを使用して、手動で型を解決するにはどうすればよいですか?

コンテナのセットアップは簡単です。

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddTransient<ISomeService, SomeConcreteService>();
}

しかし、どのようにすれば ISomeService インジェクションを実行せずに? 例えば、こんなことをしたいのです。

ISomeService service = services.Resolve<ISomeService>();

にはそのようなメソッドはありません。 IServiceCollection .

解決方法は?

その IServiceCollection インタフェースは 構築 依存性注入コンテナです。完全に構築された後、それは IServiceProvider インスタンスを作成し、それを使ってサービスを解決することができます。このインスタンスはサービスを解決するために使用できます。 IServiceProvider をどのようなクラスにも適用できます。そのため IApplicationBuilderHttpContext クラスは、サービスプロバイダも提供することができます。 ApplicationServices または RequestServices プロパティをそれぞれ指定します。

IServiceProvider を定義しています。 GetService(Type type) メソッドでサービスを解決します。

var service = (IFooService)serviceProvider.GetService(typeof(IFooService));

また、次のような便利な拡張メソッドも用意されています。 serviceProvider.GetService<IFooService>() (を追加)。 using に対して Microsoft.Extensions.DependencyInjection ).

スタートアップ・クラス内のサービスの解決

依存関係の注入

ランタイムのホスティングサービスプロバイダは、特定のサービスを Startup クラスのような IConfiguration , IWebHostEnvironment ( IHostingEnvironment 3.0より前のバージョンでは)。 ILoggerFactory IServiceProvider . 後者はホスティング層によって構築されたインスタンスであることに注意してください。 には、アプリケーションを起動するために必要なサービスだけが含まれています。 .

ConfigureServices() メソッドはサービスを注入することはできません。 IServiceCollection 引数で指定します。これは、以下の理由で理にかなっています。 ConfigureServices() は、アプリケーションで必要なサービスを登録する場所です。しかし、例えばスタートアップのコンストラクタに注入されたサービスをここで使用することもできます。

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    // Use Configuration here
}

に登録されているサービスは、すべて ConfigureServices() に注入することができます。 Configure() メソッドの後に、任意の数のサービスを追加することができます。 IApplicationBuilder パラメータを使用します。

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IFooService>();
}

public void Configure(IApplicationBuilder app, IFooService fooService)
{
    fooService.Bar();
}

依存関係を手動で解決する

サービスを手動で解決する必要がある場合、できれば ApplicationServices が提供する IApplicationBuilder の中で Configure() メソッドを使用します。

public void Configure(IApplicationBuilder app)
{
    var serviceProvider = app.ApplicationServices;
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}

を渡して直接使用することが可能です。 IServiceProvider のコンストラクタで使用します。 Startup というクラスがありますが、上記のように これには、サービスの限定されたサブセットが含まれます。 そのため、有用性は限定的である。

public Startup(IServiceProvider serviceProvider)
{
    var hostingEnv = serviceProvider.GetService<IWebHostEnvironment>();
}

でサービスを解決する必要がある場合は ConfigureServices() メソッドを使用する場合は、別のアプローチが必要です。中間的な IServiceProvider から IServiceCollection 登録されたサービスを含むインスタンス それまで :

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFooService, FooService>();

    // Build the intermediate service provider
    var sp = services.BuildServiceProvider();

    // This will succeed.
    var fooService = sp.GetService<IFooService>();
    // This will fail (return null), as IBarService hasn't been registered yet.
    var barService = sp.GetService<IBarService>();
}

ご注意ください。 一般に、サービスを ConfigureServices() メソッドで使用されます。 コンフィギュレーション アプリケーション・サービスです。へのアクセスだけが必要な場合もあります。 IOptions<MyOptions> のインスタンスです。の値をバインドすることで、これを実現することができます。 IConfiguration のインスタンスに MyOptions (これは本質的にオプションフレームワークが行うことです)。

public void ConfigureServices(IServiceCollection services)
{
    var myOptions = new MyOptions();
    Configuration.GetSection("SomeSection").Bind(myOptions);
}

のオーバーロードを使用することもできます。 AddSingleton/AddScoped/AddTransient :

// Works for AddScoped and AddTransient as well
services.AddSingleton<IBarService>(sp =>
{
    var fooService = sp.GetRequiredService<IFooService>();
    return new BarService(fooService);
}

サービスを手動で解決する(別名:サービスロケータ)ことは 一般にアンチパターンと呼ばれる . フレームワークやインフラ層での使用例はありますが、できる限り避けるべきです。