在不返回结果的情况下在其他方法中调用多个异步方法
Calling multiple async methods within other method without returning result
我正在使用 Dapper
开发 ASP.NET Core 2.2
应用程序。几乎所有方法都遵循 async/await
模式 return 结果是某种 Task
。
由于我们在 Dapper
中遇到的问题(我没有亲自调查过,这部分代码我按原样使用)但基本上可以归结为这样一个事实,如果你想在 Transaction
多个异步方法中执行,这些方法在内部调用其他异步方法,并且您可能以这种方式嵌套多个级别,您需要将所有这些方法调用包装在一个将在事务中执行的方法中。
处理方法如下:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(
Delegate function,
params object[] parameters)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await ((Task<TOut>)function.DynamicInvoke(parameters))
.ConfigureAwait(false);
scope.Complete();
return result;
}
}
所以我有一个非常复杂的实体,它通过调用 Save
到许多较小的实体来保存。这部分代码运行正常,如下所示:
public async SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await SaveInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
SaveInTransaction
方法如下所示:
private async Task<dynamic> SaveInTransaction(dynamic dto)
{
var entityId = await nameService.Add(dto.Name);
await addressService.Add(dto.Address);
await ageService.Add(dto.Age);
return entityId;
}
所以这是简化的,但实际上我在这里调用了多个服务,它们调用了多个存储库,这工作正常。
问题 我遇到的问题是在事务中更新同一实体。显示 Save
逻辑的全部目的是在最后指出,因为我有这个 return entityId;
我能够毫无问题地将所有东西链接在一起。但是,就像现在一样,默认情况下我们的 Update
方法没有 returning 任何东西,这就是我无法弄清楚如何实现 Update
逻辑的地方。
目前我有这个:
public async Task UpdateEntireEntity(UpdateEntityDTO, entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await UpdateInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
而 UpdateInTransaction
看起来像这样:
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
这似乎至少基于我所做的几次测试,但我真的不喜欢这部分:
return await Task.FromResult<dynamic>(null);
对我来说,这似乎是一个丑陋的 hack。 Update
方法被认为不会 return 任何值,这太人为了。
甚至最糟糕的是,我不知道如何在不需要 return 的情况下实现更新方法。
我试过的一件事是将 UpdateInTransaction
的声明更改为
private async Task UpdateInTransaction(dynamic dto)
当我调用该方法时,我将其更改为:
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task>( async dto => await UpdateInTransaction(dto)..
但是我遇到了以下异常:
AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,
<fully-qualified- name>.<<UpdateEntireEntity>b__0>d] to type
'System.Threading.Tasks.Task
1[System.Threading.Tasks.Task]'
。
所以基本上就是这样。很抱歉 post。我真的很感激一些解释得很好的答案。
你可以改变
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
到
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return null;
}
我会避免使用 Delegate
因为它不是输入的:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(Func<Task<TOut>> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await (function()).ConfigureAwait(false);
scope.Complete();
return result;
}
}
此签名意味着您需要捕获参数而不是传递它们:
public async Task<dynamic> SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync(
async () => await SaveInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
一旦您在方法签名中使用强类型 Func<Task<T>>
而不是 Delegate
,您就可以像这样为 ExecuteInTransactionAsync
创建重载:
public async Task ExecuteInTransactionAsync(Func<Task> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
await (function()).ConfigureAwait(false);
scope.Complete();
}
}
可以这样使用:
public async Task UpdateEntireEntity(UpdateEntityDTO entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync(
async () => await UpdateInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
private async Task UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
}
我正在使用 Dapper
开发 ASP.NET Core 2.2
应用程序。几乎所有方法都遵循 async/await
模式 return 结果是某种 Task
。
由于我们在 Dapper
中遇到的问题(我没有亲自调查过,这部分代码我按原样使用)但基本上可以归结为这样一个事实,如果你想在 Transaction
多个异步方法中执行,这些方法在内部调用其他异步方法,并且您可能以这种方式嵌套多个级别,您需要将所有这些方法调用包装在一个将在事务中执行的方法中。
处理方法如下:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(
Delegate function,
params object[] parameters)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await ((Task<TOut>)function.DynamicInvoke(parameters))
.ConfigureAwait(false);
scope.Complete();
return result;
}
}
所以我有一个非常复杂的实体,它通过调用 Save
到许多较小的实体来保存。这部分代码运行正常,如下所示:
public async SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await SaveInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
SaveInTransaction
方法如下所示:
private async Task<dynamic> SaveInTransaction(dynamic dto)
{
var entityId = await nameService.Add(dto.Name);
await addressService.Add(dto.Address);
await ageService.Add(dto.Age);
return entityId;
}
所以这是简化的,但实际上我在这里调用了多个服务,它们调用了多个存储库,这工作正常。
问题 我遇到的问题是在事务中更新同一实体。显示 Save
逻辑的全部目的是在最后指出,因为我有这个 return entityId;
我能够毫无问题地将所有东西链接在一起。但是,就像现在一样,默认情况下我们的 Update
方法没有 returning 任何东西,这就是我无法弄清楚如何实现 Update
逻辑的地方。
目前我有这个:
public async Task UpdateEntireEntity(UpdateEntityDTO, entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await UpdateInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
而 UpdateInTransaction
看起来像这样:
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
这似乎至少基于我所做的几次测试,但我真的不喜欢这部分:
return await Task.FromResult<dynamic>(null);
对我来说,这似乎是一个丑陋的 hack。 Update
方法被认为不会 return 任何值,这太人为了。
甚至最糟糕的是,我不知道如何在不需要 return 的情况下实现更新方法。
我试过的一件事是将 UpdateInTransaction
的声明更改为
private async Task UpdateInTransaction(dynamic dto)
当我调用该方法时,我将其更改为:
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task>( async dto => await UpdateInTransaction(dto)..
但是我遇到了以下异常:
AsyncStateMachineBox
1[System.Threading.Tasks.VoidTaskResult, <fully-qualified- name>.<<UpdateEntireEntity>b__0>d] to type 'System.Threading.Tasks.Task
1[System.Threading.Tasks.Task]'
。 所以基本上就是这样。很抱歉 post。我真的很感激一些解释得很好的答案。
你可以改变
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
到
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return null;
}
我会避免使用 Delegate
因为它不是输入的:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(Func<Task<TOut>> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await (function()).ConfigureAwait(false);
scope.Complete();
return result;
}
}
此签名意味着您需要捕获参数而不是传递它们:
public async Task<dynamic> SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync(
async () => await SaveInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
一旦您在方法签名中使用强类型 Func<Task<T>>
而不是 Delegate
,您就可以像这样为 ExecuteInTransactionAsync
创建重载:
public async Task ExecuteInTransactionAsync(Func<Task> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
await (function()).ConfigureAwait(false);
scope.Complete();
}
}
可以这样使用:
public async Task UpdateEntireEntity(UpdateEntityDTO entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync(
async () => await UpdateInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
private async Task UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
}