1

Es ist großartig, dass ASP.NET DI Out-of-the-Box funktioniert und alle Konstruktorabhängigkeiten rekursiv auflöst. Manchmal möchten Sie jedoch direkt auf den DI-Container zugreifen können. Ich frage mich, ob es einen Weg gibt? Vielleicht so etwas wie folgt aus:ASP.NET Core Auflösung DbContext-Abhängigkeit zu Init-Migrationen

IService service = Container.Instance.Resolve<IService>(); 

ich nichts in der docs gefunden (obwohl ich weiß, ich kann integrierter DI-Rahmen ersetzen).


Für den größten Teil es Sie nicht brauchen, aber es gibt einige spezielle Fälle. In meiner Situation muß ich mein EF DbContext mit IoC-Containern auf App-Start-up zu starten Auto-Migrationen initialisieren, wie das mit EF-Core funktionieren sollten:

using (var context = new MyContext()) 
{ 
    context.Database.Migrate(); 
} 

Mein Kontext in Containern registriert ist, aber es ist in einem separate Klassenbibliothek Und ich möchte nicht direktKonstruktor nennen.

+1

Es wird dringend Praxis abgeraten, diese zu verwenden, da es im Grunde alle Vorteile tötet IoC der mit an erster Stelle und effektiv wird eine Service Locator-Muster, das ein Anti-Pattern ist (es verbirgt Abhängigkeiten). Es wäre interessanter zu wissen, warum du das machen würdest. In 99% der Fälle ist es nur ein schlechtes Design und im Zusammenhang mit ASP.NET Core kann ich nicht an einen einzelnen Fall denken, wo es notwendig ist, der sonst nicht gelöst werden könnte. – Tseng

+0

@Tseng Und ich stimme dir zu. Wenn App-Design gut ist, geschieht die Auflösung von Controllern zu Repositories im gesamten System. Aber es gibt bestimmte Fälle. In meiner speziellen Situation möchte ich meinen EF DbContext mit DI beim Start initialisieren, um die automatische Migration einzuleiten. Es passiert beim Start und nicht wenn die Anfrage auf den Controller trifft. – Andrei

+0

Schlüsselwörter - "beim Start." Wenn Sie während des Startvorgangs Abhängigkeiten vom Container auflösen, ist dies der Kompositionsstamm. Genau dorthin gehört es. Siehe [diesen Beitrag] (http://blog.ploeh.dk/2014/06/13/passive-attributes/) zum Auflösen von Filtern aus dem Container beim Start, geschrieben von Mark Seemann (offizieller Really Smart Guy bezüglich Abhängigkeitsinjektion in. NET.) –

Antwort

2

Nachdem die Frage aktualisiert wurde und klar ist, dass es sich um EntityFramework Core-Migrationen handelt, gibt es eine halboffizielle Methode des ASP.NET Core-Teams zur korrekten Lösung der DbContext beim Start der Anwendung.

Standardmäßig ist die DbContext als Dienst für Bereiche registriert, sodass Sie pro Anforderung instanziiert werden. Der Haken beim Start der Anwendung ist, dass es noch keinen Kontext gibt und nur app.ApplicationServices innerhalb der Configure Methode verfügbar ist und der ApplicationServices Provider im Wesentlichen Singletons auflöst (Bereich ist ein Singleton pro Bereich und Anwendungsbereich bleibt so lange wie die Anwendung).

Also ist der Trick, zuerst einen Bereich zu erstellen, lösen Sie die DbContext, führen Sie die Operationen und dann den Kontext (und die DbContext damit).

Beispiele finden Sie in den MusicStore-Beispielanwendungen here und here.

Im Moment ist dies der einzige sichere Weg, um Probleme zu lösen, die zu Problemen mit entsorgten Objektausnahmen führen.

Bitte beachten Sie auch, dass der früheste Punkt, den Sie dies tun können, in der Configure Methode ist, denn nur dann wurde der IoC-Container gebaut. In ConfigureServices füllen Sie nur die IServiceCollection.

Der entsprechende Code-Schnipsel:

void Configure(IApplicationBuilder app) 
{ 
    //Populates the MusicStore sample data 
    SampleData.InitializeMusicStoreDatabaseAsync(app.ApplicationServices).Wait(); 
} 

public static class SampleData 
{ 
    ... 

    public static async Task InitializeMusicStoreDatabaseAsync(IServiceProvider serviceProvider, bool createUsers = true) 
    { 
     using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) 
     { 
      var db = serviceScope.ServiceProvider.GetService<MusicStoreContext>(); 

      if (await db.Database.EnsureCreatedAsync()) 
      { 
       await InsertTestData(serviceProvider); 
       if (createUsers) 
       { 
        await CreateAdminUser(serviceProvider); 
       } 
      } 
     } 
    } 
} 

Edit:

Zusätzliche Ressourcen zu diesem Thema: