ASP.NET Core DI でインスタンスを ConfigureServices 内から解決する 質問する

ASP.NET Core DI でインスタンスを ConfigureServices 内から解決する 質問する

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

コンテナの設定は非常に簡単です:

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

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

しかし、注入を実行せずに解決するにはどうすればよいでしょうかISomeService? たとえば、次のようにします。

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

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

ベストアンサー1

IServiceCollectionインターフェースは依存性注入コンテナの構築に使用されます。完全に構築された後、IServiceProviderIServiceProviderインスタンスはサービスを解決するために使用できます。任意のクラスに を注入できます。IApplicationBuilderおよびHttpContextクラスは、サービスプロバイダも提供できます。ApplicationServicesまたはRequestServicesそれぞれプロパティです。

IServiceProvider定義するGetService(Type type)サービスを解決する方法:

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

他にも便利な拡張メソッドがいくつかあります。serviceProvider.GetService<IFooService>()(usingにを追加しますMicrosoft.Extensions.DependencyInjection)。

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

依存関係の注入

ランタイムのホスティングサービスプロバイダーは、クラスのコンストラクタに特定のサービスを注入することができますStartupIConfigurationIWebHostEnvironmentIHostingEnvironment3.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ます。IApplicationBuilderConfigure()

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()中間体を構築できます。IServiceProviderIServiceCollection

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>IConfigurationMyOptions

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);
}

手動でサービスを解決すること(サービスロケータとも呼ばれる)は一般的にアンチパターンと見なされるフレームワークやインフラストラクチャ層ではユースケースがありますが、可能な限り避けるべきです。

おすすめ記事