1. 程式人生 > >MVC自定義錯誤頁面

MVC自定義錯誤頁面

scu ebp name lte timeout sts form -m 技術

  MVC異常處理主要有三種方案:1.基於HandleErrorAttribute重寫OnException方法;2.基於Global.apsx添加Application_Error方法;3.直接在Web.Config中配置。現基於上述思路,測試了下面三種自定義錯誤頁面的處理方法(主要側重於顯示異常信息,便於快速找到代碼中的異常來源),以便後續查閱。不足之處,還請指教!

1.直接在web.config的<system.web>節點下加入<customErrors mode="On" />,在View/Shared/Error.cshtml中寫入異常信息,發生異常時會跳轉到該l頁面。

技術分享
  <system.web>
    <customErrors mode="On" />
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35
" /> <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35
" /> </assemblies> </compilation> <authentication mode="Forms"> <forms loginUrl="~/Account/LogOn" timeout="2880" /> </authentication> <pages> <namespaces> <add namespace="System.Web.Helpers" /> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="System.Web.WebPages"/> </namespaces> </pages> </system.web>
Web.Config 技術分享
@model HandleErrorInfo
@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <title>Error</title>
</head>
<body>
    <p>Message: @Model.Exception.Message</p>
    <p>Controller: @Model.ControllerName</p>
    <p>Action: @Model.ActionName</p>
    <p>Source: @Model.Exception.Source</p>
    <p>Exception: @Model.Exception</p>
</body>
</html>
Error.html

2.新建類繼承HandleErrorAttribute並重寫OnException方法,將異常信息寫入日誌文件,並跳轉到View/Shared/Error.cshtml錯誤頁。直接將該屬性作用於某控制器或者註冊為全局變量以便於全局適用。

技術分享
    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
    public class LogExceptionAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            string controllerName = (string)filterContext.RouteData.Values["controller"];
            string actionName = (string)filterContext.RouteData.Values["action"];
            HandleErrorInfo info = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

            Log log = new Log();
            log.Write(filterContext);

            if (!filterContext.ExceptionHandled)
            {

                filterContext.Result = new ViewResult() 
                {
                    ViewName = "/Views/Shared/Error.cshtml",
                    ViewData = new ViewDataDictionary<HandleErrorInfo>(info)
                };
                filterContext.ExceptionHandled = true;
                filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            }
        }
    }
LogExceptionAttribute

錯誤頁寫入異常信息與方法1相同。

技術分享
   [LogException]
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            var x=1;
            string y="x";
            ViewBag.t = x / Convert.ToInt32(y);
            return View();
        }
    }
作用於單一控制器 技術分享
 public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            //new 
            filters.Add(new LogExceptionAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // 路由名稱
                "{controller}/{action}/{id}", // 帶有參數的 URL
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 參數默認值
            );

        }

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    }
特性註冊

3.新建繼承於IController的基礎控制器,重寫OnException方法及寫入異常日誌文件,其他控制器只需要繼承該基礎控制器即可。與方法3的區別在於不需要註冊全局篩選器取而代之的是控制器的繼承。

技術分享
public class BaseController : Controller
    {
        protected override void OnException(ExceptionContext filterContext)
        {
            string controllerName = (string)filterContext.RouteData.Values["controller"];
            string actionName = (string)filterContext.RouteData.Values["action"];
            HandleErrorInfo info = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

            DateTime dt = DateTime.Now;
            string logPath = Server.MapPath("~/Logs/" + dt.ToString("yyyy-MM"));
            if (!Directory.Exists(logPath))
            {
                Directory.CreateDirectory(logPath);
            }
            string logFilePath = string.Format("{0}/{1}.txt", logPath, dt.ToString("yyyy-MM-dd"));
            StreamWriter writer = null;
            try
            {
                writer = new StreamWriter(logFilePath, true, Encoding.UTF8);
                writer.WriteLine("------------------------------------------------------------------------------");
                writer.WriteLine("出錯時間:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                writer.WriteLine("錯誤信息:" + filterContext.Exception.Message);
                writer.WriteLine("Controller:" + filterContext.Controller);
                writer.WriteLine("錯誤源:" + filterContext.Exception.Source);
                writer.WriteLine("堆棧信息:" + filterContext.Exception.StackTrace);
                writer.WriteLine("------------------------------------------------------------------------------");
            }
            catch
            {
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                }
            }
            base.OnException(filterContext);
            filterContext.Result = new ViewResult() 
            {
                ViewName = "/Views/Shared/Error.cshtml",
                ViewData = new ViewDataDictionary<HandleErrorInfo>(info)
            };
        }

        public ActionResult Error()
        {
            return View();
        }
    }
基礎控制器實現 技術分享
 public class HomeController : BaseController
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            var x=1;
            string y="x";
            ViewBag.t = x / Convert.ToInt32(y);
            return View();
        }
    }
控制器繼承

備註:異常日誌記錄類

技術分享
public class Log
    {
        /// <summary>
        /// 異常信息記錄
        /// </summary>
        /// <param name="filterContext"></param>
        public void Write(ExceptionContext filterContext)
        {
            DateTime dt = DateTime.Now;
            string logPath = HttpContext.Current.Server.MapPath("~/Logs/" + dt.ToString("yyyy-MM"));
            if (!Directory.Exists(logPath))
            {
                Directory.CreateDirectory(logPath);
            }
            string logFilePath = string.Format("{0}/{1}.txt", logPath, dt.ToString("yyyy-MM-dd"));
            StreamWriter writer = null;
            try
            {
                writer = new StreamWriter(logFilePath, true, Encoding.UTF8);
                writer.WriteLine("------------------------------------------------------------------------------");
                writer.WriteLine("出錯時間:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                writer.WriteLine("錯誤信息:" + filterContext.Exception.Message);
                writer.WriteLine("Controller:" + filterContext.Controller);
                writer.WriteLine("錯誤源:" + filterContext.Exception.Source);
                writer.WriteLine("堆棧信息:" + filterContext.Exception.StackTrace);
                writer.WriteLine("------------------------------------------------------------------------------");
            }
            catch
            {
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                }
            }
        }
    }
Log

4.還可以通過Global.apsx添加Application_Error方法來實現,但實驗過程中不怎麽喜歡這種方案,故省略。

MVC自定義錯誤頁面