Dela via


ASP.NET Core Blazor med Entity Framework Core (EF Core)

Anmärkning

Det här är inte den senaste versionen av den här artikeln. Den aktuella versionen finns i den .NET 9-versionen av den här artikeln.

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. Den aktuella versionen finns i den .NET 9-versionen av den här artikeln.

Viktig

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

Den aktuella versionen finns i den .NET 9-versionen av den här artikeln.

Den här artikeln beskriver hur du använder Entity Framework Core (EF Core) i Blazor appar på serversidan.

Blazor på serversidan är ett tillståndskänsligt appramverk. Appen upprätthåller en pågående anslutning till servern och användarens tillstånd lagras i serverns minne i en krets. Ett exempel på användartillstånd är data som lagras i beroendeinmatning (DI) tjänstinstanser som är begränsade till kretsen. Den unika programmodell som Blazor tillhandahåller kräver en särskild metod för att använda Entity Framework Core.

Anmärkning

Den här artikeln tar upp EF Core i Blazor appar på serversidan. Blazor WebAssembly appar körs i en WebAssembly-sandbox-miljö som förhindrar de flesta direkta databasanslutningar. Att köra EF Core i Blazor WebAssembly ligger utanför den här artikelns omfång.

Den här vägledningen gäller för komponenter som använder interaktiv återgivning på serversidan (interaktiv SSR) i en Blazor Web App.

Den här vägledningen gäller för Server projekt för en värdbaserad Blazor WebAssembly lösning eller en Blazor Server app.

Säkert autentiseringsflöde som krävs för produktionsappar

Den här artikeln gäller användningen av en lokal databas som inte kräver användarautentisering. Produktionsappar bör använda det säkraste tillgängliga autentiseringsflödet. Mer information om autentisering för distribuerade test- och produktionsappar Blazor finns i artiklarna i noden BlazorSäkerhet och Identity nod.

För Microsoft Azure-tjänster rekommenderar vi att du använder hanterade identiteter. Hanterade identiteter autentiserar säkert till Azure-tjänster utan att lagra autentiseringsuppgifter i appkod. Mer information finns i följande resurser:

Guida till att bygga en Blazor filmdatabasapp

En självstudiekurs om hur du skapar en app som använder EF Core för databasåtgärder finns i Skapa en Blazor filmdatabasapp (översikt). Handledningen visar hur du skapar en Blazor Web App som kan visa och hantera filmer i en filmdatabas.

Databasåtkomst

EF Core förlitar sig på en DbContext som ett sätt att konfigurera databasåtkomst och fungera som en arbetsenhet. EF Core tillhandahåller AddDbContext-tillägget för ASP.NET Core-appar som registrerar kontexten som en begränsad tjänst. I Blazor appar på serversidan kan begränsade tjänstregistreringar vara problematiska eftersom instansen delas mellan komponenter i användarens krets. DbContext är inte trådsäkert och är inte utformat för samtidig användning. De befintliga livslängderna är olämpliga av följande skäl:

  • Singleton delar tillstånd för alla användare av appen och leder till olämplig samtidig användning.
  • Scoped (standard) utgör ett liknande problem mellan komponenter för samma användare.
  • Tillfälliga resulterar i en ny instans per begäran. men eftersom komponenter kan vara långlivade resulterar detta i en kontext med längre livslängd än vad som kan vara avsett.

Följande rekommendationer är utformade för att ge en konsekvent metod för att använda EF Core i Blazor appar på serversidan.

  • Överväg att använda en kontext per åtgärd. Kontexten är utformad för snabb instansiering med låg belastning.

    using var context = new ProductsDatabaseContext();
    
    return await context.Products.ToListAsync();
    
  • Använd en flagga för att förhindra flera samtidiga åtgärder:

    if (Loading)
    {
        return;
    }
    
    try
    {
        Loading = true;
    
        ...
    }
    finally
    {
        Loading = false;
    }
    

    Placera databasåtgärder efter raden Loading = true; i blocket try.

    Trådsäkerhet är inte ett problem, så inläsningslogik kräver inte låsning av databasposter. Inläsningslogik används för att inaktivera användargränssnittskontroller så att användarna inte oavsiktligt väljer knappar eller uppdaterar fält när data hämtas.

  • Om det finns en risk att flera trådar får åtkomst till samma kodblock, injicera en fabrik och skapa en ny instans per åtgärd. Annars räcker det vanligtvis att mata in och använda kontexten.

  • För åtgärder med längre livslängd som utnyttjar EF Coreändringsspårning eller samtidighetskontrollomfångskontexten till komponentens livslängd.

