Nicht auf einen entsorgt Objekt in ASP.NET Kern beim Einspritzen von DbContext
Auf eine ASP.NET Kern-Projekt habe ich Folgendes beim Start:
services.AddDbContext<Context>(x => x.UseSqlServer(connectionString));
services.AddTransient<IValidationService, ValidationService>();
services.AddTransient<IValidator<Model>, ModelValidator>();
Den ValidationService ist wie folgt:
public interface IValidationService {
Task<List<Error>> ValidateAsync<T>(T model);
}
public class ValidationService : IValidationService {
private readonly IServiceProvider _provider;
public ValidationService(IServiceProvider provider) {
_provider = provider;
}
public async Task<List<Error>> ValidateAsync<T>(T model) {
IValidator<T> validator = _provider.GetRequiredService<IValidator<T>>();
return await validator.ValidateAsync(model);
}
}
Und die ModelValidator ist wie folgt:
public class ModelValidator : AbstractValidator<Model> {
public ModelValidator(Context context) {
//Some code using context
}
}
Wenn ich Spritzen ein IValidationService in einem controller und verwenden Sie es als:
List<Error> errors = await _validator.ValidateAsync(order);
Bekomme ich die Fehlermeldung:
System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application.
This may occur is you are calling Dispose() on the context, or wrapping the context in a using statement.
If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'Context'.
Jede Idee, warum bin ich mit diesem Fehler bei der Verwendung von Kontext innerhalb ModelValidator.
Wie man dieses Problem beheben?
UPDATE
Also änderte ich den code, um:
services.AddScoped<IValidationService, ValidationService>();
services.AddScoped<IValidator<Model>, ModelValidator>();
Aber ich bekomme die gleiche Fehlermeldung ...
UPDATE - Seed-Daten-Code, der in Configure Methode auf Start
Also auf "Configure" - Methode habe ich noch:
if (hostingEnvironment.IsDevelopment())
applicationBuilder.SeedData();
Und die SeedData Erweiterung:
public static class DataSeedExtensions {
private static IServiceProvider _provider;
public static void SeedData(this IApplicationBuilder builder) {
_provider = builder.ApplicationServices;
_type = type;
using (Context context = (Context)_provider.GetService<Context>()) {
await context.Database.MigrateAsync();
//Insert data code
}
}
Was bin ich?
UPDATE - EINE mögliche Lösung
Ändert sich meine Seed-Methode, die der folgenden scheint zu funktionieren:
using (IServiceScope scope = _provider.GetRequiredService<IServiceScopeFactory>().CreateScope()) {
Context context = _provider.GetService<Context>();
//Insert data in database
}
InformationsquelleAutor der Frage Miguel Moura | 2016-08-01
Du musst angemeldet sein, um einen Kommentar abzugeben.
Update für ASP.NET Core 2.1
In ASP.NET Core 2.1 die Methoden etwas verändert. Die Allgemeine Methode ist ähnlich wie der 2.0, nur der Methoden-name und die Rückgabe-Typen geändert wurden.
Gilt für ASP.NET Core 2.0
Mit ASP.NET Core 2.0 gab es einige Veränderungen, wie EF-Core-tools (
dotnet ef migrations
etc.) bestimmen Sie die DbContext-und connection-string zur design-Zeit.Den unten Antwort führt, dass die Migrationen und seeding angewendet werden, wenn beim aufrufen einer der
dotnet ef xxx
Befehle.Das neue Muster für ein design-Zeit-Instanz für die EF-Core-tools ist die Verwendung eines
BuildHostWeb
statische Methode.Als pro diese AnkündigungEF-Core wird nun die statische
BuildWebHost
Methode, die die Konfiguration der gesamten Anwendung, aber nicht ausführen.Ersetzen Sie diese in Ihrer alten
Main
MethodeSich Saatgut ist eine extension-Methode:
Alte Antwort, gilt noch ASP.NET Kern 1.x
Gibt es eine halb-offizielle Muster auf, wie die Samen, Entity Framework Core in ASP.NET Core-Anwendung, die Sie anwenden sollten, da während des Starts der Anwendung es gibt keine Anfrage und somit keine
RequestServices
(der behebt scoped services).Im wesentlichen läuft es auf den neuen Bereich erstellt haben, lösen Sie die Typen, die Sie brauchen, und entsorgen Sie den Bereich erneut, sobald Sie fertig sind.
Einer der Gründe, die direkt das auflösen der service über
app.ApplicationServices.GetService<MyService>()
ist, dassApplicationServices
ist die Anwendung (oder das Leben) Umfang der Anbieter und der Dienstleistungen aufgelöst hier am Leben bleiben, bis die Anwendung heruntergefahren.In der Regel die scoped-container beheben von seinem übergeordneten container, wenn das Objekt bereits existiert. Also, wenn Sie instanziieren des DbContext wird auf diese Weise in der Anwendung, es wird in
ApplicationServices
container und wenn eine Anfrage geschieht, eine untergeordnete container erstellt werden.Nun bei der Auflösung der DbContext wird es nicht aufgelöst werden, wie Gültigkeitsbereich, da es bereits in der übergeordneten container, also die Instanz der parent-container zurückgegeben werden, statt. Aber da es entsorgt wurde während der Aussaat, ist es nicht zugänglich sein.
Einen scope-container ist nichts anders dann ein singleton-container mit begrenzter Lebensdauer.
So nie beheben scoped services bei Programmstart w/o Verwendung der Muster über der ersten erstellen eines Bereichs und der Lösung aus.
InformationsquelleAutor der Antwort Tseng
Nur eine Vermutung, was die Ursachen der Fehler:
Sind Sie mit DI und asynchrone Aufrufe. Wenn irgendwo in Ihrem call-stack Sie eine void zurückgeben, statt der Aufgabe erhalten Sie das beschriebene Verhalten. An diesem Punkt wird der Anruf beendet ist und der Rahmen entsorgt. Überprüfen Sie also, wenn Sie einen asynchronen Aufruf, einen void zurückgibt anstelle der Aufgabe. Wenn Sie ändern Sie den Rückgabewert, der objectdisposedexception ist wohl behoben.
Und konfigurieren:
Blog-post auf, wie man diesen Fehler beheben: cannot-access-a-entsorgt-Objekt-in-asp-net-core-bei-Injektion-dbcontext
InformationsquelleAutor der Antwort Peter
Ich hatte ein ähnliches Problem, die Arbeit mit asp.net core. Ich habe einen asynchronen POST-Methode in meinem controller, und wenn es gibt void zurück habe, habe ich diese Ausnahme. Nachdem ich verändert die POST-Methode return eine AUFGABE war das problem gelöst.
Ändern von:
Zu
InformationsquelleAutor der Antwort Yang Zhang
das problem ist, dass DBContext bezieht sich pro Anfrage standardmäßig, aber Sie haben Dinge, die davon abhängen Gültigkeitsbereich als vorübergehend, damit Sie nicht die gleichen Möglichkeiten und DBContext kann entsorgt werden, bevor Sie fertig sind es zu benutzen
InformationsquelleAutor der Antwort Joe Audette