Поделиться через


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

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 9 этой статьи.

В этой статье объясняется, как использовать Entity Framework Core (EF Core) в серверных приложениях Blazor .

Серверная часть Blazor — это платформа приложений с отслеживанием состояния. Приложение поддерживает постоянное подключение к серверу, а состояние пользователя хранится в памяти сервера в канале. Примером состояния пользователя являются данные, хранящиеся во внедрениях зависимостей (DI) экземпляров службы, областью действия которых является канал. Для уникальной модели приложения, которую предоставляет Blazor, требуется специальный подход к использованию Entity Framework Core.

Примечание.

В этой статье рассматриваются EF Core серверные Blazor приложения. Приложения Blazor WebAssembly выполняются в песочнице WebAssembly, которая запрещает большинство прямых подключений к базе данных. Выполнение EF Core выходит Blazor WebAssembly за рамки этой статьи.

Это руководство относится к компонентам, которые применяют интерактивную отрисовку на стороне сервера (интерактивный SSR) в объекте Blazor Web App.

Это руководство относится к Server проекту размещенного Blazor WebAssembly решения или Blazor Server приложения.

Безопасный поток проверки подлинности, необходимый для рабочих приложений

Эта статья относится к использованию локальной базы данных, которая не требует проверки подлинности пользователя. Рабочие приложения должны использовать самый безопасный поток проверки подлинности. Дополнительные сведения о проверке подлинности для развернутых тестовых и рабочих Blazor приложений см. в статьях о Blazorбезопасности и Identity узле.

Для служб Microsoft Azure рекомендуется использовать управляемые удостоверения. Управляемые удостоверения безопасно проходят проверку подлинности в службах Azure без хранения учетных данных в коде приложения. Дополнительные сведения см. на следующих ресурсах:

Руководство по созданию Blazor приложения базы данных фильма

Для получения опыта по созданию приложения, использующего EF Core для операций с базами данных, см. статью создание приложения кино базы данных Blazor (Обзор). В этом руководстве показано, как создать Blazor Web App фильмы и управлять ими в базе данных фильмов.

Доступ к базе данных

EF Core используется в DbContext качестве средства для настройки доступа к базе данных и действия в качестве единицы работы. EF Core AddDbContext предоставляет расширение для приложений ASP.NET Core, которые регистрируют контекст в качестве службы с областью действия. В серверных Blazor приложениях регистрация служб с областью действия может быть проблематичной, так как экземпляр предоставляется совместно между компонентами в канале пользователя. DbContext не является потокобезопасным и не предназначен для одновременного использования. Существующие времена существования не подходят по следующим причинам.

  • Отдельная. Состояние используется всеми пользователями приложения, что приводит к неприемлемому одновременному использованию.
  • С заданной областью (по умолчанию). Приводит к той же проблеме для компонентов одного и того же пользователя.
  • Временная. В каждом запросе создается новый экземпляр, но, поскольку компоненты могут быть длительного времени существования, это приводит к более долгоживущему контексту, чем предполагалось.

Следующие рекомендации предназначены для обеспечения согласованного подхода к использованию EF Core в серверных приложениях Blazor .

  • Рассмотрите возможность использования одного контекста для каждой операции. Контекст предназначен для быстрого создания экземпляров с низкими накладными расходами.

    using var context = new ProductsDatabaseContext();
    
    return await context.Products.ToListAsync();
    
  • Используйте флаг для предотвращения нескольких одновременных операций.

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

    Поместите операции базы данных после строки Loading = true; в блоке try.

    Безопасность потоков не является проблемой, поэтому логика загрузки не требует блокировки записей базы данных. С помощью логики загрузки можно отключить элементы управления пользовательским интерфейсом, чтобы пользователи не могли случайно нажать на кнопки или обновить поля во время получения данных.

  • Если существует вероятность, что к одному блоку кода обращается несколько потоков, внедрите производство и создайте новый экземпляр для каждой операции. В противном случае обычно достаточно внедрения и использования контекста.

  • Для более длительных операций, использующих управление EF Coreотслеживанием изменений или параллелизмом, примените контекст к времени существования компонента.

Новые экземпляры DbContext

Самый быстрый способ создать новый экземпляр DbContext — использовать new. Однако существуют сценарии, в которых может потребоваться разрешение дополнительных зависимостей.

Предупреждение

Не сохраняйте секреты приложений, строка подключения, учетные данные, пароли, персональные идентификационные номера (ПИН-коды), частный код C#/.NET или закрытые ключи и токены в клиентском коде, который всегда небезопасн. В средах тестирования и промежуточной и рабочей среды код на стороне Blazor сервера и веб-API должны использовать безопасные потоки проверки подлинности, которые не поддерживают учетные данные в файлах кода проекта или конфигурации. Вне локального тестирования разработки рекомендуется избегать использования переменных среды для хранения конфиденциальных данных, так как переменные среды не являются наиболее безопасным подходом. Для локального тестирования разработки средство Secret Manager рекомендуется для защиты конфиденциальных данных. Дополнительные сведения см. в разделе "Безопасное обслуживание конфиденциальных данных и учетных данных".

Рекомендуемым подходом для создания нового экземпляра DbContext с зависимостями является использование фабрики. EF Core 5.0 или более поздней версии предоставляет встроенную фабрику для создания новых контекстов.

В версиях .NET до 5.0 используйте следующие 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);
    }
}

В предыдущей фабрике:

  • ActivatorUtilities.CreateInstance удовлетворяет все зависимости через поставщика услуг;
  • IDbContextFactory<TContext> доступен в EF Core ASP.NET Core 5.0 или более поздней версии, поэтому предыдущий интерфейс необходим только для ASP.NET Core 3.x.

В следующем примере настраивается SQLite и включается ведение журнала данных в приложении, которое управляет контактами. Код использует метод расширения (AddDbContextFactory) для настройки фабрики баз данных для DI и предоставления параметров по умолчанию:

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"));

Фабрика интегрируется в компоненты для создания новых экземпляров DbContext.

Установите область контекста базы данных для метода компонента

Фабрика интегрируется в компонент.

@inject IDbContextFactory<ContactContext> DbFactory

Создайте DbContext для метода, используя фабрику (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();
        }
    }
}

Ограничьте контекст базы данных до времени существования компонента

Может потребоваться создать экземпляр DbContext, который будет существовать в течение времени существования компонента. Это позволяет использовать его как единицу работы и пользоваться преимуществами встроенных функций, таких как отслеживание изменений и разрешение параллелизма.

Реализуйте IDisposable и внедрите фабрику в компонент.

@implements IDisposable
@inject IDbContextFactory<ContactContext> DbFactory

Установите свойство для DbContext:

private ContactContext? Context { get; set; }

OnInitializedAsync переопределяется, чтобы создать DbContext:

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

DbContext удаляется при удалении компонента:

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

Включение ведения журнала для конфиденциальных данных

EnableSensitiveDataLogging позволяет включить данные приложения в сообщения об исключениях и журналы платформы. Записанные в журнал данные могут содержать значения, присвоенные свойствам экземпляров сущностей, и значения параметров для команд, отправляемых в базу данных. Данные ведения журнала с EnableSensitiveDataLogging помощью риска безопасности, так как они могут предоставлять пароли и другие персональные данные (PII) при журнале инструкций SQL, выполняемых в базе данных.

Мы рекомендуем включать метод EnableSensitiveDataLogging только на этапах разработки и тестирования.

#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

Дополнительные ресурсы