我有一个API,负责在数据库中插入短信详细信息。 它通过对存储库进行同步调用来实现,我认为可以通过异步方式实现。如何实现这一点?或者什么是处理这种情况的最佳方式。代码片段示例非常受欢迎,因为我仍然围绕着.NET。
API:
public IHttpActionResult SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_service.SendSMS(smsNotification);
return Ok();
}
服务:
internal void SendSMS(SMSNotification smsNotification)
{
_repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
回复:
public virtual bool Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("@fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("@fRetVal", System.Data.SqlDbType.Int);
sql.Execute();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
这里的sql是一个自定义的东西,它有以下方法:
public static int Execute(this IDataCommand @this);
[AsyncStateMachine(typeof(<ExecuteAsync>d__1))]
public static Task<int> ExecuteAsync(this IDataCommand @this);
答案 0 :(得分:2)
将阻止(通常是IO绑定的调用)(例如数据库,网络或文件系统工作)更改为异步可以使您的应用程序更好地扩展。
这确实会通过您的API产生影响。也就是说,你需要等待异步调用一直到最顶层的调用,否则,某个地方会阻塞,你只是失去了调用异步API的好处。
为了证明这一点,让我们从存储库调用的底部开始,因为这可能是非常昂贵的阻塞操作。我们改变sql.Execute以使用异步版本ExecutAsync版本:
回购:
public virtual async Task<bool> Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("@fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("@fRetVal", System.Data.SqlDbType.Int);
await sql.ExecuteAsync();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
现在我们必须更改方法的签名,以返回包含bool结果的Task。
我们还将该方法标记为异步,因此我们可以进一步使用“await”运算符。如果不这样做,我们必须做更多的重构来操作并自己返回Task结果,但是“async”修饰符和“await”关键字让编译器为我们做了那个魔术,其余代码大部分看起来像正常。
映射器调用实际上不需要更改:
映射器:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
服务调用现在正在调用异步方法,因此我们要等待而不是阻塞该异步调用,我们还必须将此前的void方法更改为异步方法。注意我们将它从“void”更改为“async Task”;您可以将void方法标记为“async void”,但这是作为Windows窗体和WPF应用程序中事件处理程序的解决方法;在其他每种情况下,您都希望在将其设置为异步时将“void”方法更改为“async Task”。
服务:
internal async Task SendSMS(SMSNotification smsNotification)
{
await _repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
最后,我们的API调用可以异步,等待我们的服务调用:
API:
public async Task<IHttpActionResult> SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _service.SendSMS(smsNotification);
return Ok();
}
有时候建议你在执行这样的重构之后,按照惯例将方法重命名为“Async”;但是我认为这不是必须的,因为.NET API表面的大部分变得异步,现在几乎是多余的。
值得深入了解异步/等待的东西;我试图让这个例子保持相对简短。但我希望这至少可以让你开始。