Frage
Wie soll ich (unter Verwendung der Standard-Abhängigkeitsinjektion) eine DbContext
Instanz in eine Instanz injizieren IHostedService
?
Was habe ich versucht?
Ich lasse meine IHostedService
Klasse derzeit eine MainContext
(abgeleitete DbContext
) Instanz im Konstruktor übernehmen.
Wenn ich die Anwendung starte, bekomme ich:
Der Scoped-Service 'Microsoft.EntityFrameworkCore.DbContextOptions' kann nicht vom Singleton 'Microsoft.Extensions.Hosting.IHostedService' verwendet werden.
Also habe ich versucht, den DbContextOptions
Übergang durch Angabe von:
services.AddDbContext<MainContext>(options =>
options.UseSqlite("Data Source=development.db"), ServiceLifetime.Transient);
in meiner Startup
Klasse.
Der Fehler bleibt jedoch derselbe, obwohl gemäß diesem gelösten Github-Problem die DbContextOptions
übergebene Lebensdauer dieselbe im AddDbContext
Aufruf angegebene Lebensdauer haben sollte .
Ich kann den Datenbankkontext nicht zu einem Singleton machen, da sonst gleichzeitige Aufrufe zu Parallelitätsausnahmen führen würden (da nicht garantiert wird, dass der Datenbankkontext threadsicher ist).
Antworten:
Eine gute Möglichkeit, Dienste innerhalb gehosteter Dienste zu verwenden, besteht darin, bei Bedarf einen Bereich zu erstellen. Dies ermöglicht die Verwendung von Diensten / Datenbankkontexten usw. mit der Lebensdauerkonfiguration, mit der sie eingerichtet wurden. Wenn kein Bereich erstellt wird, kann dies theoretisch dazu führen, dass einzelne DbContexts erstellt und der Kontext nicht ordnungsgemäß wiederverwendet wird (EF Core 2.0 mit DbContext-Pools).
Fügen
IServiceScopeFactory
Sie dazu ein ein und erstellen Sie bei Bedarf einen Bereich. Lösen Sie dann alle Abhängigkeiten, die Sie von diesem Bereich benötigen. Auf diese Weise können Sie auch benutzerdefinierte Dienste als Abhängigkeiten mit Gültigkeitsbereich registrieren, wenn Sie die Logik aus dem gehosteten Dienst verschieben und den gehosteten Dienst nur zum Auslösen von Arbeiten verwenden möchten (z. B. regelmäßig eine Aufgabe auslösen - dies würde regelmäßig Bereiche erstellen und den Aufgabendienst in erstellen dieser Bereich, in den auch ein Datenbankkontext eingefügt wird).public class MyHostedService : IHostedService { private readonly IServiceScopeFactory scopeFactory; public MyHostedService(IServiceScopeFactory scopeFactory) { this.scopeFactory = scopeFactory; } public void DoWork() { using (var scope = scopeFactory.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>(); … } } … }
quelle
IServiceScopeFactory
undIServiceProvider
direktem Injizieren ?IServiceProvider
gibt Ihnen nur den Root-Dienstanbieter. Während es auch die Schnittstelle implementiert, um einen Bereich zu erstellen, können Sie ihn verwenden. Die allgemeine Regel ist jedoch, so wenig wie nötig anzufordern.DoWork
innerhalb derusing
Klausel einen neuen Thread (der die Lebensdauer überlebt ) spawne und einige der Dienste verwende, die ich darin abgerufen habe , ist das in Ordnung ? Oder definiert der Geltungsbereich, wann ein Dienst veräußert wird?await Task.Delay(…)
Ich möchte gerne lange laufende geplante Arbeiten ausführen .AddDbContext()
von EF bereitgestellten Standardmethoden registrieren es nur als Gültigkeitsbereich. Am Ende des Bereichs führt EF beispielsweise eine Bereinigung durch. Sie möchten keinen Singleton-Datenbankkontext in Webanwendungen haben, da sonst alle Ihre Komponenten die Transaktionen anderer Komponenten beeinträchtigen würden. Alle Dienste, die DB-Kontextinstanzen verwenden (über Konstruktorinjektion), müssen ebenfalls einen Gültigkeitsbereich haben.