我正在开发一个MVC3基础网站,我正在寻找处理错误的解决方案,并为每种错误渲染自定义视图。因此,假设我有一个“错误”控制器,其主要操作是“索引”(通用错误页面),并且此控制器将针对用户可能出现的错误(如“Handle500”或“HandleActionNotFound”)执行更多操作。
因此,网站上可能发生的每个错误都可能由此“错误”控制器处理(例如:“Controller”或“Action”未找到,500,404,dbException等)。
我使用Sitemap文件来定义网站路径(而不是路由)。
这个问题已经回答了,这是对Gweebz的回复
我的最终applicaiton_error方法如下:
protected void Application_Error() {
//while my project is running in debug mode
if (HttpContext.Current.IsDebuggingEnabled && WebConfigurationManager.AppSettings["EnableCustomErrorPage"].Equals("false"))
{
Log.Logger.Error("unhandled exception: ", Server.GetLastError());
}
else
{
try
{
var exception = Server.GetLastError();
Log.Logger.Error("unhandled exception: ", exception);
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
IController errorsController = new ErrorsController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
catch (Exception e)
{
//if Error controller failed for same reason, we will display static HTML error page
Log.Logger.Fatal("failed to display error page, fallback to HTML error: ", e);
Response.TransmitFile("~/error.html");
}
}
}
答案 0 :(得分:201)
以下是我如何处理自定义错误的示例。我定义了ErrorsController
,其中包含处理不同HTTP错误的操作:
public class ErrorsController : Controller
{
public ActionResult General(Exception exception)
{
return Content("General failure", "text/plain");
}
public ActionResult Http404()
{
return Content("Not found", "text/plain");
}
public ActionResult Http403()
{
return Content("Forbidden", "text/plain");
}
}
然后我订阅Application_Error
中的Global.asax
并调用此控制器:
protected void Application_Error()
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 403:
routeData.Values["action"] = "Http403";
break;
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
IController errorsController = new ErrorsController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
答案 1 :(得分:18)
以下是更多文章如何使用MVC http://kitsula.com/Article/MVC-Custom-Error-Pages创建自定义错误页面。
答案 2 :(得分:6)
您也可以在Web.Config文件中执行此操作。这是一个适用于IIS 7.5的示例。
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File">
<remove statusCode="502" subStatusCode="-1" />
<remove statusCode="501" subStatusCode="-1" />
<remove statusCode="412" subStatusCode="-1" />
<remove statusCode="406" subStatusCode="-1" />
<remove statusCode="405" subStatusCode="-1" />
<remove statusCode="404" subStatusCode="-1" />
<remove statusCode="403" subStatusCode="-1" />
<remove statusCode="401" subStatusCode="-1" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="/notfound.html" responseMode="ExecuteURL" />
<error statusCode="401" prefixLanguageFilePath="" path="/500.html" responseMode="ExecuteURL" />
<error statusCode="403" prefixLanguageFilePath="" path="/403.html" responseMode="ExecuteURL" />
<error statusCode="404" prefixLanguageFilePath="" path="/404.html" responseMode="ExecuteURL" />
<error statusCode="405" prefixLanguageFilePath="" path="/405.html" responseMode="ExecuteURL" />
<error statusCode="406" prefixLanguageFilePath="" path="/406.html" responseMode="ExecuteURL" />
<error statusCode="412" prefixLanguageFilePath="" path="/412.html" responseMode="ExecuteURL" />
<error statusCode="501" prefixLanguageFilePath="" path="/501.html" responseMode="ExecuteURL" />
<error statusCode="502" prefixLanguageFilePath="" path="/genericerror.html" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
答案 3 :(得分:3)
我看到您为EnableCustomErrorPage
添加了配置值,并且您还在检查IsDebuggingEnabled
以确定是否运行错误处理。
由于ASP.NET中已有<customErrors/>
配置(完全是出于此目的),因此最简单的说法是:
protected void Application_Error()
{
if (HttpContext.Current == null)
{
// errors in Application_Start will end up here
}
else if (HttpContext.Current.IsCustomErrorEnabled)
{
// custom exception handling
}
}
然后在配置中,您可以放置<customErrors mode="RemoteOnly" />
,这样可以安全部署,当您需要测试自定义错误页面时,您可以将其设置为<customErrors mode="On" />
,这样您就可以验证它有效。
请注意,您还需要检查HttpContext.Current
是否为空,因为Application_Start
中的异常仍然是他的此方法,尽管不存在活动上下文。
答案 4 :(得分:2)
您可以通过实施Jeff Atwood的User Friendly Exception Handling module并稍微修改http状态代码来显示包含正确http状态代码的用户友好错误页面。它没有任何重定向工作。虽然代码来自2004(!),但它适用于MVC。它可以完全在您的web.config中配置,根本不会更改MVC项目源代码。
this related forum post中描述了返回原始HTTP状态而非200
状态所需的修改。
基本上,在Handler.vb中,您可以添加以下内容:
' In the header...
Private _exHttpEx As HttpException = Nothing
' At the top of Public Sub HandleException(ByVal ex As Exception)...
HttpContext.Current.Response.StatusCode = 500
If TypeOf ex Is HttpException Then
_exHttpEx = CType(ex, HttpException)
HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode()
End If
答案 5 :(得分:0)
我正在使用MVC 4.5而且我遇到了Darin解决方案的问题。注意:Darin的解决方案很棒,我用它来提出我的解决方案。 这是我修改过的解决方案:
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.StatusCode = httpException.GetHttpCode();
Response.Clear();
Server.ClearError();
if (httpException != null)
{
var httpContext = HttpContext.Current;
httpContext.RewritePath("/Errors/InternalError", false);
// MVC 3 running on IIS 7+
if (HttpRuntime.UsingIntegratedPipeline)
{
switch (Response.StatusCode)
{
case 403:
httpContext.Server.TransferRequest("/Errors/Http403", true);
break;
case 404:
httpContext.Server.TransferRequest("/Errors/Http404", true);
break;
default:
httpContext.Server.TransferRequest("/Errors/InternalError", true);
break;
}
}
else
{
switch (Response.StatusCode)
{
case 403:
httpContext.RewritePath(string.Format("/Errors/Http403", true));
break;
case 404:
httpContext.RewritePath(string.Format("/Errors/Http404", true));
break;
default:
httpContext.RewritePath(string.Format("/Errors/InternalError", true));
break;
}
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(httpContext);
}
}
}