我正在使用Blazor Server,但希望页面上的业务逻辑尽可能少,特别是可以 Select 创建REST端点,这些端点可以处理与我的Blazor Server应用程序相同的用例,因此我的UI中的加载和保存方法看起来非常类似:

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

MyEntityService中(它位于一个单独的类库中,因此我可以很容易地在future 的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作为解释on the Microsoft docs here,但这似乎是非常Blazor服务器特定的.我还希望在REST API中使用我的后端类库,在REST API中,仅使用生存期为Transient的上下文是绝对可以的.

推荐答案

因为Blazor Server不会 for each 请求创建作用域,所以您必须自己维护它.

public class MyUIHandler
{
    private readonly IServiceProvider _serviceProvider;

    public MyUIHandler(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    private async Task HandleValidSubmit()
    {
        if (_myDto != default)
        {
            using var scope = serviceProvider.CreateScope();
            var myEntityService = scope.ServiceProvider.GetRequiredService<IMyEntityService>();
            _myDto.Id = await myEntityService.Save(_myDto);
        }
    }
}

Csharp相关问答推荐

ASP.NET Core将SON重新序列化为派生类

使用C#中的Shape API从Azure目录获取所有用户

如何告诉自己创建的NuGet包在应用程序中发生了变化?

当通过Google的Gmail Api发送邮件时,签名会产生dkim = neutral(正文散列未验证)'

默认情况下,.NET通用主机(Host.CreateDefaultBuilder)中是否包含UseConsoleLifetime?

将现有字段映射到EFCore中的复杂类型

在命名管道上使用GRPC ASP.NET核心时如何配置命名管道权限

注册所有IMediatR类

如何在实体框架中添加包含列表?

使用预定义对象减少Task.Run/Factory.StartNew中的关闭开销

我如何让我的秒表保持运行场景而不重置

try 在.Net核心身份注册页面中使用AJAX,但没有成功..NET Core 5.0 Razor页面应用程序

从VS调试器而不是测试资源管理器运行的调试NUnitDotNet测试

GODOT 4向C#中的字符串参数发送信号以等待

使用System.Text.Json进行序列化时发生StackOverflow异常

为什么C#/MSBuild会自发地为不同的项目使用不同的输出路径?

使用未赋值的、传递的局部变量

如何在C#控制台应用程序中获取用户输入并将其作为订单项目进行处理?

删除MudRadio时,MudRadioGroup未 Select 正确的MudRadio

C#中的逻辑运算符用作单词';is';and';and';