Reputation: 43
I have a application where I use Async and Await when calling a rest web service. When running my unit tests, I can't seem to get any proper response back even though I am using await. This is the async method:
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;
}
The calling method looks like this:
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;
}
Now if I put a breakpoint on return response in the calling function, I can see an object that has the status="Waiting for Activation" and Result="Not yet computed". Of what I have been able to gather, calling .Result on the returned object should make it run synchronously and return the result. (For example, status code of the request such as 200).
What am I missing here? Why does it not wait until it is finished?
Upvotes: 1
Views: 4367
Reputation: 2681
async-await are just keywords which tell the compiler to compile your code as an implementation of an IAsyncStateMachine
and also wait for it to finish, both keywords need to be used in conjunction for this to work and they only work on Task
objects. A Task
represents a piece of work that is happening.
You must mark your SendEmail
method as async
, change the return type to Task<object>
and await
your emailHandler.SendEmail
call.
Bottom line is, if you're going async
then you must go async
all the way up and await
at some or many points, otherwise you begin looking at running asynchronous code synchronously which is kind of shooting yourself in the foot.
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;
}
As always, Stephen Cleary is an excellent source for async
knowledge.
Upvotes: 5
Reputation: 25070
It seems to me that you expect SendEmail to be synchronous. You can wait for the asynchronous method to complete in SendEmail like this:
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;
}
Upvotes: -4
Reputation: 1805
It's because
var response = emailHandler.SendEmail(apiKey, senderEmail, senderName, recipientEmail, recipientName, subject, content, html);
initiaties a Task, and your caller (public static object SendEmail) doesn't await that task.
Chris Pratt has written a nice blog with an async-helper to run async-methods sync.
Upvotes: 2