template rendersection renderbody net mvc cshtml asp _layout asp.net-mvc-3 error-handling

asp.net mvc 3 - rendersection - Páginas de error personalizadas en asp.net MVC3



razor if (6)

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


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


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


También puede hacer esto en el archivo Web.Config. Aquí hay un ejemplo que funciona en 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>


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 <customErrors/> 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 <customErrors mode="RemoteOnly" /> que es seguro para implementar así, y cuando necesite probar su página de error personalizada la establecería en <customErrors mode="On" /> 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.