tag route page net mvc for error data custom asp all asp.net asp.net-mvc asp.net-mvc-4

asp.net - route - tag helpers asp net core



Cómo hacer que las páginas de error personalizadas funcionen en ASP.NET MVC 4 (11)

Quiero una página de error personalizada para 500, 404 y 403. Esto es lo que he hecho:

  1. Se habilitaron los errores personalizados en el web.config de la siguiente manera:

    <customErrors mode="On" defaultRedirect="~/Views/Shared/Error.cshtml"> <error statusCode="403" redirect="~/Views/Shared/UnauthorizedAccess.cshtml" /> <error statusCode="404" redirect="~/Views/Shared/FileNotFound.cshtml" /> </customErrors>

  2. Se registró HandleErrorAttribute como un filtro de acción global en la clase FilterConfig la siguiente manera:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomHandleErrorAttribute()); filters.Add(new AuthorizeAttribute()); }

  3. Creó una página de error personalizada para cada uno de los mensajes anteriores. El predeterminado para 500 ya estaba disponible fuera de la caja.

  4. Se declara en cada vista de página de error personalizado que el modelo para la página es System.Web.Mvc.HandleErrorInfo

Para 500, muestra la página de error personalizada. Para otros, no es así.

¿Hay algo que este olvidando?

Parece que esto no es todo lo que hay para mostrar errores personalizados cuando leo el código en el método OnException de la clase HandleErrorAttribute y solo maneja 500.

¿Qué tengo que hacer para manejar otros errores?


Aquí está mi solución. Utilizar [ExportModelStateToTempData] / [ImportModelStateFromTempData] es incómodo en mi opinión.

~ / Vistas / Inicio / Error.cshtml:

@{ ViewBag.Title = "Error"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Error</h2> <hr/> <div style="min-height: 400px;"> @Html.ValidationMessage("Error") <br /> <br /> <button onclick="Error_goBack()" class="k-button">Go Back</button> <script> function Error_goBack() { window.history.back() } </script> </div>

~ / Controladores / HomeController.sc:

public class HomeController : BaseController { public ActionResult Index() { return View(); } public ActionResult Error() { return this.View(); } ... }

~ / Controladores / BaseController.sc:

public class BaseController : Controller { public BaseController() { } protected override void OnActionExecuted(ActionExecutedContext filterContext) { if (filterContext.Result is ViewResult) { if (filterContext.Controller.TempData.ContainsKey("Error")) { var modelState = filterContext.Controller.TempData["Error"] as ModelState; filterContext.Controller.ViewData.ModelState.Merge(new ModelStateDictionary() { new KeyValuePair<string, ModelState>("Error", modelState) }); filterContext.Controller.TempData.Remove("Error"); } } if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult)) { if (filterContext.Controller.ViewData.ModelState.ContainsKey("Error")) { filterContext.Controller.TempData["Error"] = filterContext.Controller.ViewData.ModelState["Error"]; } } base.OnActionExecuted(filterContext); } }

~ / Controladores / MyController.sc:

public class MyController : BaseController { public ActionResult Index() { return View(); } public ActionResult Details(int id) { if (id != 5) { ModelState.AddModelError("Error", "Specified row does not exist."); return RedirectToAction("Error", "Home"); } else { return View("Specified row exists."); } } }

Te deseo proyectos exitosos ;-)


En web.config agregue esto bajo la etiqueta system.webserver como se muestra a continuación,

<system.webServer> <httpErrors errorMode="Custom" existingResponse="Replace"> <remove statusCode="404"/> <remove statusCode="500"/> <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound"/> <error statusCode="500" responseMode="ExecuteURL"path="/Error/ErrorPage"/> </httpErrors>

y agregar un controlador como,

