一、问题背景描述:
我有一个需求,需要在字典服务里创建字典类型成功后执行ILocalEventBus.PublishAsync 发布一个事件,让主业务服务订阅这个事件,然后执行业务代码将字典类型同步给所有租户。
最开始我在字典服务员的applicationService层写了事件发布代码如下:
[Authorize(DataDictionaryManagementPermissions.DataDictionaryManagement.Create)]
public async Task CreateAsync(CreateDataDictionaryInput input)
{
var retentity=await _dataDictionaryManager.CreateAsync(input.TenantId, input.Code, input.DisplayText, input.Description);
var dicid = retentity.Id.ToString();
input.IsSyncToTenant = true;
if (input.IsSyncToTenant)
{
await PublishDataDicSyncToTenant(dicid);
}
}
private async Task PublishDataDicSyncToTenant(string id)
{
await _distributedEventBus.PublishAsync
(new PublishDataDicSyncToTenant
{
DataDicId = id,
});
Logger.LogInformation($"已发送DataDic消息:{id}");
//await Task.CompletedTask;
}
以上代码无论我怎么改,都无法实现数据保存后发布事件,直到订阅事件的业务代码执行完毕都没有看到数据行在字典类型表里增加过。
二、解决过程说明:
1、强行结束事物CurrentUnitOfWork.CompleteAsync
最后在技术群内大佬指点下, 在CreateAsync行下面加上await UnitOfWorkManager.Current.SaveChangesAsync();
没看到预期效果,然后我又加上await UnitOfWorkManager.Current.CompleteAsync();
看到了数据行在执行完这一行代码之后就进入了表。 然后他们说其实只需要
await UnitOfWorkManager.Current.CompleteAsync();
这一行就可以了,还可以写成下面这样
await CurrentUnitOfWork.CompleteAsync();
执行效果图如下:
2、建立新的局部事物
说明:虽然上面一步解决了发布事件之前,数据入库问题。但是执行后面的业务代码,访问数据库时,会造成新的问题 complete is called before。如下图:
然后我就干脆在创建数据这个方法上用一个新的局部事物来提交。
注意:abpvext对工作单元做了自己的封装,所以局部事物的创建代码跟原始 UnitOfWorkManager的写法有点不一样。
using (var unitOfWork = UnitOfWorkManager.Begin(true,true))
{
retentity = await _dataDictionaryManager.CreateAsync(input.TenantId, input.Code, input.DisplayText, input.Description);
await unitOfWork.CompleteAsync();
}