Ich erhalte die folgende Ausnahme, wenn ich versuche, benutzerdefinierten DbContext in der Configure
-Methode in der Datei Startup.cs
Zu verwenden. Ich verwende ASP.NET Core in Version 2.0.0-preview1-005977
Nicht behandelte Ausnahme: System.Exception: Ein Dienst des Typs 'Communicator.Backend.Data.CommunicatorContext' für den Parameter 'dbContext' der Methode 'Configure' konnte für den Typ 'Communicator.Backend.Startup' nicht aufgelöst werden. ---> System.InvalidOperationException: Der Bereichsdienst 'Communicator.Backend.Data.CommunicatorContext' vom Stammanbieter kann nicht aufgelöst werden.
Diese Ausnahme wird auch ausgelöst, wenn ich versuche, eine andere Instanz zu empfangen.
Nicht behandelte Ausnahme: System.Exception: Ein Dienst vom Typ 'Communicator.Backend.Services.ILdapService' konnte nicht aufgelöst werden
...
Hier sind meine Methoden ConfigureServices
und 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);
}
Angebotsunterlagen
ASP.NET Core Dependency Injection stellt Anwendungsdienste während des Starts einer Anwendung bereit. Sie können diese Services anfordern, indem Sie die entsprechende Schnittstelle als Parameter in den Konstruktor Ihrer Klasse
Startup
oder in eine ihrer MethodenConfigure
oderConfigureServices
aufnehmen.Bei Betrachtung jeder Methode in der Klasse
Startup
in der Reihenfolge, in der sie aufgerufen werden, können die folgenden Dienste als Parameter angefordert werden:
- Im Konstruktor:
IHostingEnvironment
,ILoggerFactory
- In der
ConfigureServices
Methode:IServiceCollection
- In der
Configure
Methode:IApplicationBuilder
,IHostingEnvironment
,ILoggerFactory
,IApplicationLifetime
Sie versuchen, Dienste aufzulösen, die während des Startvorgangs nicht verfügbar sind.
...CommunicatorContext dbContext, ILdapService ldapService) {
das gibt Ihnen die Fehler, die Sie bekommen. Wenn Sie Zugriff auf die Implementierungen benötigen, müssen Sie eine der folgenden Aktionen ausführen:
Ändern Sie die Methode ConfigureServices
, und greifen Sie dort über die Servicesammlung auf sie zu. d.h.
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();
}
Ändern Sie die Methode ConfigureServices
, um IServiceProvider zurückzugeben, und die Methode Configure
, um ein IServiceProvider
zu übernehmen und Ihre Abhängigkeiten dort aufzulösen. d.h.
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);
}
Die Lösung von NKosi funktioniert, weil Sie durch Aufrufen von services.BuildServiceProvider()
ohne Parameter das validateScopes
nicht übergeben. Da diese Überprüfung deaktiviert ist, wird die Ausnahme nicht ausgelöst. Dies bedeutet nicht, dass das Problem nicht vorhanden ist.
EF Core DbContext
ist mit einem bestimmten Lebensstil registriert. In ASP native DI ist der Container-Bereich mit der Instanz von IServiceProvider
verbunden. Wenn Sie Ihr DbContext
normalerweise von einem Controller aus verwenden, gibt es kein Problem, weil = ASP) erstellt für jede Anforderung einen neuen Bereich (neue Instanz von IServiceProvider
) und löst dann alles in dieser Anforderung auf. Während des Anwendungsstarts ist jedoch kein Anforderungsbereich vorhanden Sie haben eine Instanz von IServiceProvider
, die nicht über einen Gültigkeitsbereich verfügt (oder mit anderen Worten im Stammbereich). Dies bedeutet, dass Sie einen Gültigkeitsbereich selbst erstellen sollten. Sie können dies folgendermaßen tun:
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
}
Die Methode ConfigureServices
kann unverändert bleiben.
[~ # ~] edit [~ # ~]
Ihre Lösung wird in 2.0.0 RTM ohne Änderungen funktionieren, da in RTM ein Dienstanbieter mit Gültigkeitsbereich für die Methode Configure erstellt wird https: // github.com/aspnet/Hosting/pull/1106 .
In ASP.NET Core 2.0 und neueren Versionen können Sie den benötigten Bereichsdienst einfach in den Konstruktor Configure
einfügen, wie Sie es ursprünglich versucht haben:
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
CommunicatorContext dbContext,
ILdapService ldapService)
{
// ...
}
Dies ist dank der Verbesserungen in # 1106 viel einfacher.
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
füge dies in Program.cs nach .UseStartup<Startup>()
hinzu
Funktioniert bei mir
Alternativ können Sie einen Servicebereich innerhalb Ihrer Configure
-Methode erstellen:
var scopeFactory = ApplicationServices.GetService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetService<CommunicatorDbContext>();
DbInitializer.Initializer(dbContext, ldapService);
}
Obwohl, wie bei Slack erwähnt, mach das nicht ;-)