[英]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: 此问题分为三部分/四部分:
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:删除对
async
, Task<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
之后,每次输入SendMail
和Application_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.