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

时间:2015-07-21 12:47:03

标签: c# ajax asynchronous asp.net-mvc-5

我正在尝试解决一个问题,但是没有正常通过我的ajax调用。

我的异步控制器方法被多次调用,我只发送一个ajax请求。应该发送响应,但是在firefox的调试面板中查看网络选项卡,我看不到任何响应; ajax错误处理程序函数也有一个readyState = 0.只有在异步控制器方法中抛出异常时才会发生这种情况。

这个问题有三个/四个部分:

  • 我的javascript
  • 我的异步控制器方法
  • 后者调用的异步私有控制器方法
  • 格式化响应的JsonError和JsonSuccess方法

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

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

异步方法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);
}

当我在SendMail的第一行(带有MailMessage mail = await GetMailFor(campagneId, tiersNum);的那一行)和catch中的断点上放置一个断点时,我看到该方法被调用了7次并且每次都进入catch,主要是使用不同的{ {1}}中的{1}}值。

奇怪的是,如果我用ManagedThreadId替换System.Threading.Thread.CurrentThread调用,则过程进展顺利,我的断点中只捕获了一个调用。

我查看了this issue,但在mail.To.Add()之前添加throw new ArgumentException("Boom");没有改变任何内容。

我只在firefox的“网络”选项卡中看到1个POST请求。这从来没有得到任何回应。 请注意这些片段足以导致问题,但我在实际应用程序中使用了更多代码(无需警告我关于不等待的异步方法)。

发生了什么事?为什么SendMail被调用了7次?为什么只有当HttpContext.ApplicationInstance.CompleteRequest();抛出而不是我手动投掷时?我该如何调试这种令人费解的行为?

编辑:return Json(new {e.Message}, JsonRequestBehavior.AllowGet);方法中移除try / catch不会产生任何变化。
EDIT2 :删除对new MailAddress()GetMailForasync的任何提及也不会产生任何变化,因此这与Task<T>问题无关。我现在有点迷失,因为我不知道如何调试...... EDIT3 :我从未输入await功能,但每次进入async之前我都会输入Application_Error,并在返回Application_BeginRequest后每次都输入SendMail

1 个答案:

答案 0 :(得分:2)

随机尝试疯狂的事情,我偶然发现了真正的问题:JsonError正在添加异常消息Response.StatusDescription,而消息包含\r\n。这在某种程度上打破了请求处理。

修复只是将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);
}