public class ErrorController : Controller { // // GET: /Error/ [GET("/Error/NotFound")] public ActionResult NotFound() { Response.StatusCode = 404; return View(); } [GET("/Error/ErrorPage")] public ActionResult ErrorPage() { Response.StatusCode = 500; return View(); } }

Y agregue sus opiniones respetadas, esto funcionará definitivamente, supongo para todos.

Esta solución la encontré en: Neptune Century


Hago algo que requiere menos codificación que las otras soluciones publicadas.

Primero, en mi web.config, tengo lo siguiente:

<customErrors mode="On" defaultRedirect="~/ErrorPage/Oops"> <error redirect="~/ErrorPage/Oops/404" statusCode="404" /> <error redirect="~/ErrorPage/Oops/500" statusCode="500" /> </customErrors>

Y el controlador (/Controllers/ErrorPageController.cs) contiene lo siguiente:

public class ErrorPageController : Controller { public ActionResult Oops(int id) { Response.StatusCode = id; return View(); } }

Y, finalmente, la vista contiene lo siguiente (simplificado, pero puede contener:

@{ ViewBag.Title = "Oops! Error Encountered"; } <section id="Page"> <div class="col-xs-12 well"> <table cellspacing="5" cellpadding="3" style="background-color:#fff;width:100%;" class="table-responsive"> <tbody> <tr> <td valign="top" align="left" id="tableProps"> <img width="25" height="33" src="~/Images/PageError.gif" id="pagerrorImg"> </td> <td width="360" valign="middle" align="left" id="tableProps2"> <h1 style="COLOR: black; FONT: 13pt/15pt verdana" id="errortype"><span id="errorText">@Response.Status</span></h1> </td> </tr> <tr> <td width="400" colspan="2" id="tablePropsWidth"><font style="COLOR: black; FONT: 8pt/11pt verdana">Possible causes:</font> </td> </tr> <tr> <td width="400" colspan="2" id="tablePropsWidth2"> <font style="COLOR: black; FONT: 8pt/11pt verdana" id="LID1"> <hr> <ul> <li id="list1"> <span class="infotext"> <strong>Baptist explanation: </strong>There must be sin in your life. Everyone else opened it fine.<br> </span> </li> <li> <span class="infotext"> <strong>Presbyterian explanation: </strong>It''s not God''s will for you to open this link.<br> </span> </li> <li> <span class="infotext"> <strong> Word of Faith explanation:</strong> You lack the faith to open this link. Your negative words have prevented you from realizing this link''s fulfillment.<br> </span> </li> <li> <span class="infotext"> <strong>Charismatic explanation: </strong>Thou art loosed! Be commanded to OPEN!<br> </span> </li> <li> <span class="infotext"> <strong>Unitarian explanation:</strong> All links are equal, so if this link doesn''t work for you, feel free to experiment with other links that might bring you joy and fulfillment.<br> </span> </li> <li> <span class="infotext"> <strong>Buddhist explanation:</strong> .........................<br> </span> </li> <li> <span class="infotext"> <strong>Episcopalian explanation:</strong> Are you saying you have something against homosexuals?<br> </span> </li> <li> <span class="infotext"> <strong>Christian Science explanation: </strong>There really is no link.<br> </span> </li> <li> <span class="infotext"> <strong>Atheist explanation: </strong>The only reason you think this link exists is because you needed to invent it.<br> </span> </li> <li> <span class="infotext"> <strong>Church counselor''s explanation:</strong> And what did you feel when the link would not open? </span> </li> </ul> <p> <br> </p> <h2 style="font:8pt/11pt verdana; color:black" id="ietext"> <img width="16" height="16" align="top" src="~/Images/Search.gif"> HTTP @Response.StatusCode - @Response.StatusDescription <br> </h2> </font> </td> </tr> </tbody> </table> </div> </section>

Es tan simple como eso. Podría extenderse fácilmente para ofrecer información de error más detallada, pero ELMAH encarga de eso, y el código de estado y estado es todo lo que necesito.


He hecho la solución pablo y siempre tuve el error (MVC4)

No se encontró la vista ''Error'' o su maestro o ningún motor de visualización admite la ubicación buscada.

Para deshacerse de esto, quita la línea.

filters.Add(new HandleErrorAttribute());

en FilterConfig.cs


Mi configuración actual (en MVC3, pero creo que todavía se aplica) se basa en tener un ErrorController , así que uso:

<system.web> <customErrors mode="On" defaultRedirect="~/Error"> <error redirect="~/Error/NotFound" statusCode="404" /> </customErrors> </system.web>

Y el controlador contiene lo siguiente:

public class ErrorController : Controller { public ViewResult Index() { return View("Error"); } public ViewResult NotFound() { Response.StatusCode = 404; //you may want to set this to 200 return View("NotFound"); } }

Y las vistas tal como las implementas. Sin embargo, tiendo a agregar un poco de lógica para mostrar el seguimiento de la pila y la información de error si la aplicación está en modo de depuración. Así que Error.cshtml se ve algo como esto:

@model System.Web.Mvc.HandleErrorInfo @{ Layout = "_Layout.cshtml"; ViewBag.Title = "Error"; } <div class="list-header clearfix"> <span>Error</span> </div> <div class="list-sfs-holder"> <div class="alert alert-error"> An unexpected error has occurred. Please contact the system administrator. </div> @if (Model != null && HttpContext.Current.IsDebuggingEnabled) { <div> <p> <b>Exception:</b> @Model.Exception.Message<br /> <b>Controller:</b> @Model.ControllerName<br /> <b>Action:</b> @Model.ActionName </p> <div style="overflow:scroll"> <pre> @Model.Exception.StackTrace </pre> </div> </div> } </div>


Parece que hay una serie de pasos aquí mezclados. Voy a presentar lo que hice desde cero.

  1. Crea el controlador ErrorPage

    public class ErrorPageController : Controller { public ActionResult Index() { return View(); } public ActionResult Oops(int id) { Response.StatusCode = id; return View(); } }

  2. Agregue vistas para estas dos acciones (clic derecho -> Agregar vista). Estos deben aparecer en una carpeta llamada ErrorPage.

  3. Dentro de App_Start abra FilterConfig.cs y comente el filtro de manejo de errores.

    public static void RegisterGlobalFilters(GlobalFilterCollection filters) { // Remove this filter because we want to handle errors ourselves via the ErrorPage controller //filters.Add(new HandleErrorAttribute()); }

  4. Dentro de web.config agregue las siguientes entradas <customerErrors> , bajo System.Web

    <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops"> <error redirect="~/ErrorPage/Oops/404" statusCode="404" /> <error redirect="~/ErrorPage/Oops/500" statusCode="500" /> </customErrors>

  5. Prueba (por supuesto). Lance una excepción no controlada en su código y véala ir a la página con id 500, y luego use una URL para una página que no existe para ver 404.


Parece que llegué tarde a la fiesta, pero deberías revisar esto también.

Así que en system.web para almacenar en caché las excepciones dentro de la aplicación, como devolver HttpNotFound ()

<system.web> <customErrors mode="RemoteOnly"> <error statusCode="404" redirect="/page-not-found" /> <error statusCode="500" redirect="/internal-server-error" /> </customErrors> </system.web>

y en system.webServer para recuperar los errores que fueron detectados por IIS y no se abrieron paso hacia el marco asp.net

<system.webServer> <httpErrors errorMode="DetailedLocalOnly"> <remove statusCode="404"/> <error statusCode="404" path="/page-not-found" responseMode="Redirect"/> <remove statusCode="500"/> <error statusCode="500" path="/internal-server-error" responseMode="Redirect"/> </system.webServer>

En la última, si te preocupa la respuesta del cliente, cambia el responseMode="Redirect" a responseMode="File" y entrega un archivo html estático, ya que este mostrará una página amigable con un código de respuesta 200.


Puede obtener errores funcionando correctamente sin hackear global.cs, desordenar con HandleErrorAttribute, haciendo Response.TrySkipIisCustomErrors, conectando Application_Error, o lo que sea:

En system.web (solo lo habitual, encendido / apagado)

<customErrors mode="On"> <error redirect="/error/401" statusCode="401" /> <error redirect="/error/500" statusCode="500" /> </customErrors>

y en system.webServer

<httpErrors existingResponse="PassThrough" />

Ahora las cosas deben comportarse como se espera y puede usar su ErrorController para mostrar lo que necesite.


Recomendaría utilizar el archivo Global.asax.cs.

protected void Application_Error(Object sender, EventArgs e) { var exception = Server.GetLastError(); if (exception is HttpUnhandledException) { Server.Transfer("~/Error.aspx"); } if (exception != null) { Server.Transfer("~/Error.aspx"); } try { // This is to stop a problem where we were seeing "gibberish" in the // chrome and firefox browsers HttpApplication app = sender as HttpApplication; app.Response.Filter = null; } catch { } }


Sobre la base de la respuesta publicada por maxspan, he reunido un proyecto de muestra mínima en GitHub que muestra todas las partes de trabajo.

Básicamente, solo agregamos un método Application_Error a global.asax.cs para interceptar la excepción y nos da la oportunidad de redirigir (o más correctamente, transferir la solicitud ) a una página de error personalizada.

protected void Application_Error(Object sender, EventArgs e) { // See http://.com/questions/13905164/how-to-make-custom-error-pages-work-in-asp-net-mvc-4 // for additional context on use of this technique var exception = Server.GetLastError(); if (exception != null) { // This would be a good place to log any relevant details about the exception. // Since we are going to pass exception information to our error page via querystring, // it will only be practical to issue a short message. Further detail would have to be logged somewhere. // This will invoke our error page, passing the exception message via querystring parameter // Note that we chose to use Server.TransferRequest, which is only supported in IIS 7 and above. // As an alternative, Response.Redirect could be used instead. // Server.Transfer does not work (see https://support.microsoft.com/en-us/kb/320439 ) Server.TransferRequest("~/Error?Message=" + exception.Message); } }

Controlador de error:

/// <summary> /// This controller exists to provide the error page /// </summary> public class ErrorController : Controller { /// <summary> /// This action represents the error page /// </summary> /// <param name="Message">Error message to be displayed (provided via querystring parameter - a design choice)</param> /// <returns></returns> public ActionResult Index(string Message) { // We choose to use the ViewBag to communicate the error message to the view ViewBag.Message = Message; return View(); } }

Página de error Ver:

<!DOCTYPE html> <html> <head> <title>Error</title> </head> <body> <h2>My Error</h2> <p>@ViewBag.Message</p> </body> </html>

No hay nada más involucrado, aparte de deshabilitar / eliminar filters.Add(new HandleErrorAttribute()) en FilterConfig.cs

public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); // <== disable/remove } }

Aunque es muy sencillo de implementar, el único inconveniente que veo en este enfoque es el uso de cadenas de consulta para entregar información de excepción a la página de error de destino.


Tenía todo configurado, pero aún no podía ver las páginas de error adecuadas para el código de estado 500 en nuestro servidor de pruebas, a pesar de que todo funcionaba bien en los servidores de desarrollo local.

Encontré esta publicación de blog de Rick Strahl que me ayudó.

Necesitaba agregar Response.TrySkipIisCustomErrors = true; a mi código de manejo de errores personalizado.