Nya DbContext instanser

Det snabbaste sättet att skapa en ny DbContext instans är att använda new för att skapa en ny instans. Det finns dock scenarier som kräver att ytterligare beroenden löses.

Varning

Lagra inte apphemligheter, anslutningssträngar, autentiseringsuppgifter, lösenord, personliga identifieringsnummer (PIN),privat C#/.NET-kod eller privata nycklar/token i kod på klientsidan, vilket är alltid osäker. I test-/mellanlagrings- och produktionsmiljöer bör Blazor kod på serversidan och webb-API:er använda säkra autentiseringsflöden som undviker att underhålla autentiseringsuppgifter i projektkod eller konfigurationsfiler. Förutom testning av lokal utveckling rekommenderar vi att du undviker användning av miljövariabler för att lagra känsliga data, eftersom miljövariabler inte är den säkraste metoden. För testning av lokal utveckling rekommenderas verktyget Secret Manager för att skydda känsliga data. Mer information finns i På ett säkert sätt underhålla känsliga data och autentiseringsuppgifter.

Den rekommenderade metoden för att skapa en ny DbContext med beroenden är att använda en fabrik. EF Core 5.0 eller senare erbjuder en inbyggd fabrik för att skapa nya kontexter.

I versioner av .NET före 5.0 använder du följande DbContextFactory:

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorServerDbContextExample.Data
{
    public class DbContextFactory<TContext> 
        : IDbContextFactory<TContext> where TContext : DbContext
    {
        private readonly IServiceProvider provider;

        public DbContextFactory(IServiceProvider provider)
        {
            this.provider = provider ?? throw new ArgumentNullException(
                $"{nameof(provider)}: You must configure an instance of " +
                "IServiceProvider");
        }

        public TContext CreateDbContext() => 
            ActivatorUtilities.CreateInstance<TContext>(provider);
    }
}

I föregående fabrik:

I följande exempel konfigureras SQLite- och aktiverar dataloggning i en app som hanterar kontakter. Koden använder en tilläggsmetod (AddDbContextFactory) för att konfigurera databasfabriken för DI och ange standardalternativ:

builder.Services.AddDbContextFactory<ContactContext>(opt =>
    opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db"));
services.AddDbContextFactory<ContactContext>(opt =>
    opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db"));

Fabriken matas in i komponenter för att skapa nya DbContext instanser.

Ange en databaskontext för en komponentmetod

Fabriken injiceras i komponenten:

@inject IDbContextFactory<ContactContext> DbFactory

Skapa en DbContext för en metod med hjälp av fabriken (DbFactory):

private async Task DeleteContactAsync()
{
    using var context = DbFactory.CreateDbContext();

    if (context.Contacts is not null)
    {
        var contact = await context.Contacts.FirstAsync(...);

        if (contact is not null)
        {
            context.Contacts?.Remove(contact);
            await context.SaveChangesAsync();
        }
    }
}

Begränsa en databaskontext till komponentens livslängd

Du kanske vill skapa en DbContext som finns under en komponents livslängd. På så sätt kan du använda den som en arbetsenhet och dra nytta av inbyggda funktioner, till exempel ändringsspårning och samtidighetsmatchning.

Implementera IDisposable och mata in fabriken i komponenten:

@implements IDisposable
@inject IDbContextFactory<ContactContext> DbFactory

Upprätta en egenskap för DbContext:

private ContactContext? Context { get; set; }

OnInitializedAsync skrivs över för att skapa DbContext:

protected override async Task OnInitializedAsync()
{
    Context = DbFactory.CreateDbContext();
}

DbContext tas bort när komponenten tas bort:

public void Dispose() => Context?.Dispose();

Aktivera loggning av känsliga data

EnableSensitiveDataLogging innehåller programdata i undantagsmeddelanden och ramverksloggning. De loggade data kan innehålla värden som tilldelats egenskaper för entitetsinstanser och parametervärden för kommandon som skickas till databasen. Loggning av data med EnableSensitiveDataLogging är en säkerhetsriskeftersom det kan exponera lösenord och andra personligt identifierbar information (PII) när SQL-instruktioner som körs mot databasen loggas.

Vi rekommenderar att du bara aktiverar EnableSensitiveDataLogging för utveckling och testning:

#if DEBUG
    services.AddDbContextFactory<ContactContext>(opt =>
        opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")
        .EnableSensitiveDataLogging());
#else
    services.AddDbContextFactory<ContactContext>(opt =>
        opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db"));
#endif

Ytterligare resurser