1

I am having problem with calling async void function in non async method. I get internal server error. I have googled this issue and got found some answers for TASK and not TASK. my case is not task so i should call task.RunSynchronously(). which will wait to my async method to completed and then continue to the next point. But when i am debugging it brings server error.

private async void MyMthodAsync(int userId, string email)
{
    var emailTemplate = await EmailTemplateLoader.Load(EmailTemplateFile);
    var Message = new MailMessage(emailTemplate.`enter code here`From, email)
    {
        Subject = emailTemplate.Subject,
        Body = emailTemplate.Body,
        IsBodyHtml = true,
        BodyEncoding = Encoding.UTF8
    };
    await EmailSender.Send(Message);
}

I am calling above async method in none async method

public HttpResponseMessage ChangePassword([FromBody]ChangePasswordModel model)
{
    Task sendEmail = new Task(()=>MyMthodAsync(model.userId, model.email));
    sendEmail.RunSynchronously();

    return TheResponse.CreateSuccessResponse(Constants.PasswordHasBeenSuccessfullyChanged);
}

I get my response as internal server error.

What am I doing wrong?

MPelletier
  • 16,256
  • 15
  • 86
  • 137

1 Answers1

0

Avoid async void unless it is an event handler. Change the return type to Task.

private async Task SendChangePasswordEmailAsync(int userId, string email)
{
    var emailTemplate = await EmailTemplateLoader.Load(EmailTemplateFile);
    var Message = new MailMessage(emailTemplate.From, email)
    {
        Subject = emailTemplate.Subject,
        Body = emailTemplate.Body,
        IsBodyHtml = true,
        BodyEncoding = Encoding.UTF8
    };

    await EmailSender.Send(Message);
}

Then change the method to use async-await.

public async Task<HttpResponseMessage> ChangePassword(
    [FromBody]ChangePasswordModel model
)
{
    await SendChangePasswordEmailAsync(model.userId, model.email);

    return TheResponse
        .CreateSuccessResponse(Constants.PasswordHasBeenSuccessfullyChanged);
}
Dustin Kingen
  • 20,677
  • 7
  • 52
  • 92
  • 2
    Calling `RunSynchronously` on an already started task, which is what you're doing, will throw an exception. If you wait synchronously on it them the code will deadlock, because the sync context can't be marshaled to by the async method's continuation due to it being blocked by code waiting on the async method. – Servy Apr 10 '14 at 17:34
  • I got this exception : [System.InvalidOperationException] = {"RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method."} – John Dudley Apr 10 '14 at 17:41
  • Try changing the code to use async-await. If you're using it in the method you're calling then you should use it in the caller. – Dustin Kingen Apr 10 '14 at 17:47
  • I get response ok, it seems working with Task.WhenAll() but don't have email being logged into the file – John Dudley Apr 10 '14 at 17:56
  • 1
    changing to async-wait works. I was wondering if it is possible to call async method in non-async method? – John Dudley Apr 10 '14 at 18:00
  • It should be `Task.WaitAll` not `Task.WhenAll`. It was my mistake. – Dustin Kingen Apr 10 '14 at 18:08