MVC4での例外処理についていくつか質問があります。
HandleErrorAttribute
カスタマイズする新しい属性を実装して導出しました。それは本当にうまくいきます。しかし、私はユーザーに毎回カスタムエラーページをリダイレクトしたくありません。
アクションで発生したエラーのいくつかは、Web APIからスローされ、現在のページでユーザーに表示したいと思います。たとえば、ユーザーがレコードを作成したいが、モデル状態が無効であるためにWebAPIが例外をスローした場合、例外の詳細は[ビューの作成]にわかりやすい方法で表示されます。
ただし、HandleErrorAttributeは、デフォルトでError.cshtmlをリダイレクトします。
アクションですべての例外を処理できますが、別の方法があると思います。
また、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とラッパークラスを介してWebAPI呼び出しを行いました。たとえば、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);
}
}