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


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

對上節的內容進行了補充

MVC過濾器Filter

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

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

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

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

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

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

但是可以在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方法達到這個目的

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);
         */
    }
}

示例代碼

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;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM