.NET MVC全局異常處理(二)

.NET MVC全局異常處理(二)

對上節的內容進行了補充web

MVC過濾器Filter

MVC有四種過濾器:Authorization、Exception、Action、Result,咱們要用的的就是Exception異常過濾器mvc

當咱們新建一個MVC項目後,異常過濾器就已經自動在程序中註冊了,先從上一節所說的全局配置文件開始,Global.asax這個文件中的Application_Start方法會在程序啓動時運行,其中的即默認註冊了全局過濾器,如圖app

咱們能夠進入RegisterGlobalFilters方法查看,這個方法中默認註冊了一個異常處理過濾器,也就是說默認狀態的MVC程序發生異常時會被程序捕獲處理,處理方式是跳轉至錯誤頁面,也就是上一篇文章說的Layout文件夾下面的Error頁ide

但使用異常過濾器有一個大前提是要在Web.config中打開自定義錯誤處理的設置,customErrors節點要設置爲「On」,這一設置默認是關閉的,也就是說要手動加上才行debug

<system.web>
  <compilation debug="true" targetFramework="4.6.1"/>
  <httpRuntime targetFramework="4.6.1"/>
  <customErrors mode="On">
  </customErrors>
</system.web>

須要注意的是 404 錯誤,這種類型的異常並不會被過濾器捕獲3d

可是能夠在web.config中添加節點進行自定義配置,跳轉到相應的頁面日誌

<customErrors mode="On">
  <error redirect="~/Error/NotFound" statusCode="404" />
</customErrors>
public class ErrorController : Controller
{
    // GET: Error
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult CustomHttpError()
    {
        ViewBag.Message = "有錯誤";
        //HandleErrorInfo
        //ExceptionContext

        return View();
    }
    public ActionResult NotFound()
    {
        return View();
    }
}

自定義過濾器

MVC默認的異常過濾器能夠知足基本的須要,可是若是要對一些異常進行特殊處理就須要咱們自定義過濾器的內容,能夠經過重寫OnException方法達到這個目的code

public class CustomHandleErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        /* 調用基類的OnException方法,實現基礎的功能。
         * 若是要徹底的自定義,就不須要調用基類的方法
         */
        base.OnException(filterContext);

        /* 此處可進行記錄錯誤日誌,發送錯誤通知等操做
         * 經過Exception對象和HttpException對象可獲取相關異常信息。
         * Exception exception = filterContext.Exception;
         * HttpException httpException = new HttpException(null, exception);
         */
    }
}

示例代碼orm

public class MyErrorHandler : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
            return;

        var statusCode = (int) HttpStatusCode.InternalServerError;
        if (filterContext.Exception is HttpException)
        {
            statusCode = filterContext.Exception.As<HttpException>().GetHttpCode();
        }
        else if (filterContext.Exception is UnauthorizedAccessException)
        {
            //to prevent login prompt in IIS
            // which will appear when returning 401.
            statusCode = (int)HttpStatusCode.Forbidden;
        }
        _logger.Error("Uncaught exception", filterContext.Exception);

        var result = CreateActionResult(filterContext, statusCode);
        filterContext.Result = result;

        // Prepare the response code.
        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = statusCode;
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }

    protected virtual ActionResult CreateActionResult(ExceptionContext filterContext, int statusCode)
    {
        var ctx = new ControllerContext(filterContext.RequestContext, filterContext.Controller);
        var statusCodeName = ((HttpStatusCode) statusCode).ToString();

        var viewName = SelectFirstView(ctx,
                                       "~/Views/Error/{0}.cshtml".FormatWith(statusCodeName),
                                       "~/Views/Error/General.cshtml",
                                       statusCodeName,
                                       "Error");

        var controllerName = (string) filterContext.RouteData.Values["controller"];
        var actionName = (string) filterContext.RouteData.Values["action"];
        var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
        var result = new ViewResult
                         {
                             ViewName = viewName,
                             ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
                         };
        result.ViewBag.StatusCode = statusCode;
        return result;
    }

    protected string SelectFirstView(ControllerContext ctx, params string[] viewNames)
    {
        return viewNames.First(view => ViewExists(ctx, view));
    }

    protected bool ViewExists(ControllerContext ctx, string name)
    {
        var result = ViewEngines.Engines.FindView(ctx, name, null);
        return result.View != null;
    }
}
相關文章
相關標籤/搜索