ASP.NET MVC自定义error handlingApplication_Error Global.asax?

我有一些基本的代码来确定我的MVC应用程序中的错误。 目前在我的项目中,我有一个名为Error与控制器的操作方法HTTPError404()HTTPError500()General() 。 他们都接受一个string参数error 。 使用或修改下面的代码。 将数据传递给错误控制器进行处理的最佳方式是什么? 我希望有一个可靠的解决scheme。

 protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); Response.Clear(); HttpException httpException = exception as HttpException; if (httpException != null) { RouteData routeData = new RouteData(); routeData.Values.Add("controller", "Error"); switch (httpException.GetHttpCode()) { case 404: // page not found routeData.Values.Add("action", "HttpError404"); break; case 500: // server error routeData.Values.Add("action", "HttpError500"); break; default: routeData.Values.Add("action", "General"); break; } routeData.Values.Add("error", exception); // clear error on server Server.ClearError(); // at this point how to properly pass route data to error controller? } } 

而不是创build一个新的路线,你可以redirect到你的控制器/行动,并通过查询string传递信息。 例如:

 protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); Response.Clear(); HttpException httpException = exception as HttpException; if (httpException != null) { string action; switch (httpException.GetHttpCode()) { case 404: // page not found action = "HttpError404"; break; case 500: // server error action = "HttpError500"; break; default: action = "General"; break; } // clear error on server Server.ClearError(); Response.Redirect(String.Format("~/Error/{0}/?message={1}", action, exception.Message)); } 

那么你的控制器会收到你想要的东西:

 // GET: /Error/HttpError404 public ActionResult HttpError404(string message) { return View("SomeView", message); } 

你的方法有一些权衡。 在这种error handling循环中要非常小心。 还有一件事是因为你正在通过asp.netpipe道来处理一个404,你将为所有这些命中创build一个会话对象。 对于大量使用的系统,这可能是一个问题(性能)。

回答最初的问题:“如何正确地将routedata传递给错误控制器?”:

 IController errorController = new ErrorController(); errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData)); 

然后在你的ErrorController类中,实现一个像这样的函数:

 [AcceptVerbs(HttpVerbs.Get)] public ViewResult Error(Exception exception) { return View("Error", exception); } 

这将exception推入视图。 视图页面应该声明如下:

 <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<System.Exception>" %> 

并显示错误的代码:

 <% if(Model != null) { %> <p><b>Detailed error:</b><br /> <span class="error"><%= Helpers.General.GetErrorMessage((Exception)Model, false) %></span></p> <% } %> 

以下是从exception树中收集所有exception消息的函数:

  public static string GetErrorMessage(Exception ex, bool includeStackTrace) { StringBuilder msg = new StringBuilder(); BuildErrorMessage(ex, ref msg); if (includeStackTrace) { msg.Append("\n"); msg.Append(ex.StackTrace); } return msg.ToString(); } private static void BuildErrorMessage(Exception ex, ref StringBuilder msg) { if (ex != null) { msg.Append(ex.Message); msg.Append("\n"); if (ex.InnerException != null) { BuildErrorMessage(ex.InnerException, ref msg); } } } 

我find了Lion_cllogging的ajax问题的解决scheme。

Global.asax中:

 protected void Application_Error() { if (HttpContext.Current.Request.IsAjaxRequest()) { HttpContext ctx = HttpContext.Current; ctx.Response.Clear(); RequestContext rc = ((MvcHandler)ctx.CurrentHandler).RequestContext; rc.RouteData.Values["action"] = "AjaxGlobalError"; // TODO: distinguish between 404 and other errors if needed rc.RouteData.Values["newActionName"] = "WrongRequest"; rc.RouteData.Values["controller"] = "ErrorPages"; IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory(); IController controller = factory.CreateController(rc, "ErrorPages"); controller.Execute(rc); ctx.Server.ClearError(); } } 

ErrorPagesController

 public ActionResult AjaxGlobalError(string newActionName) { return new AjaxRedirectResult(Url.Action(newActionName), this.ControllerContext); } 

AjaxRedirectResult

 public class AjaxRedirectResult : RedirectResult { public AjaxRedirectResult(string url, ControllerContext controllerContext) : base(url) { ExecuteResult(controllerContext); } public override void ExecuteResult(ControllerContext context) { if (context.RequestContext.HttpContext.Request.IsAjaxRequest()) { JavaScriptResult result = new JavaScriptResult() { Script = "try{history.pushState(null,null,window.location.href);}catch(err){}window.location.replace('" + UrlHelper.GenerateContentUrl(this.Url, context.HttpContext) + "');" }; result.ExecuteResult(context); } else { base.ExecuteResult(context); } } } 

AjaxRequestExtension

 public static class AjaxRequestExtension { public static bool IsAjaxRequest(this HttpRequest request) { return (request.Headers["X-Requested-With"] != null && request.Headers["X-Requested-With"] == "XMLHttpRequest"); } } 

我以前在MVC应用程序中集中全局error handling例程的想法挣扎。 我在ASP.NET论坛上有一个post 。

它基本上处理global.asax中的所有应用程序错误,而不需要错误控制器,用[HandlerError]属性装饰,或者用web.config中的customErrors节点来摆弄。

也许在MVC中处理错误的一个更好的方法是将HandleError属性应用到您的控制器或操作,并更新Shared / Error.aspx文件来执行您想要的操作。 该页面上的Model对象包含一个Exception属性以及ControllerName和ActionName。

Application_Error对Ajax请求有问题。 如果在由Ajax调用的Action中处理错误 – 它将在生成的容器中显示错误视图。

Brian,这种方法对于非Ajax请求非常有用,但是如Lion_cl所述,如果在Ajax调用期间出现错误,则您的Share / Error.aspx视图(或您的自定义错误页面视图)将返回给Ajax调用者 – 用户不会被redirect到错误页面。

这可能不是MVC的最佳方式( https://stackoverflow.com/a/9461386/5869805

以下是在Application_Error中呈现视图并将其写入http响应的方法。 你不需要使用redirect。 这将阻止对服务器的第二个请求,所以浏览器的地址栏中的链接将保持不变。 这可能是好的或坏的,这取决于你想要什么。

的Global.asax.cs

 protected void Application_Error() { var exception = Server.GetLastError(); // TODO do whatever you want with exception, such as logging, set errorMessage, etc. var errorMessage = "SOME FRIENDLY MESSAGE"; // TODO: UPDATE BELOW FOUR PARAMETERS ACCORDING TO YOUR ERROR HANDLING ACTION var errorArea = "AREA"; var errorController = "CONTROLLER"; var errorAction = "ACTION"; var pathToViewFile = $"~/Areas/{errorArea}/Views/{errorController}/{errorAction}.cshtml"; // THIS SHOULD BE THE PATH IN FILESYSTEM RELATIVE TO WHERE YOUR CSPROJ FILE IS! var requestControllerName = Convert.ToString(HttpContext.Current.Request.RequestContext?.RouteData?.Values["controller"]); var requestActionName = Convert.ToString(HttpContext.Current.Request.RequestContext?.RouteData?.Values["action"]); var controller = new BaseController(); // REPLACE THIS WITH YOUR BASE CONTROLLER CLASS var routeData = new RouteData { DataTokens = { { "area", errorArea } }, Values = { { "controller", errorController }, {"action", errorAction} } }; var controllerContext = new ControllerContext(new HttpContextWrapper(HttpContext.Current), routeData, controller); controller.ControllerContext = controllerContext; var sw = new StringWriter(); var razorView = new RazorView(controller.ControllerContext, pathToViewFile, "", false, null); var model = new ViewDataDictionary(new HandleErrorInfo(exception, requestControllerName, requestActionName)); var viewContext = new ViewContext(controller.ControllerContext, razorView, model, new TempDataDictionary(), sw); viewContext.ViewBag.ErrorMessage = errorMessage; //TODO: add to ViewBag what you need razorView.Render(viewContext, sw); HttpContext.Current.Response.Write(sw); Server.ClearError(); HttpContext.Current.Response.End(); // No more processing needed (ex: by default controller/action routing), flush the response out and raise EndRequest event. } 

视图

 @model HandleErrorInfo @{ ViewBag.Title = "Error"; // TODO: SET YOUR LAYOUT } <div class=""> ViewBag.ErrorMessage </div> @if(Model != null && HttpContext.Current.IsDebuggingEnabled) { <div class="" style="background:khaki"> <p> <b>Exception:</b> @Model.Exception.Message <br/> <b>Controller:</b> @Model.ControllerName <br/> <b>Action:</b> @Model.ActionName <br/> </p> <div> <pre> @Model.Exception.StackTrace </pre> </div> </div> } 

使用下面的代码在路由页面上redirect。 使用exception.Message引发exception。 如果扩展查询string长度,则Cozexception查询string会发生错误。

 routeData.Values.Add("error", exception.Message); // clear error on server Server.ClearError(); Response.RedirectToRoute(routeData.Values); 

我有这个error handling方法的问题:在web.config的情况下:

 <customErrors mode="On"/> 

error handling程序正在search视图Error.shtml和控制stream步骤中的Application_Error global.asax只有在exception之后

System.InvalidOperationException:视图'错误'或其主人没有被发现或没有视图引擎支持search的位置。 search到以下位置:〜/ Views / home / Error.aspx〜/ Views / home / Error.ascx〜/ Views / Shared / Error.aspx〜/ Views / Shared / Error.ascx〜/ Views / home / Error。 cshtml〜/ Views / home / Error.vbhtml〜/ Views / Shared / Error.cshtml〜/ Views / Shared / Error.vbhtml at System.Web.Mvc.ViewResult.FindView(ControllerContext context)…….. …………

所以

  Exception exception = Server.GetLastError(); Response.Clear(); HttpException httpException = exception as HttpException; 

httpException总是为空然后customErrors mode =“On”:(这是误导然后<customErrors mode="Off"/>或者<customErrors mode="RemoteOnly"/>用户看到customErrors html,然后customErrors mode =“On”代码也是错误的


这个代码的另一个问题

 Response.Redirect(String.Format("~/Error/{0}/?message={1}", action, exception.Message)); 

用代码302返回页面,而不是真正的错误代码(402,403等)