简体   繁体   English

捕获异常时,控制器中的异步方法被多次调用

[英]Async method in controller is called multiple times when an exception is caught

I am trying to troubleshoot a problem with exceptions not getting through to my ajax call properly. 我正在尝试解决异常无法正常通过我的ajax调用的问题。

My asynchronous controller method is called multiple times, where I only send one ajax request. 我的异步控制器方法被多次调用,我只发送一个ajax请求。 The response is supposed to be sent, but looking at the network tab in firefox's debug panel, I see no response; 应该发送响应,但是在firefox的调试面板中的“网络”选项卡上,我没有看到响应。 the ajax error handler function also has a readyState = 0. This happens only when an exception is thrown inside the async controller method. ajax错误处理程序函数还具有readyState =0。仅当在异步控制器方法内引发异常时,才会发生这种情况。

There are three/four parts to this problem: 此问题分为三部分/四部分:

  • My javascript 我的JavaScript
  • My async controller method 我的异步控制器方法
  • The async private controller method called by the latter 后者调用的异步私有控制器方法
  • The JsonError and JsonSuccess methods formatting the response JsonError和JsonSuccess方法格式化响应

Ajax call: Ajax呼叫:

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: 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: 异步方法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: 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 . 当我在SendMail的第一行上放置一个断点时(带有MailMessage mail = await GetMailFor(campagneId, tiersNum); )和一个catch中的一个断点,我看到该方法被调用了7次,每次都进入该catch中在System.Threading.Thread.CurrentThread具有不同的ManagedThreadId值。

Oddly enough, if I replace the mail.To.Add() call by a throw new ArgumentException("Boom"); 奇怪的是,如果我用throw new ArgumentException("Boom");替换了mail.To.Add()调用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(); 我看了这个问题,但添加了HttpContext.ApplicationInstance.CompleteRequest(); before return Json(new {e.Message}, JsonRequestBehavior.AllowGet); return Json(new {e.Message}, JsonRequestBehavior.AllowGet); did not change anything. 没有改变任何东西。

I only see 1 POST request in Network tab from firefox. 我只在firefox的“网络”选项卡中看到1个POST请求。 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? 为什么SendMail被调用7次? Why only when new MailAddress() throws and not when I throw manually? 为什么仅当new MailAddress()抛出new MailAddress()不是我手动抛出时才为何? How can I debug such a mindblowing behavior? 我该如何调试这种令人讨厌的行为?

EDIT: Removing try/catch from inside the GetMailFor method yields no change. 编辑:GetMailFor方法内部删除try / catch不会产生任何变化。
EDIT2: Removing any mention of async , Task<T> or await also yields no change, so this has nothing to do with an async problem. EDIT2:删除对asyncTask<T>await任何提及也不会产生任何变化,因此与async问题无关。 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 EDIT3:我从不输入Application_Error函数,但每次返回JsonError之后,每次输入SendMailApplication_EndRequest之前,我都会输入Application_BeginRequest

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 . 随机尝试疯狂的事情时,我偶然发现了一个真正的问题: JsonError正在将异常消息添加为Response.StatusDescription而该消息包含\\r\\n This somehow broke the request handling. 这以某种方式破坏了请求处理。

The fix is simply to change JsonError to: 解决方法是将JsonError更改为:

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM