MVC自定義錯誤頁面
阿新 • • 發佈:2017-08-15
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=31BF3856AD364E35Web.Config" /> <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>
@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自定義錯誤頁面