我有一个MVC控制器方法可以做很多事情,但它最后做的是:
public void PerformCheckout(int salesAddressId)
{
try
{
...
...
// We just made a sale. Send emails to all market owners.
SendSalesEmailsAsync(master);
}
catch (System.Exception exception)
{
// Log the error
}
然后SendSalesEmailesAsynch()看起来像这样:
private async Task SendSalesEmailsAsync(SalesMaster salesMaster)
{
...
...
// Send an email to the owner of each marker
foreach(string market in markets)
await SendSalesEmailAsync(salesMaster, salesDetailList, market).ConfigureAwait(false);
}
SendSalesEmailAsynch()如下所示:
// Send an email to a market owner
private async Task SendSalesEmailAsync(SalesMaster salesMaster, List<SalesDetail> salesDetail, string marketName)
{
...
...
Email email = new Email(new List<string> { sellerEmailAddress }, emailSubject, emailHtmlBody);
await email.SendAsync().ConfigureAwait(false);
最后,实际发送电子邮件的方法是:
public async Task SendAsync()
{
// Create a network credentials object
var credentials = new NetworkCredential(azureUserName, azurePassword);
// Create an Web transport for sending the email
var transportWeb = new Web(credentials);
// Send the email. We don't care about the current context so let's run this in a thread pool context.
// For more information: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
await transportWeb.DeliverAsync(this._email).ConfigureAwait(false);
}
我是Async和Await的新手。这一切看起来都合适吗?此外,我不完全确定如果在发送电子邮件时发生错误,将调用控制器操作方法中的catch块。
答案 0 :(得分:1)
如您所料,由于您未与当前上下文同步,catch
块无法获得任何异常。为此,您必须将操作方法标记为async
,并使用await
来调用SendSalesEmailsAsync
。因此action方法如下所示:
public async Task PerformCheckout(int salesAddressId)
{
try
{
...
...
// We just made a sale. Send emails to all market owners.
await SendSalesEmailsAsync(master);
}
catch (System.Exception exception)
{
// Log the error
}
答案 1 :(得分:1)
这不是用于异步等待的典型方法。我不愿意说“不正确”,因为设计目标是依赖于实现的。
显示的代码中有几个问题。有一个采取异步操作并返回void的方法可能是一个坏主意,原因有几个。
控制器不应该真正暴露不包含返回信息的功能。如果它是要执行的操作,则应将其称为某种服务或业务逻辑。此外,由于该方法是公共的,并且控制器的一部分任何人都可以从URL调用它。由于它发送了一组电子邮件,这可能是不可取的。
应该使用Async / await来释放处理能力。在大多数情况下,只应在处理时间或等待时间超过40毫秒时使用。由于电子邮件是火上浇油而忘记,在您的情况下可能不是这种情况,在这种情况下,整个方法可以转换回同步。
如果花费的时间超过40毫秒,那么异步就可以使用了。但是,在显示的代码中,第一次调用未正确使用。如果在没有等待的情况下进行异步调用,它基本上就是“发射并忘记”。特别是当没有返回值时,从未注意到返回。因此,如果抛出异常,它也会被遗忘,并且catch块将永远不会被执行。
使用await会导致创建新的任务延续。在调用发生时,该方法的其余部分基本上是分叉的。一旦被调用的执行完成,那么分叉的方法的其余部分就会执行。如果没有等待,方法的其余部分只会执行,而旁边调用的执行可能会在很晚之后完成。
总而言之,这个设计应该重构,以便从更受控制的环境中调用,甚至可能从同步方法调用。