Páginas de error personalizadas en asp.net MVC3

Estoy desarrollando un sitio web base de MVC3 y estoy buscando una solución para manejar errores y renderizar vistas personalizadas para cada tipo de error. Así que imagina que tengo un controlador “Error” donde su acción principal es “Índice” (página de error genérica) y este controlador tendrá un par de acciones más para los errores que pueden aparecer al usuario como “Handle500” o “HandleActionNotFound”.

Por lo tanto, cada error que pueda ocurrir en el sitio web puede ser manejado por este Controlador de “Error” (ejemplos: “Controlador” o “Acción” no encontrados, 500, 404, dbException, etc.).

Estoy usando un archivo de sitemaps para definir las rutas del sitio web (y no la ruta).

Esta pregunta ya fue respondida, esta es una respuesta a Gweebz

Mi último método de applicaiton_error es el siguiente:

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

Aquí hay un ejemplo de cómo manejo los errores personalizados. ErrorsController un ErrorsController con acciones que manejan diferentes errores de 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"); } } 

y luego me suscribo al Application_Error en Global.asax e invoco este controlador:

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

Aquí hay más artículos Cómo crear páginas de error personalizadas con MVC http://kitsula.com/Article/MVC-Custom-Error-Pages .

También puede hacer esto en el archivo Web.Config. Aquí hay un ejemplo que funciona en IIS 7.5.

                        

Veo que agregó un valor de configuración para EnableCustomErrorPage y también está comprobando IsDebuggingEnabled para determinar si ejecutará o no el manejo de errores.

Dado que ya hay una en ASP.NET (que es exactamente para este propósito) es más fácil decir:

  protected void Application_Error() { if (HttpContext.Current == null) { // errors in Application_Start will end up here } else if (HttpContext.Current.IsCustomErrorEnabled) { // custom exception handling } } 

Luego, en la configuración pondría que es seguro para implementar así, y cuando necesite probar su página de error personalizada la establecería en para que pueda verificar que funciona.

Tenga en cuenta que también necesita comprobar si HttpContext.Current es nulo porque una excepción en Application_Start seguirá siendo su método aunque no habrá un contexto activo.

Puede visualizar una página de error fácil de usar con el código de estado HTTP correcto implementando el módulo de manejo de excepciones amigable de usuario de Jeff Atwood con una ligera modificación para el código de estado de http. Funciona sin redirecciones. Aunque el código es de 2004 (!), Funciona bien con MVC. Se puede configurar completamente en su web.config, sin ningún cambio en el código fuente del proyecto MVC.

La modificación requerida para devolver el estado HTTP original en lugar de un estado 200 se describe en esta publicación relacionada del foro .

Básicamente, en Handler.vb, puede agregar algo como:

 ' 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 

Estoy usando MVC 4.5 y tenía problemas con la solución de Darin. Nota: la solución de Darin es excelente y la usé para llegar a mi solución. Aquí está mi solución modificada:

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