将 SignalR 用于 ABP Web 应用程序,源自 SignalR 中心的任何数据库操作实际上不会应用于数据库。 可以通过覆盖集线器的 OnConnectedAsync 虚拟并使用 UnitOfWork 实例以任何形式查询数据库来避免这种情况。 我怀疑这与 SignalR 在客户端和集线器之间保持持续的连接有关,并且该连接未关闭,从而阻止了数据库操作的应用。
问题:
我创建了一个 github 存储库来展示这一点。这只是实现了 SignalR 的基本 ABP.io BookStore 教程项目:
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
重现问题所需的步骤:
原本应该插入数据库的新书被返回到前端,但数据库实际上只是发生了变化,因为之前在 BookHub 的 OnConnectedAsync 中查询过一次图书数据库。如果没有初始查询,对数据库的更改将不会应用。
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);
}
}