Tillämpa migreringar av Entity Framework Core i .NET Aspire
Eftersom .NET.NET Aspire projekt använder en containerbaserad arkitektur är databaserna tillfälliga och kan återskapas när som helst. Entity Framework Core (EF Core) använder en funktion som kallas migreringar för att skapa och uppdatera databasscheman. Eftersom databaser återskapas när appen startas måste du använda migreringar för att initiera databasschemat varje gång appen startas. Detta uppnås genom att registrera ett migreringstjänstprojekt i din app som kör migreringar under starten.
I den här guiden får du lära dig hur du konfigurerar .NET Aspire projekt för att köra EF Core migreringar vid appstart.
Förutsättningar
Om du vill arbeta med .NET.NET Aspirebehöver du följande installerat lokalt:
- .NET 8,0 eller .NET 9,0
- En OCI-kompatibel container-runtime, till exempel:
- Docker Desktop eller Podman. Mer information finns i Container Runtime.
- En IDE (Integrated Developer Environment) eller kodredigerare, till exempel:
- Visual Studio 2022 version 17.9 eller senare (valfritt)
-
Visual Studio Code (valfritt)
- C# Dev Kit: Tillägg (valfritt)
- JetBrains Rider med .NET.NET Aspire insticksprogram (valfritt)
Mer information finns i .NET.NET Aspire installation och verktygoch .NET.NET Aspire SDK.
Hämta startappen
I denna handledning används en exempelapp som visar hur du tillämpar EF Core migreringar i .NET Aspire. Använd Visual Studio för att klona exempelappen från GitHub eller använd följande kommando:
git clone https://github.com/MicrosoftDocs/aspire-docs-samples/
Exempelappen finns i mappen SupportTicketApi. Öppna lösningen i Visual Studio eller VS Code och ta en stund att granska exempelappen och se till att den körs innan du fortsätter. Exempelappen är ett rudimentärt supportbegäran-API och innehåller följande projekt:
- SupportTicketApi.Api: Det ASP.NET Core projekt som hostar API:et.
- SupportTicketApi.Data: Innehåller EF Core kontexter och modeller.
- SupportTicketApi.AppHost: Innehåller .NET.NET Aspire applikationsvärd och konfiguration.
- SupportTicketApi.ServiceDefaults: Innehåller standardkonfigurationerna för tjänsten.
Kör appen för att säkerställa att den fungerar som förväntat. På kontrollpanelen .NET.NET Aspire väljer du https Swagger-slutpunkten och testar API:ets GET /api/SupportTickets slutpunkt genom att expandera operationen och välja Prova det. Välj Kör för att skicka begäran och visa svaret:
[
{
"id": 1,
"title": "Initial Ticket",
"description": "Test ticket, please ignore."
}
]
Skapa migreringar
Börja med att skapa några migreringar att tillämpa.
Öppna en terminal (Ctrl+` i Visual Studio).
Ange SupportTicketApiSupportTicketApi.Api som aktuell katalog.
Använd kommandoradsverktyget
dotnet ef
för att skapa en ny migrering för att avbilda databasschemats ursprungliga tillstånd:dotnet ef migrations add InitialCreate --project ..\SupportTicketApi.Data\SupportTicketApi.Data.csproj
Kommandot för att fortsätta:
- Kör kommandoradsverktyget för EF Core-migrering i katalogen SupportTicketApi.Api.
dotnet ef
körs på den här platsen eftersom API-tjänsten är den plats där DB-kontexten används. - Skapar en migrering med namnet InitialCreate.
- Skapar migreringen i mappen Migrations i SupportTicketApi.Data-projektet.
- Kör kommandoradsverktyget för EF Core-migrering i katalogen SupportTicketApi.Api.
Ändra modellen så att den innehåller en ny egenskap. Öppna SupportTicketApi.DataModelsSupportTicket.cs och lägg till en ny egenskap i klassen
SupportTicket
:public sealed class SupportTicket { public int Id { get; set; } [Required] public string Title { get; set; } = string.Empty; [Required] public string Description { get; set; } = string.Empty; public bool Completed { get; set; } }
Skapa en ny migrering för att samla in ändringarna i modellen:
dotnet ef migrations add AddCompleted --project ..\SupportTicketApi.Data\SupportTicketApi.Data.csproj
Nu har du några migreringar att tillämpa. Sedan skapar du en migreringstjänst som tillämpar dessa migreringar under appstarten.
Skapa migreringstjänsten
Om du vill köra migreringarna vid start måste du skapa en tjänst som tillämpar migreringarna.
Lägg till ett nytt Worker Service projekt i lösningen. Om du använder Visual Studiohögerklickar du på lösningen i Solution Explorer och väljer Add>New Project. Välj Worker Service och ge projektet namnet SupportTicketApi.MigrationService. Om du använder kommandoraden använder du följande kommandon från lösningskatalogen:
dotnet new worker -n SupportTicketApi.MigrationService dotnet sln add SupportTicketApi.MigrationService
Lägg till SupportTicketApi.Data- och SupportTicketApi.ServiceDefaults-projektreferenserna i SupportTicketApi.MigrationService-projektet med hjälp av Visual Studio eller kommandoraden:
dotnet add SupportTicketApi.MigrationService reference SupportTicketApi.Data dotnet add SupportTicketApi.MigrationService reference SupportTicketApi.ServiceDefaults
Lägg till 📦Aspire. Microsoft.EntityFrameworkCore.SqlServer NuGet-paketreferens till SupportTicketApi.MigrationService-projektet med hjälp av Visual Studio eller kommandoraden:
dotnet add package Aspire.Microsoft.EntityFrameworkCore.SqlServer
Lägg till de markerade raderna i filen Program.cs i SupportTicketApi.MigrationService-projektet:
using SupportTicketApi.Data.Contexts; using SupportTicketApi.MigrationService; var builder = Host.CreateApplicationBuilder(args); builder.AddServiceDefaults(); builder.Services.AddHostedService<Worker>(); builder.Services.AddOpenTelemetry() .WithTracing(tracing => tracing.AddSource(Worker.ActivitySourceName)); builder.AddSqlServerDbContext<TicketContext>("sqldata"); var host = builder.Build(); host.Run();
I föregående kod:
- Förlängningsmetoden
AddServiceDefaults
lägger till standardfunktioner för tjänster. -
AddOpenTelemetry
-tilläggsmetoden konfigurerar OpenTelemetry funktionalitet. - Metoden
AddSqlServerDbContext
adderarTicketContext
-tjänsten till tjänstsamlingen. Den här tjänsten används för att köra migreringar och fylla databasen.
- Förlängningsmetoden
Ersätt innehållet i Worker.cs-filen i SupportTicketApi.MigrationService-projektet med följande kod:
using System.Diagnostics; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using OpenTelemetry.Trace; using SupportTicketApi.Data.Contexts; using SupportTicketApi.Data.Models; namespace SupportTicketApi.MigrationService; public class Worker( IServiceProvider serviceProvider, IHostApplicationLifetime hostApplicationLifetime) : BackgroundService { public const string ActivitySourceName = "Migrations"; private static readonly ActivitySource s_activitySource = new(ActivitySourceName); protected override async Task ExecuteAsync(CancellationToken cancellationToken) { using var activity = s_activitySource.StartActivity("Migrating database", ActivityKind.Client); try { using var scope = serviceProvider.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<TicketContext>(); await EnsureDatabaseAsync(dbContext, cancellationToken); await RunMigrationAsync(dbContext, cancellationToken); await SeedDataAsync(dbContext, cancellationToken); } catch (Exception ex) { activity?.RecordException(ex); throw; } hostApplicationLifetime.StopApplication(); } private static async Task EnsureDatabaseAsync(TicketContext dbContext, CancellationToken cancellationToken) { var dbCreator = dbContext.GetService<IRelationalDatabaseCreator>(); var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { // Create the database if it does not exist. // Do this first so there is then a database to start a transaction against. if (!await dbCreator.ExistsAsync(cancellationToken)) { await dbCreator.CreateAsync(cancellationToken); } }); } private static async Task RunMigrationAsync(TicketContext dbContext, CancellationToken cancellationToken) { var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { // Run migration in a transaction to avoid partial migration if it fails. await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken); await dbContext.Database.MigrateAsync(cancellationToken); await transaction.CommitAsync(cancellationToken); }); } private static async Task SeedDataAsync(TicketContext dbContext, CancellationToken cancellationToken) { SupportTicket firstTicket = new() { Title = "Test Ticket", Description = "Default ticket, please ignore!", Completed = true }; var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { // Seed the database await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken); await dbContext.Tickets.AddAsync(firstTicket, cancellationToken); await dbContext.SaveChangesAsync(cancellationToken); await transaction.CommitAsync(cancellationToken); }); } }
I föregående kod:
- Metoden
ExecuteAsync
anropas när arbetaren startar. Den utför i sin tur följande steg:- Hämtar en referens till
TicketContext
-tjänsten från tjänstleverantören. - Anropar
EnsureDatabaseAsync
för att skapa databasen om den inte finns. - Anropar
RunMigrationAsync
för att tillämpa väntande migreringar. - Anropar
SeedDataAsync
för att seeda databasen med inledande data. - Stoppar arbetaren med
StopApplication
.
- Hämtar en referens till
- Metoderna
EnsureDatabaseAsync
,RunMigrationAsync
ochSeedDataAsync
kapslar alla in sina respektive databasåtgärder med hjälp av körningsstrategier för att hantera tillfälliga fel som kan uppstå när de interagerar med databasen. För att lära dig mer om exekveringsstrategier, se Anslutningsåterhämtning.
- Metoden
Lägg till migreringstjänsten i orkestreraren
Migreringstjänsten skapas, men den måste läggas till i .NET.NET Aspire appvärd så att den körs när appen startar.
Öppna filen SupportTicketApi.AppHost i Program.cs-projektet.
Lägg till följande markerade kod i metoden
ConfigureServices
:var builder = DistributedApplication.CreateBuilder(args); var sql = builder.AddSqlServer("sql") .AddDatabase("sqldata"); builder.AddProject<Projects.SupportTicketApi_Api>("api") .WithReference(sql); builder.AddProject<Projects.SupportTicketApi_MigrationService>("migrations") .WithReference(sql); builder.Build().Run();
Detta registrerar SupportTicketApi.MigrationService-projektet som en tjänst i .NET.NET Aspire-applikationsvärd.
Viktig
Om du använder Visual Studio, och du valde alternativet Enlist in Aspire orchestration när du skapade Worker Service projektet, läggs liknande kod till automatiskt med tjänstnamnet
supportticketapi-migrationservice
. Ersätt koden med föregående kod.
Ta bort den befintliga utsädeskoden
Eftersom migreringstjänsten använder databasen bör du ta bort den befintliga datasåddkoden från API-projektet.
Öppna filen SupportTicketApi.Api i Program.cs-projektet.
Ta bort markerade rader.
if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); using (var scope = app.Services.CreateScope()) { var context = scope.ServiceProvider.GetRequiredService<TicketContext>(); context.Database.EnsureCreated(); if(!context.Tickets.Any()) { context.Tickets.Add(new SupportTicket { Title = "Initial Ticket", Description = "Test ticket, please ignore." }); context.SaveChanges(); } } }
Testa migreringstjänsten
Nu när migreringstjänsten har konfigurerats kör du appen för att testa migreringarna.
Kör appen och observera instrumentpanelen SupportTicketApi.
Efter en kort väntan visas statusen för tjänsten
migrations
som Slutförd.Välj länken View i migreringstjänsten för att undersöka loggarna som visar DE SQL-kommandon som kördes.
Hämta koden
Du kan hitta den slutförda exempelappen på GitHub.
Mer exempelkod
Exempelappen Aspire Shop använder den här metoden för att tillämpa migreringar. Se AspireShop.CatalogDbManager
projektet för implementeringen av migreringstjänsten.
.NET Aspire