Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Eftersom 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 Aspire projekt för att köra EF Core migreringar vid appstart.
Prerequisites
För att arbeta med Aspirebehöver du följande installerat lokalt:
-
.NET 8.0 eller .NET 9.0.
- Från och med Aspire 9.4 .NET stöds 10 Förhandsversion 5 eller senare .
- 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 Aspire plugin (valfritt)
För mer information, se Aspire konfiguration och verktyg och Aspire SDK.
Hämta startappen
I denna handledning används en exempelapp som visar hur du tillämpar EF Core migreringar i 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.AppHost: Innehåller Aspire AppHost och konfigurationen.
- SupportTicketApi.Data: Innehåller EF Core kontexter och modeller.
- 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. Vänta i Aspire Dashboard tills alla resurser körs och är felfria. Välj sedan https Swagger-slutpunkten och testa API:ets GET /api/SupportTickets slutpunkt genom att expandera åtgärden och välja Prova. Välj Kör för att skicka begäran och visa svaret:
[
{
"id": 1,
"title": "Initial Ticket",
"description": "Test ticket, please ignore."
}
]
Stäng webbläsarflikarna som visar Swagger-slutpunkten och Aspire instrumentpanelen och sluta sedan felsöka.
Skapa migreringar
Börja med att skapa några migreringar att tillämpa.
Öppna en terminal (Ctrl+` i Visual Studio).
Ange SupportTicketApi\SupportTicketApi.Api som aktuell katalog.
Använd kommandoradsverktyget
dotnet efför att skapa en ny migrering för att avbilda databasschemats ursprungliga tillstånd:dotnet ef migrations add InitialCreate --project ..\SupportTicketApi.Data\SupportTicketApi.Data.csprojKommandot för att fortsätta är:
- Kör kommandoradsverktyget för EF Core-migrering i katalogen SupportTicketApi.Api.
dotnet efkö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.Data\Models\SupportTicket.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 genomföra. Sedan skapar du en migreringstjänst som tillämpar dessa migreringar under appstarten.
Felsöka migreringsproblem
När du arbetar med EF Core migreringar i Aspire projekt kan det uppstå några vanliga problem. Här är lösningar på de vanligaste problemen:
Felet "Ingen databasprovider har konfigurerats"
Om du får ett felmeddelande som "Ingen databasprovider har konfigurerats för denna DbContext" när du kör migreringskommandon beror det på att EF-verktygen inte kan hitta en anslutningssträng eller databasproviderkonfiguration. Detta beror på att Aspire projekt använder tjänsteupptäckt och orkestrering som endast är tillgängligt under körning.
Lösning: Lägg tillfälligt till en anslutningssträng i projektets appsettings.json fil:
Öppna eller skapa en
appsettings.jsonfil i DITT API-projekt (där DbContext är registrerad).Lägg till en anslutningssträng med samma namn som används i din Aspire AppHost:
{ "ConnectionStrings": { "ticketdb": "Server=(localdb)\\mssqllocaldb;Database=TicketDb;Trusted_Connection=true" } }Kör dina migreringskommandon som vanligt.
Ta bort anslutningssträngen från
appsettings.jsonnär du är klar, vilket Aspire ger den vid körning.
Tip
Anslutningssträngens namn måste matcha det du använder i din AppHost. Om du till exempel använder builder.AddProject<Projects.SupportTicketApi_Api>().WithReference(sqlServer.AddDatabase("ticketdb"))använder du "ticketdb" som anslutningssträngsnamn.
Flera databaser i en lösning
När lösningen Aspire har flera tjänster med olika databaser skapar du migreringar för varje databas separat:
Navigera till varje tjänstprojektkatalog som har en DbContext.
Kör migreringskommandon med lämplig projektreferens:
# For the first service/database dotnet ef migrations add InitialCreate --project ..\FirstService.Data\FirstService.Data.csproj # For the second service/database dotnet ef migrations add InitialCreate --project ..\SecondService.Data\SecondService.Data.csprojSkapa separata migreringstjänster för varje databas eller hantera flera DbContexts i en enda migreringstjänst.
Konfiguration av startprojekt
Kontrollera att du kör migreringskommandon från rätt projekt:
- CLI: Navigera till projektkatalogen som innehåller DbContext-registreringen (vanligtvis ditt API-projekt)
- Package Manager-konsolen: Ställ in startprojektet på det som konfigurerar DbContext och standardprojektet där migreringar ska skapas
Skapa migreringstjänsten
Om du vill köra migreringar anropar du EF CoreMigrate metoden eller MigrateAsync metoden. I den här självstudien skapar du en separat arbetstjänst för att tillämpa migreringar. Den här metoden separerar migreringsproblem i ett dedikerat projekt, vilket är enklare att underhålla och gör att migreringar kan köras innan andra tjänster startas.
Note
Var du skapar migreringar: Migreringar ska skapas i projektet som innehåller dina Entity Framework DbContext- och modellklasser (i det här exemplet SupportTicketApi.Data). Migreringstjänstprojektet refererar till det här dataprojektet för att tillämpa migreringarna vid start.
Så här skapar du 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, namnge projektet SupportTicketApi.MigrationService och mål .NET 9.0. Om du använder kommandoraden använder du följande kommandon från lösningskatalogen:
dotnet new worker -n SupportTicketApi.MigrationService -f "net9.0" dotnet sln add SupportTicketApi.MigrationServiceLä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.ServiceDefaultsLägg till 📦Aspire. Microsoft.EntityFrameworkCore.SqlServer NuGet-paketreferens till SupportTicketApi.MigrationService-projektet med hjälp av Visual Studio eller kommandoraden:
cd SupportTicketApi.MigrationService dotnet add package Aspire.Microsoft.EntityFrameworkCore.SqlServer -v "9.4.0"Tip
I vissa fall kan du också behöva lägga 📦 till paketet Microsoft.EntityFrameworkCore.Tools för att förhindra EF Core att tyst misslyckas utan att använda migreringar. Detta är särskilt relevant när du använder andra databaser än SQL Server, till exempel PostgreSQL. Mer information finns i dotnet/efcore#27215.
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
AddServiceDefaultslägger till standardfunktioner för tjänster. -
AddOpenTelemetry-tilläggsmetoden konfigurerar OpenTelemetry funktionalitet. - Metoden
AddSqlServerDbContextadderarTicketContext-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 RunMigrationAsync(dbContext, cancellationToken); await SeedDataAsync(dbContext, cancellationToken); } catch (Exception ex) { activity?.AddException(ex); throw; } hostApplicationLifetime.StopApplication(); } 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 dbContext.Database.MigrateAsync(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
ExecuteAsyncanropas 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. - Kallar på
RunMigrationAsyncför att tillämpa väntande migreringar. - Anropar
SeedDataAsyncför att seeda databasen med inledande data. - Stoppar arbetaren med
StopApplication.
- Hämtar en referens till
- Metoderna
RunMigrationAsyncochSeedDataAsyncinkapslar sina respektive databasåtgärder med strategier 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 Aspire AppHost så att den körs när appen startar.
Öppna filen SupportTicketApi.AppHost i AppHost.cs-projektet.
Lägg till följande markerade kod:
var builder = DistributedApplication.CreateBuilder(args); var sql = builder.AddSqlServer("sql", port: 14329) .WithEndpoint(name: "sqlEndpoint", targetPort: 14330) .AddDatabase("sqldata"); var migrations = builder.AddProject<Projects.SupportTicketApi_MigrationService>("migrations") .WithReference(sql) .WaitFor(sql); builder.AddProject<Projects.SupportTicketApi_Api>("api") .WithReference(sql) .WithReference(migrations) .WaitForCompletion(migrations); builder.Build().Run();Den här koden registrerar SupportTicketApi.MigrationService projektet som en tjänst i Aspire AppHost. Det säkerställer också att API-resursen inte körs förrän migreringarna har slutförts.
Note
I föregående kod lägger anropet till en representation av en AddDatabase-databas till SQL Server-applikationsmodellen med en anslutningssträng. Den skapar ingen databas i containern SQL Server . För att säkerställa att databasen skapas, anropar exempelprojektet metoden EF CoreEnsureCreated från SUPPORT-API:ets Program.cs-fil.
Tip
Koden skapar containern varje gång den SQL Server körs och tillämpar migreringar på den. Data sparas inte mellan felsökningssessioner och eventuella nya databasrader som du skapar under testningen kommer inte att överleva en omstart av appen. Om du vill spara dessa data lägger du till en datavolym i containern. Mer information finns i Lägga till SQL Server resurs med datavolym.
Om koden inte kan matcha migreringstjänstprojektet lägger du till en referens till migreringstjänstprojektet i AppHost-projektet:
dotnet add SupportTicketApi.AppHost reference SupportTicketApi.MigrationServiceImportant
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.
Scenario med flera databaser
Om lösningen Aspire använder flera databaser har du två alternativ för att hantera migreringar:
Alternativ 1: Separata migreringstjänster (rekommenderas)
Skapa en dedikerad migreringstjänst för varje databas. Den här metoden ger bättre isolering och gör det enklare att hantera olika databasscheman oberoende av varandra.
Skapa separata migreringstjänstprojekt för varje databas:
dotnet new worker -n FirstService.MigrationService -f "net8.0" dotnet new worker -n SecondService.MigrationService -f "net8.0"Konfigurera varje migreringstjänst för att hantera dess specifika databaskontext.
Lägg till båda migreringstjänsterna i din AppHost:
var firstDb = sqlServer.AddDatabase("firstdb"); var secondDb = postgres.AddDatabase("seconddb"); var firstMigrations = builder.AddProject<Projects.FirstService_MigrationService>() .WithReference(firstDb); var secondMigrations = builder.AddProject<Projects.SecondService_MigrationService>() .WithReference(secondDb); // Ensure services wait for their respective migrations builder.AddProject<Projects.FirstService_Api>() .WithReference(firstDb) .WaitFor(firstMigrations); builder.AddProject<Projects.SecondService_Api>() .WithReference(secondDb) .WaitFor(secondMigrations);
Alternativ 2: Enskild migreringstjänst med flera kontexter
Du kan också skapa en migreringstjänst som hanterar flera databaskontexter:
Lägg till referenser till alla dataprojekt i migreringstjänsten.
Registrera alla DbContexts i migreringstjänstens
Program.cs.Ändra
Worker.csför att tillämpa migreringar på varje kontext:public async Task<bool> RunMigrationAsync(IServiceProvider serviceProvider) { await using var scope = serviceProvider.CreateAsyncScope(); var firstContext = scope.ServiceProvider.GetRequiredService<FirstDbContext>(); var secondContext = scope.ServiceProvider.GetRequiredService<SecondDbContext>(); await firstContext.Database.MigrateAsync(); await secondContext.Database.MigrateAsync(); return true; }
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
migrationssom Slutförd.Välj ikonen Console logs 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.