Enrutamiento para la página de error ASP.NET MVC 404 personalizada

116

Estoy tratando de crear una página de error HTTP 404 personalizada cuando alguien escribe una URL que no invoca una acción o controlador válido en ASP.NET MVC, en lugar de mostrar el error genérico de ASP.NET "Recurso no encontrado".

No quiero usar web.config para manejar esto.

¿Existe algún tipo de magia de enrutamiento que pueda hacer para detectar URL no válidas?

Actualización: probé la respuesta dada, sin embargo, todavía recibo el feo mensaje "Recurso no encontrado".

Otra actualización: Ok, aparentemente algo cambió en RC1. Incluso he intentado capturar específicamente 404 en un HttpExceptiony todavía me da la página "Recurso no encontrado".

Incluso he usado la función de recursos de MvcContrib y nada, el mismo problema. ¿Algunas ideas?

dswatik
fuente
@Peter Esa es la solución que agregué junto con la anulación de HandleUnknownAction para mostrar una vista de página no encontrada cuando una acción no existe y luego el controlador de errores personalizado ASP.net integrado para manejar cualquier otra cosa que los usuarios puedan escribir .
dswatik
@pete Esto también funciona stackoverflow.com/questions/619895/…
dswatik
8
Odio cuando otros usuarios son presuntuosos y dicen cosas como, "¿por qué querrías hacer eso? Simplemente haz esto ..." Pero te sugiero que si no hay nada que te impida usar el enfoque web.config y satisface sus necesidades, es un enfoque estándar y elegante. Se agradece cualquier comentario sobre ese enfoque, ya que podría haber algún problema con él que no conozco.
Sean

Respuestas:

10

Simplemente agregue capturar todas las rutas al final de la tabla de rutas y muestre la página que desee con ella.

Ver: ¿Cómo puedo hacer una captura de todas las rutas para manejar consultas de 'página 404 no encontrada' para ASP.NET MVC?

Alex Reitbort
fuente
Intenté esto, sin embargo, todavía obtengo el feo mensaje predeterminado de recurso no encontrado de ASP.NET ..
dswatik
3
No encuentro una solución definitiva (¡y flexible!) A este problema ni en esta respuesta ni en el enlace proporcionado.
Peter
4
Yo tampoco ... esto parece una especie de respuesta hacky. Estoy buscando más una forma de hacer que customErrors se comporte como lo hacen en WebForms. ¿Algunas ideas?
JC Grubbs
1
Esto no funciona y es malo en principio. No funciona porque no detectará URL incorrectas que coincidan con uno de los patrones de enrutamiento anteriores. Malo en principio porque convierte lo que debería ser un error en no un error. Redirigir a una página que ha llamado "Error" es diferente a redirigir a una página de error. Desea guardarlo como un error, registrar el error y luego manejarlo como un error. Los errores son información valiosa.
Mateo
105

Intenté habilitar errores personalizados en el servidor de producción durante 3 horas, parece que encontré una solución final sobre cómo hacer esto en ASP.NET MVC sin ninguna ruta.

Para habilitar errores personalizados en la aplicación ASP.NET MVC, necesitamos (IIS 7+):

  1. Configure páginas personalizadas en la configuración web en la system.websección:

    <customErrors mode="RemoteOnly"  defaultRedirect="~/error">
        <error statusCode="404" redirect="~/error/Error404" />
        <error statusCode="500" redirect="~/error" />
    </customErrors>

    RemoteOnlysignifica que en la red local verá errores reales (muy útiles durante el desarrollo). También podemos reescribir la página de error para cualquier código de error.

  2. Establecer el parámetro de respuesta mágica y el código de estado de respuesta (en el módulo de manejo de errores o en el atributo de manejo de errores)

      HttpContext.Current.Response.StatusCode = 500;
      HttpContext.Current.Response.TrySkipIisCustomErrors = true;
  3. Establezca otra configuración mágica en la configuración web en la system.webServersección:

    <httpErrors errorMode="Detailed" />

Esto fue lo último que encontré y después de esto puedo ver errores personalizados en el servidor de producción.

