1

I have a method for sending emails, which makes use of SmtpClient. At one point in this method, I have the following await smtpClient.SendMailAsync (mail);. The call is made from my controller as follows, depending on the case:

    [HttpPost]
    [AllowAnonymous]
    [ValidateJsonAntiForgeryToken]
    public async Task<ActionResult> RegisterParticipant(RegisterIndexBaseVm attendee)
    {
        if (attendee == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        if (ModelState.IsValid)
        {
            attendee.EventId = Int32.Parse(Session["id"].ToString());
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(BaseUrl);
                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpResponseMessage Res = await client.PostAsync("Register/RegisterAttendee", new StringContent(JsonConvert.SerializeObject(Mapper.ToParticipant(attendee)), Encoding.UTF8, "application/json"));
                if (Res.IsSuccessStatusCode)
                {
                    var EmpResponse = Res.Content.ReadAsStringAsync().Result;
                    var result = JsonConvert.DeserializeObject<EmailTemplateDTO>(EmpResponse);
                    if (result.NotError == false)return Json(new { success = false, message = Constants.CulqiResponses[result.Response] }, JsonRequestBehavior.AllowGet);
                    if (string.IsNullOrEmpty(result.InvoiceInstitution))
                    {

                        if (result.SendEmail == true) MailHelper.SendMail(Enumerables.MailAction.EventRegisterSuccess, result);
                        return Json(new { success = true }, JsonRequestBehavior.AllowGet);
                    }
                    else
                    {
                        if (result.SendEmail == true) MailHelper.SendMail(Enumerables.MailAction.EventRegisterSuccessWithInvoice, result);
                        return Json(new { success = true, message = "Registro Exitoso" }, JsonRequestBehavior.AllowGet);
                    } 
                }
                else
                {
                    return Json(new { success = false }, JsonRequestBehavior.AllowGet);
                }
            }
        }
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

In the web application, I have an AJAX that executes the call to said controller, which uses the parameter async: true, but I always get a 500 error. I do not understand the reason well and how I should make the correct call to each method and class to get the correct results.

$.ajax({
    type: 'POST',
    url: url,
    headers: headers,
    dataType: 'json',
    async: true,
    data: { attendee: enviar },
    success: function (response) {
        $('#payment').modal('hide');
        if (payType === 'Culqui') {
            resultdiv("", 'success');
        }
        else {
            resultdiv("", 'warning');
        }

    },
    error: function (result) {
        $('#payment').modal('hide')
        resultdiv("", 'error');
    }
});

The answer is the following:

An asynchronous module or handler completed while an asynchronous operation was still pending.

But the sending of the emails is done with no inconvenience. It is necessary that the method of sending emails has the following public static async void SendMail, I do not expect any real response from the same from the controller.

Dale K
  • 25,246
  • 15
  • 42
  • 71
  • Use you browser tools (the Network tab) to inspect the response which will give you the full details of the error message –  Jul 31 '18 at 06:15
  • The answer is the following: `An asynchronous module or handler completed while an asynchronous operation was still pending.` But the sending of the emails is done with no inconvenience. It is necessary that the method of sending emails has the following `public static async void SendMail` , I do not expect any real response from the same from the controller. – Adolfo F. Ibarra Landeo Jul 31 '18 at 06:15
  • Edit the question if you have further details to add (not in comments) –  Jul 31 '18 at 06:16
  • Try with this post: https://stackoverflow.com/a/28806198/1081079 – freshbm Jul 31 '18 at 06:25
  • @freshbm, the problem is that if I call that method synchronously (what I tried), I obtain the exact same results... – Adolfo F. Ibarra Landeo Jul 31 '18 at 06:35
  • 1
    @AdolfoF.IbarraLandeo did you try what he is suggesting in the post? to temporary replace synchronization context? https://stackoverflow.com/a/45972474/1081079 – freshbm Jul 31 '18 at 06:50
  • @freshbm, that was the answer... It works now. Can you write it as an answer so that you can mark it as the correct one? – Adolfo F. Ibarra Landeo Jul 31 '18 at 07:50

1 Answers1

1

As suggested by @binki in this post:

var originalSynchronizationContext = SynchronizationContext.Current;
try
{
    SynchronizationContext.SetSynchronizationContext(null);

    //... call your method here!
}
finally
{
    SynchronizationContext.SetSynchronizationContext(originalSynchronizationContext);
}

This is because async methods track their completion, even async void. They do this by registering with the SynchronizationContext when starting and marking the operation complete when returning. ASP.NET tracks all created operations and requires them to all be completed before your action returns, otherwise it returns an error to the HTTP client.

freshbm
  • 5,540
  • 5
  • 46
  • 75