MVC擴展Filter,通過繼承HandleErrorAttribute,使用log4net或ELMAH組件記錄服務端500錯誤、HttpException、Ajax異常等


□ 接口

public interface IExceptionFilter
{
    void OnException(ExceptionContext filterContext);
}

ExceptionContext繼承於ControllerContext,從中可以獲得路由數據route data、HttpContext。

 

□ 的HandleErrorAttribute是對IExceptionFilter的實現,默認是啟用的

public static void RegisterGlobalFilters(GlobalFiltersCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}

 

  使用默認的HandleErrorAttribute

□ 讓Shared/Error.cshtml的出錯頁報錯

前提是,在Web.config中配置:

<customErrors mode="On"></customErrors>

 

□ 根據不同錯誤類型顯示不同的錯誤頁

        [HandleError(ExceptionType = typeof(DbException),View = "")]
        [HandleError(ExceptionType = typeof(ApplicationException), View = "")]
        public ActionResult SomeAction()

 

□ HandleErrorAttribute的不足之處

1、只是顯示錯誤頁,無法記錄錯誤日志
2、只能捕獲500錯誤
3、不能捕獲Controller以外的錯誤

 

  繼承HandleErrorAttribute自定義異常處理

使用log4net記錄錯誤日志,並能記錄AJAX錯誤,返回狀態碼為500的服務端錯誤。

 

需要一個顯示錯誤信息的類:

namespace MvcApplication1.Models
{
    public class HandleErrorInfo
    {
        public HandleErrorInfo(Exception exception, string actionName, string controllerName)
        {
            this.Exception = exception;
            this.ControllerName = controllerName;
            this.ActionName = actionName;
        }
        public string ActionName { get; set; }
        public string ControllerName { get; set; }
        public Exception Exception { get; set; }
    }
}

 

引用log4net組件,繼承HandleErrorAttribute自定義異常,使之能記錄狀態碼為500的服務端錯誤,並能以json形式返回ajax相關異常。

using System.Web;
using System.Web.Mvc;
using log4net;
 
namespace MvcApplication1.Extension
{
    public class PowerfulHandleErrorAttribute : HandleErrorAttribute
    {
        private readonly ILog _logger;
 
        public PowerfulHandleErrorAttribute()
        {
            _logger = LogManager.GetLogger("MyLogger");
        }
 
        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;
            }
 
            //如果是AJAX請求返回json
            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(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;
        }
    }
}
 

 

以上PowerfulHandleErrorAttribute錯誤,只能處理服務端狀態碼500錯誤。還可以在全局中設置:當出現HttpException異常的時候,返回對應的錯誤提醒視圖。

       //處理filter遺漏的錯誤
        protected void Application_Error(object sender, EventArgs e)
        {
            var httpContext = ((MvcApplication) sender).Context;
 
            var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
            var currentController = "";
            var currentAction = "";
            if (currentRouteData != null)
            {
                if (currentRouteData.Values["controller"] != null &&
                    !string.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
                {
                    currentController = currentRouteData.Values["controller"].ToString();
                }
 
                if (currentRouteData.Values["action"] != null &&
                    !string.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
                {
                    currentAction = currentRouteData.Values["action"].ToString();
                }
            }
 
            var ex = Server.GetLastError();
            var controller = new ErrorController();
            var routeData = new RouteData();
            var action = "Index";
            if (ex is HttpException)
            {
                var httpEx = ex as HttpException;
                switch (httpEx.GetHttpCode())
                {
                    case 404:
                        action = "NotFound";
                        break;
                    default:
                        action = "Index";
                        break;
                }
            }
 
            httpContext.ClearError();
            httpContext.Response.Clear();
            httpContext.Response.StatusCode = ex is HttpException ? ((HttpException) ex).GetHttpCode() : 500;
            httpContext.Response.TrySkipIisCustomErrors = true;
            routeData.Values["controller"] = "Error";
            routeData.Values["action"] = action;
 
            controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
            ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
        }
 

 

為此,還需要定義一個ErrorController,當然還有與之對應的錯誤提示視圖:

using System.Web.Mvc;
 
namespace MvcApplication1.Controllers
{
    public class ErrorController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
 
        public ActionResult NotFound()
        {
            return View();
        }
 
    }
}
 

 

  使用ELMAH記錄全局異常

using System.Web.Mvc;
using Elmah;
 
namespace MvcApplication1.Extension
{
    public class ElmahHandleErrorAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            base.OnException(filterContext);
 
            if (filterContext.ExceptionHandled)
            {
                ErrorSignal.FromCurrentContext().Raise(filterContext.Exception);
            }
        }
    }
}
 

 

參考資料:
Exception Handling in ASP.NET MVC


免責聲明!

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



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