Startup.cs
ファイルのConfigure
メソッドでカスタムDbContextを使用しようとすると、次の例外を受け取ります。バージョン2.0.0-preview1-005977でASP.NET Coreを使用しています
未処理の例外:System.Exception:タイプ 'Communicator.Backend.Startup'のメソッド 'Configure'のパラメーター 'dbContext'のタイプ 'Communicator.Backend.Data.CommunicatorContext'のサービスを解決できませんでした。 ---> System.InvalidOperationException:スコープサービス 'Communicator.Backend.Data.CommunicatorContext'をルートプロバイダーから解決できません。
この例外は、他のインスタンスを受信しようとした場合にもスローされます。
未処理の例外:System.Exception: 'Communicator.Backend.Services.ILdapService'タイプのサービスを解決できませんでした
...
これが私のConfigureServices
およびConfigure
メソッドです。
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CommunicatorContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddCookieAuthentication();
services.Configure<LdapConfig>(Configuration.GetSection("Ldap"));
services.AddScoped<ILdapService, LdapService>();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, CommunicatorContext dbContext, ILdapService ldapService)
{
app.UseAuthentication();
app.UseWebSockets();
app.Use(async (context, next) =>
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(context, webSocket);
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
app.UseMvc();
DbInitializer.Initialize(dbContext, ldapService);
}
ドキュメントの引用
ASP.NET Core依存性注入は、アプリケーションの起動時にアプリケーションサービスを提供します。
Startup
クラスのコンストラクターまたはConfigure
またはConfigureServices
メソッドのいずれかのパラメーターとして適切なインターフェースを含めることにより、これらのサービスを要求できます。
Startup
クラスの各メソッドが呼び出された順に見ると、次のサービスがパラメーターとして要求される場合があります。
- コンストラクター内:
IHostingEnvironment
、ILoggerFactory
ConfigureServices
メソッド:IServiceCollection
Configure
メソッド:IApplicationBuilder
、IHostingEnvironment
、ILoggerFactory
、IApplicationLifetime
起動時に利用できないサービスを解決しようとしていますが、
...CommunicatorContext dbContext, ILdapService ldapService) {
エラーが発生します。実装にアクセスする必要がある場合は、次のいずれかを実行する必要があります。
ConfigureServices
メソッドを変更し、サービスコレクションからアクセスします。つまり.
public IServiceProvider ConfigureServices(IServiceCollection services) {
services.AddDbContext<CommunicatorContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddCookieAuthentication();
services.Configure<LdapConfig>(Configuration.GetSection("Ldap"));
services.AddScoped<ILdapService, LdapService>();
services.AddMvc();
// Build the intermediate service provider
var serviceProvider = services.BuildServiceProvider();
//resolve implementations
var dbContext = serviceProvider.GetService<CommunicatorContext>();
var ldapService = serviceProvider.GetService<ILdapService>();
DbInitializer.Initialize(dbContext, ldapService);
//return the provider
return serviceProvider();
}
ConfigureServices
メソッドを変更してIServiceProviderを返し、Configure
メソッドを変更してIServiceProvider
を取得し、そこで依存関係を解決します。つまり.
public IServiceProvider ConfigureServices(IServiceCollection services) {
services.AddDbContext<CommunicatorContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddCookieAuthentication();
services.Configure<LdapConfig>(Configuration.GetSection("Ldap"));
services.AddScoped<ILdapService, LdapService>();
services.AddMvc();
// Build the intermediate service provider then return it
return services.BuildServiceProvider();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory, IServiceProvider serviceProvider) {
//...Other code removed for brevity
app.UseMvc();
//resolve dependencies
var dbContext = serviceProvider.GetService<CommunicatorContext>();
var ldapService = serviceProvider.GetService<ILdapService>();
DbInitializer.Initialize(dbContext, ldapService);
}
NKosiのソリューションは、パラメータなしでservices.BuildServiceProvider()
を呼び出すことにより、validateScopes
を渡さないために機能します。この検証は無効になっているため、例外はスローされません。これは、問題が存在しないという意味ではありません。
EF Core DbContext
は、スコープ付きライフスタイルに登録されています。 ASPネイティブDIでは、コンテナスコープはIServiceProvider
のインスタンスに接続されます。通常、コントローラーからDbContext
を使用する場合、ASPはリクエストごとに新しいスコープ(IServiceProvider
の新しいインスタンス)を作成し、それを使用してすべてを解決するため、問題はありません。このリクエスト内。ただし、アプリケーションの起動時には、リクエストのスコープはありません。スコープされていない(つまりルートスコープにある)IServiceProvider
のインスタンスがあります。これは、自分でスコープを作成する必要があることを意味します。次のようにできます:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<CommunicatorContext>();
var ldapService = scope.ServiceProvider.GetRequiredService<ILdapService>();
// rest of your code
}
// rest of Configure setup
}
ConfigureServices
メソッドは変更しないでかまいません。
編集
ソリューションは、2.0.0 RTMで機能します。RTMで、Configureメソッド https://github.com/aspnet/ Hosting/pull/1106 。
ASP.NET Core 2.0以降では、最初にしようとしたように、必要なスコープ付きサービスをConfigure
コンストラクターに単純に挿入できます。
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
CommunicatorContext dbContext,
ILdapService ldapService)
{
// ...
}
#1106 の改善により、これは非常に簡単になりました。
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
program_csの.UseStartup<Startup>()
の後に追加します
私のために働く
または、Configure
メソッド内にサービススコープを作成できます。
var scopeFactory = ApplicationServices.GetService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetService<CommunicatorDbContext>();
DbInitializer.Initializer(dbContext, ldapService);
}
Slackで述べたように、これをしないでください;-)