我对 MVC 4 的异常处理有一些疑问。
我已经实现HandleErrorAttribute
并派生了一个要自定义的新属性。它真的很好用;但我不想每次都重定向用户自定义错误页面。
我在 Actions 中遇到的一些错误是从 Web API 抛出的,我想在当前页面向用户展示它们。例如,如果用户想要创建一条记录,但 WebAPI 因模型状态无效而引发异常,则异常详细信息会以友好的方式显示在 Create 视图中。
但是 HandleErrorAttribute 默认重定向 Error.cshtml。
我可以处理 Actions 中的所有异常,但我认为还有另一种方法。
我也跟着http://www.prideparrot.com/blog/archive/2012/5/exception_handling_in_asp_net_mvc来实施HandleErrorAttribute
public class CustomHandleErrorAttribute : HandleErrorAttribute {
private readonly ILogger _logger;
public CustomHandleErrorAttribute() {
_logger = new NLogger(typeof(CustomHandleErrorAttribute));
}
public override void OnException(ExceptionContext filterContext) {
if(filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) {
return;
}
if(new HttpException(null, filterContext.Exception).GetHttpCode() != 500) {
return;
}
if(!ExceptionType.IsInstanceOfType(filterContext.Exception)) {
return;
}
// if the request is AJAX return JSON else view.
if(filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest") {
filterContext.Result = new JsonResult {
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new {
error = true,
message = filterContext.Exception.Message
}
};
}
else {
var controllerName = (string)filterContext.RouteData.Values["controller"];
var actionName = (string)filterContext.RouteData.Values["action"];
var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
filterContext.Result = new ViewResult {
ViewName = View,
MasterName = Master,
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
TempData = filterContext.Controller.TempData
};
}
_logger.Error(filterContext.Exception.Message, filterContext.Exception);
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
我通过 HttpClient 和包装类进行了 Web API 调用。例如 Get 请求如下所示。
public async Task<BrandInfo> Create(BrandInfo entity) {
using(var apiResponse = await base.PostAsync(BaseUriTemplate, entity)) {
if(apiResponse.IsSuccess) {
return apiResponse.Model;
}
throw new HttpApiRequestException(
string.Format(HttpRequestErrorFormat, (int)apiResponse.Response.StatusCode, apiResponse.Response.ReasonPhrase),
apiResponse.Response.StatusCode, apiResponse.HttpError);
}
}