ASP.NET Core MVC 組み込み依存性注入フレームワークを使用して型を手動で解決するにはどうすればよいですか?
コンテナの設定は非常に簡単です:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<ISomeService, SomeConcreteService>();
}
しかし、注入を実行せずに解決するにはどうすればよいでしょうかISomeService
? たとえば、次のようにします。
ISomeService service = services.Resolve<ISomeService>();
にはそのようなメソッドはありませんIServiceCollection
。
ベストアンサー1
のIServiceCollection
インターフェースは依存性注入コンテナの構築に使用されます。完全に構築された後、IServiceProvider
IServiceProvider
インスタンスはサービスを解決するために使用できます。任意のクラスに を注入できます。IApplicationBuilder
およびHttpContext
クラスは、サービスプロバイダも提供できます。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);
}
手動でサービスを解決すること(サービスロケータとも呼ばれる)は一般的にアンチパターンと見なされるフレームワークやインフラストラクチャ層ではユースケースがありますが、可能な限り避けるべきです。