.Net Mvc: ¿Cómo disparar un error para Application_Error () administrarlos?

Administro todos los errores de aplicación en mi Application_Error() en Global.asax :

 protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); Log.LogException(exception); Response.Clear(); HttpException httpException = exception as HttpException; RouteData routeData = new RouteData(); routeData.Values.Add("controller", "Erro"); if (httpException == null) { routeData.Values.Add("action", "Index"); } else //It's an Http Exception { switch (httpException.GetHttpCode()) { case 404: //Page not found routeData.Values.Add("action", "HttpError404"); break; case 500: //Server error routeData.Values.Add("action", "HttpError500"); break; // Here you can handle Views to other error codes. // I choose a General error template default: routeData.Values.Add("action", "General"); break; } } //Pass exception details to the target error View. routeData.Values.Add("error", exception); //Clear the error on server. Server.ClearError(); //Avoid IIS7 getting in the middle Response.TrySkipIisCustomErrors = true; //Call target Controller and pass the routeData. IController errorController = new ErroController(); errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData)); } 

Por lo tanto, tengo un atributo de autorización personalizado en mi aplicación que maneja solicitudes no autorizadas y deseo redirigir a Application_Error() manipular eso en su lugar.

Entonces, hago eso:

 protected override void HandleUnauthorizedRequest(AuthorizationContext context) { if (context.HttpContext.Request.IsAuthenticated) { throw new HttpException(403, "Forbidden Access."); } else { base.HandleUnauthorizedRequest(context); } } 

De esa manera, se llama a Application_Error() , pero me parece feo llamar una excepción tan directamente, ¿existe otra forma? ¿Qué piensas chicos?

Tu código está bien. De forma predeterminada, si llama a la base.HandleUnauthorizedRequest lanza una excepción 401 que es interceptada por el módulo de autenticación de formularios y se le redirige a la página de inicio de sesión (que podría no ser el comportamiento deseado). Así que tu enfoque es correcto.

Otra posibilidad es representar directamente la vista de error correspondiente si no desea pasar por el error Application_Error :

 protected override void HandleUnauthorizedRequest(AuthorizationContext context) { if (context.HttpContext.Request.IsAuthenticated) { context.Result = new ViewResult { ViewName = "~/Views/Shared/Forbidden.cshtml" }; } else { base.HandleUnauthorizedRequest(context); } } 

¡Porque el Unauthorized no es un error por defecto! Solo agrega este método a global.asax

  protected void Application_EndRequest(object sender, EventArgs e) { if (Context.Response.StatusCode == 401 || Context.Response.StatusCode == 403) { // this is important, because the 401 is not an error by default!!! throw new HttpException(401, "You are not authorised"); } } 

No debe generar una excepción dentro de AuthorizeAttribute porque eso podría llevar a problemas de rendimiento para el código que se basa en AuthorizeAttribute para realizar una verificación de autorización. AuthorizeAttribute está diseñado para verificar si la Autorización es válida o no, no para tomar medidas basadas en esta información. Es por eso que el código original no lanza una excepción directamente; delega la tarea a la clase HttpUnauthorizedResult.

En su lugar, debe crear un controlador personalizado (similar a HttpUnauthorizedized ) para generar la excepción. Esto separará claramente la lógica de la verificación de la autorización y la realización de una acción basada en no estar autorizado en 2 clases diferentes.

 public class HttpForbiddenResult : HttpStatusCodeResult { public HttpForbiddenResult() : this(null) { } // Forbidden is equivalent to HTTP status 403, the status code for forbidden // access. Other code might intercept this and perform some special logic. For // example, the FormsAuthenticationModule looks for 401 responses and instead // redirects the user to the login page. public HttpForbiddenResult(string statusDescription) : base(HttpStatusCode.Forbidden, statusDescription) { } } 

Y luego en su AuthorizeAttribute personalizado, solo necesita configurar el nuevo controlador en HandleUnauthorizedized Request.

 protected override void HandleUnauthorizedRequest(AuthorizationContext context) { if (context.HttpContext.Request.IsAuthenticated) { // Returns HTTP 403 - see comment in HttpForbiddenResult.cs. filterContext.Result = new HttpForbiddenResult("Forbidden Access."); } else { base.HandleUnauthorizedRequest(context); } } 

Si necesita ejecutar una acción diferente a lanzar una HttpException, debe subclase ActionResult e implementar la acción en el método ExecuteResult o usar una de las clases incorporadas que hereda ActionResult.