C# ASP.NET MVC自定义错误处理应用程序\u Error Global.asax?
我有一些基本代码来确定MVC应用程序中的错误。目前,在我的项目中,我有一个名为C# ASP.NET MVC自定义错误处理应用程序\u Error Global.asax?,c#,asp.net,asp.net-mvc,error-handling,user-experience,C#,Asp.net,Asp.net Mvc,Error Handling,User Experience,我有一些基本代码来确定MVC应用程序中的错误。目前,在我的项目中,我有一个名为Error的控制器,其动作方法为HTTPError404(),HTTPError500(),以及General()。它们都接受字符串参数error。使用或修改下面的代码。 将数据传递给错误控制器进行处理的最佳/正确方法是什么?我希望有一个尽可能可靠的解决方案 protected void Application_Error(object sender, EventArgs e) { Exception exce
Error
的控制器,其动作方法为HTTPError404()
,HTTPError500()
,以及General()
。它们都接受字符串参数error
。使用或修改下面的代码。
将数据传递给错误控制器进行处理的最佳/正确方法是什么?我希望有一个尽可能可靠的解决方案
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?
}
}
您可以重定向到控制器/操作并通过querystring传递信息,而不是为此创建新路由。例如:
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);
}
您的方法有一些折衷之处。在这种错误处理中,要非常小心循环。另一件事是,由于您要通过asp.net管道来处理404,因此您将为所有这些点击创建一个会话对象。对于频繁使用的系统来说,这可能是一个问题(性能)。在MVC中处理错误的更好方法可能是将HandleError属性应用于控制器或操作,并更新Shared/Error.aspx文件以执行所需操作。该页面上的模型对象包括一个Exception属性以及ControllerName和ActionName。Application\u Ajax请求出现问题时出错。如果在Ajax调用的操作中处理了错误-它将在生成的容器中显示错误视图。要回答最初的问题“如何正确地将RoutedData传递给错误控制器?”: 然后在ErrorController类中,实现如下函数:
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult Error(Exception exception)
{
return View("Error", exception);
}
这会将异常推送到视图中。查看页面应声明如下:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<System.Exception>" %>
以前,我一直在努力将全局错误处理例程集中在MVC应用程序中。我有一本书
它基本上可以在global.asax中处理所有应用程序错误,而不需要错误控制器,也不需要使用
[handleerror]
属性进行装饰,也不需要在web.config中处理customErrors
节点 我找到了解决Lion_cl提到的ajax问题的方法
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();
}
}
错误页面控制器
public ActionResult AjaxGlobalError(string newActionName)
{
return new AjaxRedirectResult(Url.Action(newActionName), this.ControllerContext);
}
AjaxResult
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");
}
}
布莱恩,
这种方法适用于非Ajax请求,但正如Lion_cl所述,如果在Ajax调用过程中出现错误,您的Share/error.aspx视图(或自定义错误页面视图)将返回给Ajax调用方——用户将不会重定向到错误页面。使用以下代码在路由页面上重定向。 使用异常。异常的消息插入。因为异常查询字符串在扩展查询字符串长度时出错
routeData.Values.Add("error", exception.Message);
// clear error on server
Server.ClearError();
Response.RedirectToRoute(routeData.Values);
这可能不是MVC()的最佳方式 下面是如何在应用程序_错误中呈现视图并将其写入http响应。您不需要使用重定向。这将阻止对服务器的第二次请求,因此浏览器地址栏中的链接将保持不变。这可能是好的也可能是坏的,这取决于你想要什么 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>
}
@model HandleErrorInfo
@{
ViewBag.Title=“错误”;
//TODO:设置布局
}
ViewBag.ErrorMessage
@if(Model!=null&&HttpContext.Current.IsDebuggingEnabled)
{
异常:@Model.Exception.Message
控制器:@Model.ControllerName
操作:@Model.ActionName
@Model.Exception.StackTrace
}
我对这种错误处理方法有问题:
对于web.config:
Exception exception = Server.GetLastError();
Response.Clear();
HttpException httpException = exception as HttpException;
httpException始终为空
customErrors mode=“On”
:(
这是误导
然后
或
用户会看到customErrors html,
然后customErrors mode=“On”此代码也错误
此代码的另一个问题是
返回代码为302的页面,而不是实际错误代码(402403等)当你说“小心循环”时,你的确切意思是什么?有没有更好的方法来处理这种类型的错误重定向(假设它是一个使用量很大的系统)?我所说的循环是指当您的错误页面出现错误时,您会一次又一次地被重定向到错误页面…(例如,您希望将错误记录到数据库中,但它已关闭)。错误时重定向不符合web的体系结构。当服务器响应正确的HTTP状态代码时,URI应保持不变,以便客户端知道故障的确切上下文。实现HandleErrorAttribute.OneException或Controller.OneException是更好的解决方案。如果这些失败,则执行服务器.Transfer(“~/Error”)在Global.asax中。@Chris,这是可以接受的,但不是最佳做法。特别是因为它经常被重定向到一个带有HTTP 200状态码的资源文件,这让客户端认为一切正常。我不得不添加到web.config中,以便在服务器上工作。在实现此操作时,我遇到以下错误:“Syste”m、 Web.HttpRequest“不包含“IsAjaxRequest”的定义。本文有一个解决方案:您将如何处理
404
错误?因为没有指定用于该错误的控制器/操作?接受的答案包括404。此方法仅对500个错误有用。也许您应该将其编辑到您的答案中。可能是一个赌注ter处理错误的方法
听起来与所有错误非常相似,而不仅仅是500个错误。这是我认为最好的方法。这正是我想要的。@SteveHarris很高兴它有帮助!:)
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>
}
<customErrors mode="On"/>
Exception exception = Server.GetLastError();
Response.Clear();
HttpException httpException = exception as HttpException;
Response.Redirect(String.Format("~/Error/{0}/?message={1}", action, exception.Message));