Asp.net MVC3上的自定义错误页面

我正在开发一个 MVC3的基础网站,我正在寻找一个解决方案,处理错误和渲染自定义视图的每一种错误。所以假设我有一个“ Error”控制器,它的主要操作是“ Index”(通用错误页面) ,这个控制器对于可能出现在用户面前的错误(如“ Handle500”或“ HandleActionNotfound”)将有几个更多的操作。

因此,网站上可能发生的每个错误都可以由这个“ Error”控制器来处理(例如: “ Controller”或“ Action”not found,500,404,dbException 等)。

我使用 Sitemap 文件来定义网站路径(而不是路由)。

这个问题已经被回答了,这是对 Gweebz 的回答

我的最后一个 application _ 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");
}
}
}
57093 次浏览

下面是我如何处理自定义错误的一个例子,我定义了一个 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");
}
}

然后我订阅 Global.asax中的 Application_Error并调用这个控制器:

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);
}

这里有更多的文章如何用 MVC http://kitsula.com/Article/MVC-Custom-Error-Pages创建自定义错误页面。

你可以用正确的 HTTP状态码显示一个用户友好的错误页面,只需稍微修改一下 HTTP状态码。它不需要任何重定向。虽然代码来自2004(!),它与 MVC 很好地工作。它可以完全在 web.config 中配置,根本不需要更改 MVC 项目的源代码。

返回原始 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

您也可以在 Web.Config 文件中执行此操作。

     <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>

我看到您为 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是否为 null,因为 Application_Start中的异常将仍然是他的这个方法,尽管没有活动上下文。

我用的是 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);
}
}
}