Andrew Orsich
fuente
8
Esta todavía no es una solución ideal. No obtiene los códigos de respuesta HTTP adecuados. El uso de customErrorsresultados en una redirección 302 solo para cargar su página de error.
Justin Helgerson
@ Ek0nomik Nunca he visto soluciones ideales :)
Andrew Orsich
2
@JustinHelgerson Configuré un ErrorController para cada código de estado y configuré los Códigos de respuesta dentro de esas acciones y establece los códigos de respuesta bien. Probé con Fiddler y los códigos de estado 404 responden con un 404 y las páginas con 500 errores responden con un 500. Y en ambos casos se muestran mis vistas de error personalizadas
Shane Neuville
mi compañero de equipo acaba de eliminar la vista de error en la carpeta compartida , para realizar un error de tiempo de ejecución con el código de estado 500 para redirigir a la página de error personalizada como se menciona aquí y aquí . La esperanza ayuda a alguien.
shaijut
41

Conseguí que mi manejo de errores funcionara creando un ErrorController que devuelve las vistas en este artículo. También tuve que agregar "Catch All" a la ruta en global.asax.

No veo cómo llegará a cualquiera de estas páginas de error si no está en Web.config ..? Mi Web.config tuvo que especificar:

customErrors mode="On" defaultRedirect="~/Error/Unknown"

y luego también agregué:

error statusCode="404" redirect="~/Error/NotFound"
Jack Smit
fuente
2
Gracias, ¡eso me ayudó, 2 años después! ¿Qué haces si solo quieres un error personalizado para 404, nada más?
Shaul Behr
1
@Shaul otro año después ... no establezca el defaultRedirect, excluya el atributo por completo.
NJE
27

Fuente

NotFoundMVC : proporciona una página 404 fácil de usar cuando no se encuentra un controlador, una acción o una ruta en su aplicación ASP.NET MVC3. Se representa una vista llamada NotFound en lugar de la página de error de ASP.NET predeterminada.

Puede agregar este complemento a través de nuget usando: Install-Package NotFoundMvc

NotFoundMvc se instala automáticamente durante el inicio de la aplicación web. Maneja todas las diferentes formas en que ASP.NET MVC generalmente lanza una HttpException 404. Esto incluye un controlador, una acción y una ruta que faltan.

Guía de instalación paso a paso:

1 - Haga clic con el botón derecho en su proyecto y seleccione Administrar paquetes Nuget ...

2 - Búscalo NotFoundMvce instálalo. ingrese la descripción de la imagen aquí

3 - Una vez completada la instalación, se agregarán dos archivos a su proyecto. Como se muestra en las capturas de pantalla a continuación.

ingrese la descripción de la imagen aquí

4 - Abra el NotFound.cshtml recién agregado presente en Views / Shared y modifíquelo a su gusto. Ahora ejecute la aplicación y escriba una URL incorrecta, y será recibido con una página 404 fácil de usar.

ingrese la descripción de la imagen aquí

No más, los usuarios recibirán mensajes de error como Server Error in '/' Application. The resource cannot be found.

Espero que esto ayude :)

PD: Felicitaciones a Andrew Davey por hacer un complemento tan increíble.

Yasser Shaikh
fuente
@niico Al mirar el código fuente, parece establecer el código de respuesta en 404, así que sí.
Will Dean
20

Pruebe esto en web.config para reemplazar las páginas de error de IIS. Esta es la mejor solución, supongo, y también envía el código de estado correcto.

<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" subStatusCode="-1" />
    <remove statusCode="500" subStatusCode="-1" />
    <error statusCode="404" path="Error404.html" responseMode="File" />
    <error statusCode="500" path="Error.html" responseMode="File" />
  </httpErrors>
</system.webServer>

Más información de Tipila: use páginas de error personalizadas ASP.NET MVC

Amila
fuente
1
+1. Esto es lo único que pareció funcionar de manera consistente para mí en MVC5 con múltiples áreas.
Hawkke
Ésta es la solución más sencilla. Sin embargo, no puede usar la sintaxis de la maquinilla de afeitar en su página de error.
highace
15

Esta solución no necesita cambios en el archivo web.config ni rutas generales.

Primero, cree un controlador como este;

public class ErrorController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Title = "Regular Error";
        return View();
    }

    public ActionResult NotFound404()
    {
        ViewBag.Title = "Error 404 - File not Found";
        return View("Index");
    }
}

Luego, cree la vista en "Vistas / Error / Index.cshtml" como;

 @{
      Layout = "~/Views/Shared/_Layout.cshtml";
  }                     
  <p>We're sorry, page you're looking for is, sadly, not here.</p>

