在 Blazor 服务器中处理 EFCore 生命周期,其中后端也用于 REST API

问题描述 投票:0回答:1

我正在使用 Blazor Server,但希望页面上的业务逻辑尽可能少,特别是可以选择创建可以处理与我的 Blazor Server 应用程序相同的用例的 REST 端点,因此我的加载和保存方法我的用户界面看起来很像那样:

private async Task HandleValidSubmit()
{
    if (_myDto != default)
    {
        _myDto.Id = await MyEntityService.Save(_myDto);
    }
}

MyEntityService
(位于单独的类库中,因此我可以在将来的 REST API 中轻松使用它),然后通过 DI 注入
MyContext

public class MyEntityService : IMyEntityService
{
    private readonly ILogger<MyEntityService> _logger;
    private readonly IMyContext _context;

    public MyEntityService(ILogger<MyEntityService> logger, IMyContext context)
    {
        _logger = logger;
        _context = context;
    }

    public async Task<int> Save(DtoMyEntity dtoToSave)
    {
        _logger.LogTrace("{method}({dtoToSave})", nameof(Save), dtoToSave);
        //Some magic to convert my DTO to an EF Core entity
        await _context.SaveChangesAsync().ConfigureAwait(false);
        return entity.Id;
    }

}

这是我的数据库上下文的 DI 配置:

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddDatabase(this IServiceCollection services)
        => services
            .AddDbContext<IMyContext, MyContext>((provider, options) =>
            {
                options.UseNpgsql(provider.GetRequiredService<IDbConnectionStringHelper>()
                    .GetDbConnectionString("ServiceDatabase"));
                var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
                if (environment == "Development")
                {
                    options.EnableSensitiveDataLogging();
                }
                options.EnableDetailedErrors();
            }, ServiceLifetime.Transient, ServiceLifetime.Transient)
            .AddTransient<IDbConnectionStringHelper, DbConnectionStringHelper>()
    ;
}

当我现在单击

Save
两次而不重新加载页面/转到另一个页面并返回时,我收到以下错误:

The instance of entity type 'MyEntity' cannot be tracked because another instance with the key value '{Id: 1}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

如何解决这个问题?我知道我应该使用

IDbContextFactory
,如 在此处的 Microsoft 文档 上所解释的那样,但这似乎非常特定于 Blazor 服务器。我还希望我的后端类库在 REST API 中使用,其中仅使用具有
Transient
生命周期的上下文绝对没问题。

c# .net-core dependency-injection entity-framework-core blazor-server-side
1个回答
2
投票

由于 Blazor Server 不会为每个请求创建作用域,因此您必须自行维护。

public class MyUIHandler
{
    private readonly IServiceScopeFactory _scopeFactory;

    public MyUIHandler(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    private async Task HandleValidSubmit()
    {
        if (_myDto != default)
        {
            using var scope = _scopeFactory.CreateScope();
            var myEntityService = scope.ServiceProvider.GetRequiredService<IMyEntityService>();
            _myDto.Id = await myEntityService.Save(_myDto);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.