Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Die Entwurfszeittools sind Teil von EF, die Bootstrapping für Entwurfszeitvorgänge wie Gerüstbau für ein Modell oder Migrationsverwaltung ausführen. Sie sind für das Instanziieren von DbContext-Objekten zur Entwurfszeit verantwortlich.
Es gibt zwei primäre Einstiegspunkte: dotnet-ef und die NUGet Package Manager Console (PMC) EF Core-Tools. Beide sind dafür verantwortlich, Informationen zu den Projekten von Benutzenden zu sammeln, sie zu kompilieren und dann die Datei „ef.exe“ aufzurufen, die schließlich die Entwurfszeit-Einstiegspunkte in „EFCore.Design.dll“ aufruft.
dotnet-ef
dotnet-ef ist ein .NET-Tool. das dotnet-Präfix ermöglicht es, den Befehl als Teil des Hauptbefehls dotnet aufzurufen: dotnet ef.
Für diesen Befehl gibt es zwei primäre Eingaben: das Startprojekt und das Zielprojekt. dotnet-ef ist dafür verantwortlich, Informationen zu diesen Projekten zu lesen und sie dann zu kompilieren.
Es liest Informationen über die Projekte, indem eine MSBuild .targets-Datei eingebunden und das benutzerdefinierte MSBuild-Ziel aufgerufen wird. Die .targets-Datei wird in dotnet-ef als eingebettete Ressource kompiliert. Die Quelle befindet sich unter src/dotnet-ef/Resources/EntityFrameworkCore.targets.
Es hat ein bisschen Logik am Anfang, um Projekte mit mehreren Zielzielen zu behandeln. Im Wesentlichen wählt es einfach das erste Zielframework aus und ruft sich erneut auf. Nachdem ein einzelnes Zielframework ermittelt wurde, ruft es mehrere MSBuild-Eigenschaften wie AssemblyName, OutputPath, RootNamespace usw. ab.
Nachdem wir die Projektinformationen gesammelt haben, kompilieren wir das Startprojekt. Wir gehen davon aus, dass das Zielprojekt auch transitiv kompiliert wird.
Dann ruf dotnet-ef „ef.exe“ auf.
PMC-Tools
Die PMC-Tools führen eine ähnliche Funktion wie dotnet-ef aus, verwenden jedoch Visual Studio-APIs anstelle von MSBuild. Sie werden als Microsoft.EntityFrameworkCore.Tools-Paket ausgeliefert. Sie sind ein spezielles VS-fähiges PowerShell-Modul, das automatisch über init.ps1in die NuGet Package Manager-Konsole geladen wird. Wie dotnet-ef verwendet jeder Befehl zwei primäre Eingaben: das Startprojekt und das Zielprojekt. Die Standardwerte dieser Werte stammen jedoch aus der IDE. Das Zielprojekt wird standardmäßig auf das als Standardprojekt angegebene Projekt innerhalb der Paket-Manager-Konsole festgelegt. Das Startprojekt wird standardmäßig auf das als Startprojekt angegebene Projekt im Projektmappen-Explorer festgelegt (über Als Startprojekt festlegen).
Die PMC-Tools sammeln nach Möglichkeit Informationen zu den Projekten über die EnvDTE--APIs. Gelegentlich ist es notwendig, auf das Common Project System (CPS) oder die MSBuild-APIs zurückzugreifen. Die moderne C#-Projektsystemimplementierungsquelle ist unter dem dotnet/project-system Projekt auf GitHub verfügbar.
Nach dem Sammeln der Informationen erstellt sie die gesamte Lösung.
Tipp
Das Problem #9716 besteht darin, es so zu aktualisieren, dass nur das Startprojekt erstellt wird.
Anschließend wird wie bei dotnet-ef „ef.exe“ aufgerufen. Die PMC-Tools verfügen über eine gewisse zusätzliche Logik, nachdem Sie ef.exe aufrufen, um alle Dateien zu öffnen, die von einem Befehl erstellt wurden, um eine integriertere Benutzeroberfläche zu ermöglichen.
ef.exe
Manchmal wird „ef.exe“ (in Ermangelung eines besseren Namens) auch als „Insider“ bezeichnet und ist in dotnet-ef sowie den PMC-Tools in Form von Binärdateien enthalten. Es gibt verschiedene Binärdateien für verschiedene Zielframeworks und Plattformen.
- Werkzeuge/
- net461/
- any/
- ef.exe
- win-x86/
- ef.exe
- win-arm64/
- ef.exe
- any/
- netcoreapp2.0/
- any/
- ef.dll
- any/
- net461/
Die .NET Framework-Assemblys werden nur für EF Core 3.1-Projekte und frühere Versionen, die auf das .NET Framework abzielen, aufgerufen. Im Design können Sie die neueste Version der Tools für Projekte verwenden, die ältere Versionen von EF verwenden. Es gibt kein x64, weil die Assembly im Verzeichnis Any auf die AnyCPU-Plattform abzielt, die sowohl auf x64- als auch auf arm64-Versionen von Windows als x64 läuft.
Die .NET Core 2.0-Assembly wird für Projekte für .NET Core oder .NET 5 und höher verwendet.
Die Hauptaufgabe von „ef.exe“ besteht darin, die Ausgabeassembly des Startprojekts zu laden und die Entwurfszeit-Einstiegspunkte in „EFCore.Design.dll“ aufzurufen.
In .NET Framework verwenden wir eine separate App-Domäne (AppDomain) zum Laden der Projektassembly, die die Datei „App/Web.config“ des Projekts übergibt, um von NuGet oder Benutzenden hinzugefügte Umleitungen zu berücksichtigen und zu binden.
Auf .NET Core/5+ rufen wir ef.dll unter Verwendung der Projektdateien .deps.json und .runtimeconfig.json auf, um das tatsächliche Laufzeitverhalten und Assembly-Ladeverhalten des Projekts zu emulieren.
dotnet exec ef.dll --depsfile startupProject.deps.json --runtimeconfig startupProject.runtimeconfig.json
Tipp
Problem #18840 betrifft in erster Linie die Verwendung von AssemblyLoadContext statt dotnet exec, um die Assembly des Benutzers zu laden. Dies sollte es den Tools ermöglichen, mit mehr Projekttypen zu arbeiten, einschließlich derjenigen für Android und iOS.
Nachdem alles für das Laden eingerichtet wurde, ruft „ef.exe“ über Reflexion und „Aktivor.CreateInstance“ (bzw. „AppDomain.CreateInstance“ in .NET Framework) „EFCore.Design.dll“ auf.
EFCore.Design.dll
EFCore.Design.dlloder genauer gesagt enthält Microsoft.EntityFrameworkCore.Design.dll alle Entwurfszeitlogik für EF Core. Alle Einstiegspunkte befinden sich innerhalb der OperationExecutor Klasse. Viele der Seltsamkeit im Design dieser Klasse (MarshallByRefObject, geschachtelte Typen usw.) ergeben sich aus der Notwendigkeit, sie über AppDomains in .NET Framework aufzurufen. Eine Menge könnte vereinfacht werden, wenn diese Anforderung entfernt wurde. Alle Signaturen sind schwach typiert, um sowohl die Vorwärts- als auch die Abwärtskompatibilität mit den Tools zu ermöglichen. Denken Sie daran, dass verschiedene Versionen der Tools verwendet werden können, um Projekte mit unterschiedlichen Versionen von EF aufzurufen.
Zusätzlich zum Executor ist DbContextActivator ein weiterer wichtiger Typ in dieser Assembly. Er wird von einigen der ASP.NET Web Tools-Komponenten verwendet, um DbContext von Benutzenden zur Entwurfszeit zu instanziieren.
Erstellen eines DbContext-Elements
Bevor eine bestimmte Entwurfszeitlogik ausgeführt wird, ist in der Regel eine DbContext-Instanz erforderlich. Benutzer*innen können einen einfachen oder vollqualifizierten Typnamen ohne Beachtung der Groß-/Kleinschreibung für DbContext angeben, oder sie können keinen angeben, wenn nur ein einzelner DbContext-Typ vorhanden ist. Auf beide Weise müssen wir alle DbContext-Typen ermitteln, bevor wir sie auf ein einzelnes eingrenzen. Die Logik zum Ermitteln von DbContext-Typen befindet sich in der FindContextTypes-Methode von DbContextOperations.
Wir suchen nach DbContext-Typen aus verschiedenen Quellen.
- Verweise von IDesignTimeDbContextFactory<T>-Implementierungen in der Startassembly.
- DbContext-Instanzen, die dem Anwendungsdienstanbieter hinzugefügt werden. Um eine Liste aller Kontexttypen abzurufen, rufen wir alles ab, was als
DbContextOptionsregistriert ist, und betrachten die ContextType-Eigenschaft. (Siehe unten, wie wir den Anwendungsdienstanbieter erhalten.) - Typen, die von DbContext in den Start- und Zielassemblys abgeleitet sind
Wir verwenden auch verschiedene Methoden zum Erstellen des Typs. Hier befinden sie sich in der Reihenfolge nach Bedeutung.
- Verwendung einer IDesignTimeDbContextFactory (<T>) Implementierung
- Verwenden von IDbContextFactory<T> vom Anwendungsdienstanbieter
- Verwenden von ActivatorUtilities.CreateInstance
Suchen nach Anwendungsdiensten
Für die höchste Genauigkeit zum Laufzeitverhalten versuchen wir, die DbContext-Instanz direkt vom Anwendungsdienstanbieter abzurufen. Wir teilen diese Logik mit den ASP.NET Core-Tools. Sie wird im Rahmen des dotnet/runtime- Projekts auf GitHub unter dem Verzeichnis Microsoft.Extensions.HostFactoryResolver verwaltet.
Kurz gesagt, hier sind einige der strategien, die sie verwendet.
- Suchen Sie nach einer Methode mit dem Namen BuildWebHost, CreateWebHostBuilder oder CreateHostBuilder neben dem Assemblyeinstiegspunkt.
- Erstellen des Hosts und Abrufen der Dienste aus der Services-Eigenschaft
- Aufrufen des Einstiegspunkts für die Assembly
- Abfangen der Dienste beim Erstellen des Hosts und Beenden vor dem tatsächlichen Starten des Hosts
Entwurfszeitdienste
Neben den Anwendungsdiensten und den internen DbContext-Diensten gibt es einen dritten Satz von Entwurfszeitdiensten. Diese werden nicht zum internen Dienstanbieter hinzugefügt, da sie zur Laufzeit nie benötigt werden. Die Entwurfszeitdienste werden von DesignTimeServicesBuilder erstellt. Es gibt zwei Hauptpfade – eins mit einer Kontextinstanz und einer ohne. Der Pfad ohne Kontextinstanz wird in erster Linie beim Gerüstbau für eine neue DbContext-Instanz verwendet. Hier gibt es mehrere Erweiterbarkeitspunkte, damit Benutzer, Anbieter und Erweiterungen die Dienste außer Kraft setzen und anpassen können.
Der Benutzer kann Dienste anpassen, indem er der Startassembly eine Implementierung von IDesignTimeServices hinzufügt.
Anbieter können Dienste anpassen, indem sie das DesignTimeProviderServices-Attribut zu ihrer Assembly hinzufügen. Dies verweist auf eine Implementierung von IDesignTimeServices.
Erweiterungen können Dienste anpassen, indem DesignTimeServicesReference-Attribute zur Ziel- oder Startassembly hinzugefügt werden. Wenn das Attribut einen Anbieter angibt, wird es nur hinzugefügt, wenn dieser Anbieter verwendet wird.
Protokollierung und Ausnahmen
Nach dem Instanziieren von DbContext wird die Protokollierung mit der Ausgabe des Tools verknüpft. Dadurch kann die Ausgabe über die Laufzeit generiert werden. Alle Ausnahmefehler werden ebenfalls in die Ausgabe geschrieben. Es gibt einen speziellen Ausnahmetyp (OperationException), der ausgelöst werden kann, um die Tools ordnungsgemäß zu beenden und eine einfache Fehlermeldung ohne Stapelüberwachung anzuzeigen.