Luego agregue lo siguiente en el archivo asax global como se muestra a continuación:

protected void Application_Error(object sender, EventArgs e)
{
        // Do whatever you want to do with the error

        //Show the custom error page...
        Server.ClearError(); 
        var routeData = new RouteData();
        routeData.Values["controller"] = "Error";

        if ((Context.Server.GetLastError() is HttpException) && ((Context.Server.GetLastError() as HttpException).GetHttpCode() != 404))
        {
            routeData.Values["action"] = "Index";
        }
        else
        {
            // Handle 404 error and response code
            Response.StatusCode = 404;
            routeData.Values["action"] = "NotFound404";
        } 
        Response.TrySkipIisCustomErrors = true; // If you are using IIS7, have this line
        IController errorsController = new ErrorController();
        HttpContextWrapper wrapper = new HttpContextWrapper(Context);
        var rc = new System.Web.Routing.RequestContext(wrapper, routeData);
        errorsController.Execute(rc);

        Response.End();
}

Si aún obtiene la página de error de IIS personalizada después de hacer esto, asegúrese de que las siguientes secciones estén comentadas (o vacías) en el archivo de configuración web:

<system.web>
   <customErrors mode="Off" />
</system.web>
<system.webServer>   
   <httpErrors>     
   </httpErrors>
</system.webServer>
Sujeewa
fuente
No creo que este enfoque funcione en todos los casos, ya que un 404 a menudo es interceptado por el servidor web y, por lo tanto, nunca se maneja a nivel de aplicación.
Chris Halcrow
Quiero agregar que si opta por este enfoque, recomendaría agregar un Response.End();al final de su controlador Application_Error. Sin esto, solo se activa la primera aparición de un error para una sesión determinada, lo cual es un problema cuando, por ejemplo, tiene un registro de errores personalizado en el controlador Application_Error.
Keith
6

Si trabaja en MVC 4, puede ver esta solución, funcionó para mí.

Agregue el siguiente método Application_Error a my Global.asax:

protected void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    Server.ClearError();

    RouteData routeData = new RouteData();
    routeData.Values.Add("controller", "Error");
    routeData.Values.Add("action", "Index");
    routeData.Values.Add("exception", exception);

    if (exception.GetType() == typeof(HttpException))
    {
        routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
    }
    else
    {
        routeData.Values.Add("statusCode", 500);
    }

    IController controller = new ErrorController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    Response.End();

El controlador en sí es realmente simple:

public class ErrorController : Controller
{
    public ActionResult Index(int statusCode, Exception exception)
    {
        Response.StatusCode = statusCode;
        return View();
    }
}

Verifique el código fuente completo de Mvc4CustomErrorPage en GitHub .

Duc Hoang
fuente
0

Tuve el mismo problema, lo que tienes que hacer es, en lugar de agregar el atributo customErrors en el archivo web.config en tu carpeta Vistas, tienes que agregarlo en el archivo web.config en la carpeta raíz de tu proyecto

Fumarlo
fuente
0

Aquí hay una respuesta verdadera que permite personalizar completamente la página de error en un solo lugar. No es necesario modificar web.config o crear un código separado.

Funciona también en MVC 5.

Agregue este código al controlador:

        if (bad) {
            Response.Clear();
            Response.TrySkipIisCustomErrors = true;
            Response.Write(product + I(" Toodet pole"));
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            //Response.ContentType = "text/html; charset=utf-8";
            Response.End();
            return null;
        }

Basado en http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages

Andrus
fuente
0

Hablaré de algunos casos específicos,

si está utilizando el 'método PageNotFound' en HomeController como se muestra a continuación

[Route("~/404")]
public ActionResult PageNotFound()
{
  return MyView();
}

esto no funcionaría. Pero debe borrar las etiquetas de ruta como se muestra a continuación,

//[Route("~/404")]
public ActionResult PageNotFound()
{
  return MyView();
}

Y si lo cambia como nombre del método en web.config , funciona. Sin embargo, no olvide hacer código como el siguiente en web.config

<customErrors mode="On">
  <error statusCode="404" redirect="~/PageNotFound" /> 
 *// it is not "~/404" because it is not accepted url in Route Tag like [Route("404")]*
</customErrors>
Furkan ozturk
fuente