I am trying to troubleshoot a problem with exceptions not getting through to my ajax call properly.
My asynchronous controller method is called multiple times, where I only send one ajax request. The response is supposed to be sent, but looking at the network tab in firefox's debug panel, I see no response; the ajax error handler function also has a readyState = 0. This happens only when an exception is thrown inside the async controller method.
There are three/four parts to this problem:
Ajax call:
function test() {
var data = {
campagneId: 15,
tiersNum: 2721
};
console.debug("Starting Ajax !");
$.ajax({
url: "/CampagnesMailing/SendMail",
data: data,
method: "POST",
success: function (response) {
console.debug("Sent mail successfully!");
},
error: function (xhr, ajaxOpt, thrownError) {
console.error("Error!");
console.error(xhr); //xhr.readyState is 0
console.error(ajaxOpt);
console.error(thrownError); //this is empty
},
complete: function () {
console.debug("Finished ajax call!");
}
});
}
$("#goButton").on("click", test);
Async controller method called by ajax:
[HttpPost]
public async Task<ActionResult> SendMail(int campagneId, int tiersNum)
{
try
{
MailMessage mail = await GetMailFor(campagneId, tiersNum); //I tried adding .ConfigureAwait(false) with no change
return JsonSuccess();
}
catch (Exception e)
{
return JsonError(e);
}
}
Async method GetMailFor:
private async Task<MailMessage> GetMailFor(int campagneId, int tiersNum)
{
try
{
MailMessage mail = new MailMessage();
mail.To.Add(new MailAddress("")); // This throws an ArgumentException
return mail;
}
catch (Exception e)
{
throw;
}
}
JsonError / JsonSuccess:
protected JsonResult JsonSuccess()
{
Response.StatusCode = (int) System.Net.HttpStatusCode.OK;
Response.StatusDescription = "SUCCESS";
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
protected JsonResult JsonError(Exception e)
{
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
Response.StatusDescription = e.Message;
//HttpContext.ApplicationInstance.CompleteRequest();
return Json(new {e.Message}, JsonRequestBehavior.AllowGet);
}
When I put a breakpoint on the first line of SendMail (the one with MailMessage mail = await GetMailFor(campagneId, tiersNum);
) and a breakpoint in the catch, I see the method is called 7 times and goes into the catch everytime, mostly with different ManagedThreadId
values in System.Threading.Thread.CurrentThread
.
Oddly enough, if I replace the mail.To.Add()
call by a throw new ArgumentException("Boom");
, the process goes well and only one call is caught in my breakpoints.
I had a look at this issue but adding HttpContext.ApplicationInstance.CompleteRequest();
before return Json(new {e.Message}, JsonRequestBehavior.AllowGet);
did not change anything.
I only see 1 POST request in Network tab from firefox. This never gets any response. Please note these snippets are enough to cause the problem but I use more code in the real application (No need to warn me about async method containing no await).
What is happening? Why is SendMail called 7 times? Why only when new MailAddress()
throws and not when I throw manually? How can I debug such a mindblowing behavior?
EDIT: Removing try/catch from inside the GetMailFor
method yields no change.
EDIT2: Removing any mention of async
, Task<T>
or await
also yields no change, so this has nothing to do with an async
problem. I'm kind of lost now because I don't know how to debug that...
EDIT3: I never enter the Application_Error
function, but I enter Application_BeginRequest
everytime before entering SendMail
and Application_EndRequest
everytime after returning JsonError
Trying crazy things at random, I stumbled upon the real problem: JsonError
was adding the exception message as Response.StatusDescription
while the message contained \\r\\n
. This somehow broke the request handling.
The fix is simply to change JsonError
to:
protected JsonResult JsonError(Exception e)
{
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
Response.StatusDescription = e.Message.Replace("\r\n", " | ");
return Json(new {e.Message}, JsonRequestBehavior.AllowGet);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.