首页 > 代码库 > 想抛就抛:Application_Error中统一处理ajax请求执行中抛出的异常

想抛就抛:Application_Error中统一处理ajax请求执行中抛出的异常

女朋友不是想抛就抛,但异常却可以,不信请往下看。

今天在MVC Controller中写代码时,纠结了一下:

public async Task<ActionResult> Save(int? postId){    if(!IsOwner(postId.Value, userId))    {                            //抛不抛异常呢?    }}

在这个地方要不要抛异常呢?

如果不抛异常,就得这么写:

public async Task<ActionResult> Save(int? postId){    if(!IsOwner(postId.Value, userId))    {        return Json(new {            isSuccess = false,            message = "尝试执行未经授权的操作" });    }}

而且通常在这样的情况下,还需要记录日志,于是代码变成:

if(!IsOwner(postId.Value, userId)){    Logger.Default.Info("UnauthorizedSave", "...");    return Json(new {        isSuccess = false,        message = "尝试执行未经授权的操作" });}

如果抛异常呢,代码就可以这么写:

if(IsOwner(postId.Value, userId)){                        throw new UnauthorizedAccessException();}

代码显得更简洁,更具表达力,而且记录错误日志可以在Application_Error中统一处理:

protected void Application_Error(Object sender, EventArgs e){    var lastError = Server.GetLastError();    if (lastError != null)    {                        Logger.Default.Error("Application_Error", lastError);                       Response.StatusCode = 500;        Server.ClearError();    }}

但这会带来一个问题,客户端收到的将是自定义500错误页面的html代码,不仅没有具体的错误信息,而且在ajax回调时还要额外处理,而通常我们最期待的是一个json格式的返回结果。

于是要想实现“想抛就抛”,就必须解决:如何在Application_Error中统一处理ajax请求处理过程中产生的异常,并将之转换成json格式的响应内容返回给客户端。

分解一下,就变成了2个问题:

1)如何在Application_Error中判断一个请求是否是ajax请求?

今天上午通过MVC的扩展方法IsAjaxRequest解决了,详见如何在Global.asax中判断是否是ajax请求:

if ((new HttpRequestWrapper(Request)).IsAjaxRequest()){} 

2)如何生成json格式的响应内容并返回给客户端?

这个可以通过Json.NET+Response.Write来解决,代码如下:

Response.Clear();Response.ContentType = "application/json; charset=utf-8";Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(    new { isSuccess = false, message = lastError.Message }));Response.Flush();

最终实现“想抛就抛”的代码如下:

protected void Application_Error(Object sender, EventArgs e){    var lastError = Server.GetLastError();    if (lastError != null)    {                   CNBlogs.Infrastructure.Logging.Logger.Default.Error("Application_Error", lastError);        if(Request != null && (new HttpRequestWrapper(Request)).IsAjaxRequest())        {                                Response.Clear();            Response.ContentType = "application/json; charset=utf-8";            Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(                new { isSuccess = false, message = lastError.Message }));            Response.Flush();            Server.ClearError();            return;        }        Response.StatusCode = 500;        Server.ClearError();    }}

ajax客户端收到的结果如下:

技术分享

 从此,可以尽情地抛异常了。

想抛就抛:Application_Error中统一处理ajax请求执行中抛出的异常