• 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

  • 相关阅读:
    学生成绩判定系统
    A@2a139a55 结果产生的原因
    为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来?
    父类与子类之间构造方法的调用关系
    阅读《大道至简》第六章有感
    大数加法 待完善
    BigInteger大数加法源代码及分析
    随机数组求和
    读《大道至简》第五章“失败的过程也是过程 ”有感
    学习进度第15周
  • 原文地址:https://www.cnblogs.com/darrenji/p/3754255.html
Copyright © 2020-2023  润新知