CustomErrors y Http Status Code en ASP.NET MVC

Comentar
Compartir
SystemException

Los que trabajen con ASP .NET MVC para la generación de APIs, pronto se darán cuenta de un incómodo problema de ASP por el cual al elevar una excepción con HttpException e independientemente del código de error (http status code) que indiquemos en el constructor, el usuario siempre recibe un error 500 Internal Server Error. Esto supone un grave problema para el SEO (si aplicase, pero también para el usuario del API desde un punto de vista semántico). Por ejemplo, si lanzamos una excepción 404 Página no encontrada, el buscador de turno recibirá un error 500, y supondrá que la página existe aunque no funcione correctamente.

Además, y por el contrario, cuando implementamos Custom Errors para nuestro sitio web para evitar la pagina HTML de error del servidor “Server Error in Application”, ASP.NET elevará un Http Status Code 200 junto con el contenido de nuestra página de error personalizada. Esto también es un inconveniente, puesto que los buscadores indexarán nuestras páginas de error como páginas de contenido normal.


A continuación voy a describir una alternativa de solución a ambos problemas.

Implementar Custom Errors y devolver un codigo de error distinto de 200

Si deseamos cambiar las paginas de error de Internet Information Server por nuestras propias páginas (mucho más bonitas por supuesto) una posible via es:

1 – Crear el controlador y las acciones que manejarán cada uno de los errores:

En el código siguiente se muestra como podría ser una accion que manejase el error 500, devolviendo un json en su lugar. Aunque también podría devolverse una vista HTML.

[code lang=”csharp”]
public abstract class ErrorController : System.Web.Mvc.Controller
{

private class OperationResponse
{
public int code { get; set; }
public string description { get; set; }
}

public ActionResult Unknown()
{
OperationResponse Res = new OperationResponse();
Res.code = 500;
Res.description = "500 Internal Server Error";

Response.TrySkipIisCustomErrors = true;
Response.Status = "500 Internal Server Error";
Response.StatusCode = 500;

return Json(Res, JsonRequestBehavior.AllowGet);
}

public ActionResult NotFound()
{
OperationResponse Res = new OperationResponse();
Res.code = 404;
Res.description = "404 Not Found";

Response.TrySkipIisCustomErrors = true;
Response.Status = "404 Not Found";
Response.StatusCode = 404;

return Json(Res, JsonRequestBehavior.AllowGet);
}
}
[/code]

Hay que prestar especial atención a las tres lineas que modifican Response, ya que con esto conseguiremos que ASP devuelva un código de error distinto de 200 cuando lanza un error.

2 – Añadir la ruta que manejará las acciones del controlador de errores al Global.asax.cs

[code lang=”csharp”]
routes.MapRoute(
"ErrorManager",
"error/{action}",
new { controller = "Error" }
);
[/code]

3 – Añadir al Web.config la sección customErrors para forzar el control de los errores devueltos.

[code lang=”csharp”]
<customErrors mode="On" defaultRedirect="Error/Unknown">
<error statusCode="404" redirect="Error/NotFound" />
</customErrors>
[/code]

Y con esto se mostrará nuestro propio código de error cuando se produzca.

Devolver un código de error Http Status Code distinto de 500 al usar HttpException

Una manera de lograr solucionar este “bug” de ASP es capturar la excepción en el método OnException del Controlador y sobreescribir la respuesta, redirigiendo a nuestros custom errors anteriores, por ejemplo.

[code lang=”csharp”]
protected override void OnException(ExceptionContext filterContext)
{
try
{
HttpException ex = (HttpException)filterContext.Exception;
ActionResult CustomActionResult = GetCustomErrorActionResult(ex.GetHttpCode());
if (CustomActionResult != null) filterContext.Result = CustomActionResult;
}
catch { }

base.OnException(filterContext);
}
[/code]

Y el método al que hace referencia el código anterior y que definiremos también en el Controlador, para que se encargue de la magia:

[code lang=”csharp”]
public ActionResult GetCustomErrorActionResult(int code)
{
ActionResult Response = null;
try
{
//check custom error is on
System.Configuration.Configuration configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/");
System.Web.Configuration.CustomErrorsSection section = (System.Web.Configuration.CustomErrorsSection)configuration.GetSection("system.web/customErrors");

System.Web.Configuration.CustomErrorsMode mode = section.Mode;
if (mode != System.Web.Configuration.CustomErrorsMode.Off)
{
string ActionName = null;

switch (code)
{
case 404:
ActionName = "NotFound";
break;
default:
ActionName = "Unknown";
break;
}

if (!String.IsNullOrEmpty(ActionName))
{
Response = this.RedirectToAction(ActionName, "Error");
}
}
}
catch { }

return Response;
}
[/code]

Y eso es todo, ahora nuestra aplicación devolverá un código de error apropiado junto con un contenido de la respuesta distinto del HTML de la página de error de IIS.

¡Espero que esto os ayude a gestionar mejor la respuesta en caso de error!

Acerca de findemor

Técnico de Innovación en solusoft.

Warning: count(): Parameter must be an array or an object that implements Countable in /homepages/30/d298707731/htdocs/porexpertos.es/wp-includes/class-wp-comment-query.php on line 405

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *