0

I'm attempting to understand async and Task with await, not sure if I quite get it yet as my application isn't responding the way I thought it worked.

I have an MVC project and inside a Controller is a method that runs on Save. This method does a few things, but the main item I am focusing on is the sending of an email to SendGrid.

[HttpPost]
[ValidateAntiForgeryToken]
private void SaveAndSend(ModelView model)
{
    //This is never used, but is needed in "static async Task Execute()"
    ApplicationDBContext db = new ApplicationDBContext();

    //First try (like the SendGrid example)
        Execute().Wait();
        //More code, but wasn't being executed (even with a breakpoint)
        //...


    //Second try, removed the .Wait()
        Execute();
        //More code and is being executed (good)
        //...
}

Inside Execute():

static async Task Execute()
{
    var apiKey = "REMOVED";
    var client = new SendGridClient(apiKey);
    var from = new SendGrid.Helpers.Mail.EmailAddress("example@example.com", "Example User");
    var subject = "Sending with SendGrid is Fun";
    var to = new SendGrid.Helpers.Mail.EmailAddress("example@example.com", "Example User");
    var plainTextContent = "and easy to do anywhere, even with C#";
    var htmlContent = "<strong>and easy to do anywhere, even with C#</strong>";
    var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);
    var iResponse = await client.SendEmailAsync(msg);

    //The above ^ is executed (sent to SendGrid successfuly)

    //The below is not being executed if I run the code with no breakpoints
    //If I set a breakpoint above, I can wait a few seconds, then continue and have the code below executed

    //This is an Object I have to save the Response from SendGrid for testing purposes
    SendGridResponse sendGridResponse = new SendGridResponse
    {
        Date = DateTime.Now,
        Response = JsonConvert.SerializeObject(iResponse, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore })
    };

    //This is needed to save to the database, was hoping to avoid creating another Context
    ApplicationDBContext db = new ApplicationDBContext();

    db.SendGridResponses.Add(sendGridResponse);
    db.SaveChanges();

}

Now that I have outlined my code (most likely horrible practices), I was hoping to better understand async Task and improve what I am attempting to accomplish.

How can I wait for var iResponse = await client.SendEmailAsync(msg); and Save it to my database properly. Allowing the application to continue (not interupt the user experience).

Please let me know if I should include more information.

Derek
  • 653
  • 7
  • 20
  • Does SendGrid really recommend using `Wait()`? You should make your controller async and `await` the call, do not block with Wait. – Crowcoder Dec 09 '17 at 19:22
  • I'll check out the other Question @Clint, thank you. – Derek Dec 09 '17 at 19:29
  • SendGrid does have .Wait() in the [Getting Started](https://app.sendgrid.com/guide/integrate/langs/csharp) @Crowcoder. – Derek Dec 09 '17 at 19:30

1 Answers1

2

You can make your controller async by return Task and then await the call instead of Wait.

 [HttpPost]
 [ValidateAntiForgeryToken]
 public async Task<IActionResult> SaveAndSend(ModelView model)
 {
      //This is never used, but is needed in "static async Task Execute()"
      ApplicationDBContext db = new ApplicationDBContext();

      // Await the Execute method call, instead of Wait()
      await Execute();
    .....
}
Ankit Vijay
  • 3,752
  • 4
  • 30
  • 53