(ABP/SignalR) 未从 SignalR Hub 应用数据库操作

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

将 SignalR 用于 ABP Web 应用程序,源自 SignalR 中心的任何数据库操作实际上不会应用于数据库。 可以通过覆盖集线器的 OnConnectedAsync 虚拟并使用 UnitOfWork 实例以任何形式查询数据库来避免这种情况。 我怀疑这与 SignalR 在客户端和集线器之间保持持续的连接有关,并且该连接未关闭,从而阻止了数据库操作的应用。

问题:

  1. 这种行为是预期的/正常的/应该是这样的吗?
  2. 是否有更优雅(或者根本优雅:))的方法从 SignalR 中心调用 RESTful API 并应用数据库操作?

我创建了一个 github 存储库来展示这一点。这只是实现了 SignalR 的基本 ABP.io BookStore 教程项目:

Acme.书店

public class BookHub : AbpHub<IBookHub>
{
    public async override Task OnConnectedAsync()
    {
        IUnitOfWorkManager uowm = LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();

        using (IUnitOfWork uow = uowm.Begin())
        {
            IRepository<Book, Guid> bookRepository = uow.ServiceProvider.GetRequiredService<IRepository<Book, Guid>>();
            if (await bookRepository.AnyAsync() == false)
            {
                throw new EntityNotFoundException(typeof(Book));
            }
        }
        await base.OnConnectedAsync();
    }

    [HubMethodName("CreateOrUpdateBook")]
    public async Task CreateOrUpdateBookAsync(CreateUpdateBookDto createDto, Guid? id)
    {
        IBookAppService bookAppService = LazyServiceProvider.LazyGetRequiredService<IBookAppService>();
        BookDto bookDto = id.HasValue ? await bookAppService.UpdateAsync((Guid)id!, createDto) : await bookAppService.CreateAsync(createDto);
        await Clients.All.BookUpdated(bookDto);
    }
}

ABP框架版本:8.0.1

数据库提供商:EF Core

重现问题所需的步骤:

  1. (运行DbMigrator创建数据库并初始迁移)
  2. 打开图书视图(书店 -> 图书)
  3. 新书
  4. 填写表格
  5. 保存

原本应该插入数据库的新书被返回到前端,但数据库实际上只是发生了变化,因为之前在 BookHub 的 OnConnectedAsync 中查询过一次图书数据库。如果没有初始查询,对数据库的更改将不会应用。

signalr abp
1个回答
0
投票

abp github 上的一位热心用户“realLiangshiwei”提供了一个解决方案。 https://github.com/abpframework/abp/issues/18793#issuecomment-1906049286

public class AbpUnitOfWorkHubFilter :  IHubFilter
{
    public virtual async ValueTask<object?> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object?>> next)
    {
        var unitOfWorkManager = invocationContext.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
        using (var uow = unitOfWorkManager.Reserve(UnitOfWork.UnitOfWorkReservationName, requiresNew:true))
        {
            var result = await next(invocationContext);
            await uow.CompleteAsync();

            return result;
        }
    }
}

Configure<HubOptions>(options =>
{
    options.AddFilter<AbpUnitOfWorkHubFilter>();
});



public class BookHub : AbpHub<IBookHub>
{
    [HubMethodName("CreateOrUpdateBook")]
    public virtual async Task CreateOrUpdateBookAsync(CreateUpdateBookDto createDto, Guid? id)
    {
        IBookAppService bookAppService = LazyServiceProvider.LazyGetRequiredService<IBookAppService>();
        BookDto bookDto = id.HasValue ? await bookAppService.UpdateAsync((Guid)id!, createDto) : await bookAppService.CreateAsync(createDto);
        await Clients.All.BookUpdated(bookDto);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.