asp.net-mvc - page - try catch mvc
Manejo de errores ASP.NET MVC 404 (6)
Posible duplicado:
¿Cómo puedo manejar 404 correctamente en ASP.NET MVC?
Realicé los cambios delineados en el controlador de error 404 Http en Asp.Net MVC (RC 5) y sigo obteniendo la página de error 404 estándar. ¿Debo cambiar algo en IIS?
En IIS, puede especificar un redireccionamiento a la página "determinada" en función del código de error. En su ejemplo, puede configurar 404 -> Su página de error 404 personalizada.
He investigado MUCHO sobre cómo administrar adecuadamente 404s en MVC (específicamente MVC3) , y esto, en mi humilde opinión, es la mejor solución que he encontrado:
En global.asax:
public class MvcApplication : HttpApplication
{
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();
var rd = new RouteData();
rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["controller"] = "Errors";
rd.Values["action"] = "NotFound";
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
}
}
ErrorsController:
public sealed class ErrorsController : Controller
{
public ActionResult NotFound()
{
ActionResult result;
object model = Request.Url.PathAndQuery;
if (!Request.IsAjaxRequest())
result = View(model);
else
result = PartialView("_NotFound", model);
return result;
}
}
Editar:
Si está utilizando IoC (por ejemplo, AutoFac), debe crear su controlador usando:
var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);
En lugar de
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
(Opcional)
Explicación:
Hay 6 escenarios en los que puedo pensar que una aplicación ASP.NET MVC3 puede generar 404s.
Generado por ASP.NET:
- Escenario 1: URL no coincide con una ruta en la tabla de rutas.
Generado por ASP.NET MVC:
Escenario 2: URL coincide con una ruta, pero especifica un controlador que no existe.
Escenario 3: URL coincide con una ruta, pero especifica una acción que no existe.
Manualmente generado:
Escenario 4: una acción devuelve un HttpNotFoundResult utilizando el método HttpNotFound ().
Escenario 5: una acción arroja una HttpException con el código de estado 404.
Escenario 6: una acción modifica manualmente la propiedad Response.StatusCode a 404.
Objetivos
(A) Mostrar una página de error 404 personalizada para el usuario.
(B) Mantenga el código de estado 404 en la respuesta del cliente (especialmente importante para SEO).
(C) Envíe la respuesta directamente, sin incluir una redirección 302.
Intento de solución: errores personalizados
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>
Problemas con esta solución:
- No cumple con el objetivo (A) en los escenarios (1), (4), (6).
- No cumple con el objetivo (B) automáticamente. Debe ser programado manualmente.
- No cumple con el objetivo (C).
Intento de solución: errores de HTTP
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problemas con esta solución:
- Solo funciona en IIS 7+.
- No cumple con el objetivo (A) en los escenarios (2), (3), (5).
- No cumple con el objetivo (B) automáticamente. Debe ser programado manualmente.
Intento de solución: Errores HTTP con Reemplazar
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problemas con esta solución:
- Solo funciona en IIS 7+.
- No cumple con el objetivo (B) automáticamente. Debe ser programado manualmente.
- Oculta las excepciones http de nivel de aplicación. Por ejemplo, no puede usar la sección customErrors, System.Web.Mvc.HandleErrorAttribute, etc. No solo puede mostrar páginas de error genéricas.
Solución Intento de customErrors y errores de HTTP
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>
y
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problemas con esta solución:
- Solo funciona en IIS 7+.
- No cumple con el objetivo (B) automáticamente. Debe ser programado manualmente.
- No cumple con el objetivo (C) en los escenarios (2), (3), (5).
Las personas que han tenido problemas con esto incluso antes intentaron crear sus propias bibliotecas (ver http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html ). Pero la solución anterior parece cubrir todos los escenarios sin la complejidad de usar una biblioteca externa.
La respuesta de Marco es la MEJOR solución. Necesitaba controlar mi manejo de errores, y me refiero a realmente CONTROLARLO. Por supuesto, amplié un poco la solución y creé un sistema completo de administración de errores que maneja todo. También he leído sobre esta solución en otros blogs y parece muy aceptable para la mayoría de los desarrolladores avanzados.
Aquí está el código final que estoy usando:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "ErrorManager";
routeData.Values["action"] = "Fire404Error";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 404:
routeData.Values["action"] = "Fire404Error";
break;
}
}
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
IController errormanagerController = new ErrorManagerController();
HttpContextWrapper wrapper = new HttpContextWrapper(Context);
var rc = new RequestContext(wrapper, routeData);
errormanagerController.Execute(rc);
}
}
y dentro de mi ErrorManagerController:
public void Fire404Error(HttpException exception)
{
//you can place any other error handling code here
throw new PageNotFoundException("page or resource");
}
Ahora, en mi acción, estoy lanzando una excepción personalizada que he creado. Y mi controlador está heredando de una clase personalizada basada en el controlador que he creado. El controlador base personalizado se creó para anular el manejo de errores. Aquí está mi clase personalizada de controlador de base:
public class MyBasePageController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
filterContext.GetType();
filterContext.ExceptionHandled = true;
this.View("ErrorManager", filterContext).ExecuteResult(this.ControllerContext);
base.OnException(filterContext);
}
}
El "ErrorManager" en el código anterior es solo una vista que está usando un modelo basado en ExceptionContext
Mi solución funciona perfectamente y puedo manejar CUALQUIER error en mi sitio web y mostrar diferentes mensajes basados en CUALQUIER tipo de excepción.
Lo que puedo recomendar es buscar en FilterAttribute. Por ejemplo, MVC ya tiene HandleErrorAttribute. Puedes personalizarlo para que maneje solo 404. Responde si estás interesado veré un ejemplo.
Por cierto
La solución (con la última ruta) que ha aceptado en la pregunta anterior no funciona en la mayoría de las situaciones. La segunda solución con HandleUnknownAction funcionará, pero es necesario realizar este cambio en cada controlador o tener un solo controlador base.
Mi elección es una solución con HandleUnknownAction.
Otra solución más
Agregue los Controles de Error o la página estática a la información de error 404.
Modifique su web.config (en caso de controlador).
<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Errors/Error404" />
</customErrors>
</system.web>
O en el caso de una página estática
<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Static404.html" />
</customErrors>
</system.web>
Esto manejará las rutas perdidas y las acciones perdidas.
Parece que esta es la mejor manera de atrapar todo.