ASP.NET MVC Ajax 错误处理

当 jquery ajax 调用动作时,如何处理控制器中抛出的异常?

例如,我想要一个全局 javascript 代码,它在 Ajax 调用期间在任何类型的服务器异常上执行,Ajax 调用在调试模式下显示异常消息,或者只显示普通的错误消息。

在客户端,我将对 ajax 错误调用一个函数。

在服务器端,我是否需要编写一个自定义的 action 过滤器?

129134 次浏览

如果服务器发送一些不同于200的状态代码,则执行错误回调:

$.ajax({
url: '/foo',
success: function(result) {
alert('yeap');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('oops, something bad happened');
}
});

并注册一个全局错误处理程序,您可以使用 $.ajaxSetup()方法:

$.ajaxSetup({
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('oops, something bad happened');
}
});

另一种方法是使用 JSON。因此,您可以在服务器上编写一个自定义操作过滤器,用于捕获异常并将其转换为 JSON 响应:

public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new JsonResult
{
Data = new { success = false, error = filterContext.Exception.ToString() },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}

然后用这个属性装饰您的控制器操作:

[MyErrorHandler]
public ActionResult Foo(string id)
{
if (string.IsNullOrEmpty(id))
{
throw new Exception("oh no");
}
return Json(new { success = true });
}

and finally invoke it:

$.getJSON('/home/foo', { id: null }, function (result) {
if (!result.success) {
alert(result.error);
} else {
// handle the success
}
});

为了在客户端处理来自 ajax 调用的错误,需要为 ajax 调用的 error选项分配一个函数。

要设置全局默认值,可以使用下面描述的函数: Http://api.jquery.com/jquery.ajaxsetup.

在 Google 之后,我基于 MVC Action Filter 写了一个简单的异常处理:

public class HandleExceptionAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
filterContext.Exception.Message,
filterContext.Exception.StackTrace
}
};
filterContext.ExceptionHandled = true;
}
else
{
base.OnException(filterContext);
}
}
}

用 global.ascx 写:

 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleExceptionAttribute());
}

然后在布局或母版页上写下这个脚本:

<script type="text/javascript">
$(document).ajaxError(function (e, jqxhr, settings, exception) {
e.stopPropagation();
if (jqxhr != null)
alert(jqxhr.responseText);
});
</script>

最后,您应该打开自定义错误。 然后享受它:)

我做了一个快速的解决方案,因为我的时间短,它的工作还可以。尽管我认为更好的选择是使用异常筛选器,但是在需要简单解决方案的情况下,我的解决方案可能会有所帮助。

在控制器方法中,我返回了一个 JsonResult,它在 Data 中有一个属性“ Success”:

    [HttpPut]
public JsonResult UpdateEmployeeConfig(EmployeConfig employeToSave)
{
if (!ModelState.IsValid)
{
return new JsonResult
{
Data = new { ErrorMessage = "Model is not valid", Success = false },
ContentEncoding = System.Text.Encoding.UTF8,
JsonRequestBehavior = JsonRequestBehavior.DenyGet
};
}
try
{
MyDbContext db = new MyDbContext();


db.Entry(employeToSave).State = EntityState.Modified;
db.SaveChanges();


DTO.EmployeConfig user = (DTO.EmployeConfig)Session["EmployeLoggin"];


if (employeToSave.Id == user.Id)
{
user.Company = employeToSave.Company;
user.Language = employeToSave.Language;
user.Money = employeToSave.Money;
user.CostCenter = employeToSave.CostCenter;


Session["EmployeLoggin"] = user;
}
}
catch (Exception ex)
{
return new JsonResult
{
Data = new { ErrorMessage = ex.Message, Success = false },
ContentEncoding = System.Text.Encoding.UTF8,
JsonRequestBehavior = JsonRequestBehavior.DenyGet
};
}


return new JsonResult() { Data = new { Success = true }, };
}

在随后的 ajax 调用中,我只是要求这个属性知道我是否有一个例外:

$.ajax({
url: 'UpdateEmployeeConfig',
type: 'PUT',
data: JSON.stringify(EmployeConfig),
contentType: "application/json;charset=utf-8",
success: function (data) {
if (data.Success) {
//This is for the example. Please do something prettier for the user, :)
alert('All was really ok');
}
else {
alert('Oups.. we had errors: ' + data.ErrorMessage);
}
},
error: function (request, status, error) {
alert('oh, errors here. The call to the server is not working.')
}
});

希望这个有帮助。快乐代码

不幸的是,这两个答案都不适合我。令人惊讶的是,解决方案要简单得多。从控制器返回:

return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Response.ReasonPhrase);

并在客户端上按照您喜欢的标准 HTTP 错误处理它。

这里有一个完整的例子,与 Aleho 的回答一致,它的工作原理非常简单。

控制器代码

[HttpGet]
public async Task<ActionResult> ChildItems()
{
var client = TranslationDataHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("childItems);


if (response.IsSuccessStatusCode)
{
string content = response.Content.ReadAsStringAsync().Result;
List<WorkflowItem> parameters = JsonConvert.DeserializeObject<List<WorkflowItem>>(content);
return Json(content, JsonRequestBehavior.AllowGet);
}
else
{
return new HttpStatusCodeResult(response.StatusCode, response.ReasonPhrase);
}
}
}

视图中的 Javascript 代码

var url = '@Html.Raw(@Url.Action("ChildItems", "WorkflowItemModal")';


$.ajax({
type: "GET",
dataType: "json",
url: url,
contentType: "application/json; charset=utf-8",
success: function (data) {
// Do something with the returned data
},
error: function (xhr, status, error) {
// Handle the error.
}
});

Hope this helps someone else!