异步并等待总是返回“等待完成”

时间:2019-02-22 09:03:58

标签: c# async-await

我有一个应用程序,在调用rest Web服务时可以使用Async和Await。运行单元测试时,即使正在使用等待,我似乎也无法获得任何正确的响应。这是异步方法:

public async Task<Response> SendEmail(string apiKey, string senderEmail, string senderName, string recipientEmail, string recipientName, string subject, string content, bool html)
{
    var client = new SendGridClient(apiKey);
    var from = new EmailAddress(senderEmail, senderName);
    var to = new EmailAddress(recipientEmail, recipientName);
    var msg = MailHelper.CreateSingleEmail(from, to, subject, html ? null : content, html ? content : null);
    var response = await client.SendEmailAsync(msg);

    return response;
}

调用方法如下:

public static object SendEmail(string apiKey, string senderEmail, string senderName, string recipientEmail, string recipientName, string subject, string content, bool html)
{
    EmailHandler emailHandler = new EmailHandler();
    var response =  emailHandler.SendEmail(apiKey, senderEmail, senderName, recipientEmail, recipientName, subject, content, html);

    return response;
}

现在,如果我在调用函数的返回响应上放置一个断点,则可以看到状态为“等待激活”和结果为“尚未计算”的对象。我所能收集到的东西,在返回的对象上调用.Result应该使它同步运行并返回结果。 (例如,请求的状态码,例如200)。

我在这里想念什么?为什么不等到完成?

3 个答案:

答案 0 :(得分:5)

async-await只是关键字,它们告诉编译器将您的代码作为IAsyncStateMachine的实现进行编译并等待其完成,这两个关键字需要结合使用才能起作用,并且它们仅在Task对象上工作。 Task代表正在进行的工作。

您必须将SendEmail方法标记为async,将返回类型更改为Task<object>,然后将await更改为emailHandler.SendEmail调用。

最重要的是,如果您要async走,那么您必须一直走async,一直走,然后await在某些或许多点上,否则您将开始着眼于同步运行异步代码,这简直让您无所适从。

public static async Task<object> SendEmail(string apiKey, string senderEmail, string senderName, string recipientEmail, string recipientName, string subject, string content, bool html)
{
    EmailHandler emailHandler = new EmailHandler();
    var response = await emailHandler.SendEmail(apiKey, senderEmail, senderName, recipientEmail, recipientName, subject, content, html);

    return response;
}

与往常一样,Stephen Clearyasync知识的绝佳来源。

答案 1 :(得分:2)

这是因为

var response =  emailHandler.SendEmail(apiKey, senderEmail, senderName, recipientEmail, recipientName, subject, content, html);

初始化一个任务,而您的调用者(公共静态对象SendEmail)不会等待该任务。

克里斯·普拉特(Chris Pratt)编写了一个带有异步帮助器的nice blog,以运行异步方法同步。

答案 2 :(得分:-4)

在我看来,您希望SendEmail是同步的。您可以像这样在SendEmail中等待异步方法完成:

public static Response SendEmail(string apiKey, string senderEmail, string senderName, string recipientEmail, string recipientName, string subject, string content, bool html)
{
    EmailHandler emailHandler = new EmailHandler();
    var responseTask =  emailHandler.SendEmail(apiKey, senderEmail, senderName, recipientEmail, recipientName, subject, content, html);
    responseTask.Wait(); // Wait for the task to complete

    return responseTask.Result;
}