2008-09-21 26 views
9

aspnet mvc tiene el filtro HandleError que devolverá una vista si se produce un error, pero si se produce un error al invocar una acción JsonResult, ¿cómo puedo devolver un objeto JSON que represente un error?Cómo devolver JSON desde un filtro HandleError?

No quiero ajustar el código en cada método de acción que devuelve un JsonResult en un try/catch para lograrlo, prefiero hacerlo agregando un atributo 'HandleJsonError' o usando el atributo HandleError existente para los métodos de acción requeridos.

Respuesta

9

Eche un vistazo a la implementación MVC de HandleErrorAttribute. Devuelve un ViewResult. Podría escribir su propia versión (HandleJsonErrorAttribute) que devuelva un JsonResult.

+0

Lo he intentado pero cuando se llama al método HandleJsonErrorAttribute OnException, la propiedad filterContext.ExceptionHandled siempre es verdadera cuando hay un HandleErrorAttribute en la clase Controller a la que pertenece la acción. ¿No deberían los métodos de acción handleerror tener prioridad y ser llamados primero? –

1

Tal vez podría crear su propio atributo y tener un valor de constructor que tome un valor enum de View o Json. A continuación se muestra lo que estoy usando para un Atributo de Autorización personalizado para demostrar lo que quiero decir. De esta forma, cuando falla la autenticación en una solicitud json, responde con un error json y lo mismo con si devuelve una Vista.

public enum ActionResultTypes 
    { 
     View, 
     Json 
    } 

    public sealed class AuthorizationRequiredAttribute : ActionFilterAttribute, IAuthorizationFilter 
    { 
     public ActionResultTypes ActionResultType { get; set; } 

     public AuthorizationRequiredAttribute(ActionResultTypes actionResultType) 
     { 
      this.ActionResultType = ActionResultType; 
     } 
    } 

    //And used like 
    [AuthorizationRequired(ActionResultTypes.View)] 
    public ActionResult About() 
    { 
    } 
+0

Voy a intentar implementar un ejemplo de trabajo. ¡Si descubres que no funciona o encuentras una solución diferente, házmelo saber! – Vyrotek

7

En resumen, el camino a seguir puede ser la de ampliar el HandleErrorAttribute, así:

public class OncHandleErrorAttribute : HandleErrorAttribute 
{ 
    public override void OnException(ExceptionContext context) 
    { 
     // Elmah-Log only handled exceptions 
     if (context.ExceptionHandled) 
      ErrorSignal.FromCurrentContext().Raise(context.Exception); 

     if (context.HttpContext.Request.IsAjaxRequest()) 
     { 
      // if request was an Ajax request, respond with json with Error field 
      var jsonResult = new ErrorController { ControllerContext = context }.GetJsonError(context.Exception); 
      jsonResult.ExecuteResult(context); 
      context.ExceptionHandled = true; 
     } 
     else 
     { 
      // if not an ajax request, continue with logic implemented by MVC -> html error page 
      base.OnException(context); 
     } 
    } 
} 

Retire Elmah línea de código de registro si no lo necesita. Uso uno de mis controladores para devolver un json basado en un error y contexto. Aquí está la muestra:

public class ErrorController : Controller 
{ 
    public ActionResult GetJsonError(Exception ex) 
    { 
     var ticketId = Guid.NewGuid(); // Lets issue a ticket to show the user and have in the log 

     Request.ServerVariables["TTicketID"] = ticketId.ToString(); // Elmah will show this in a nice table 

     ErrorSignal.FromCurrentContext().Raise(ex); //ELMAH Signaling 

     ex.Data.Add("TTicketID", ticketId.ToString()); // Trying to see where this one gets in Elmah 

     return Json(new { Error = String.Format("Support ticket: {0}\r\n Error: {1}", ticketId, ex.ToString()) }, JsonRequestBehavior.AllowGet); 
    } 

Agrego información sobre el ticket anterior, puede ignorar esto. Debido a la forma en que se implementa el filtro (extiende los HandleErrorAttributes por defecto) entonces podemos eliminar HandleErrorAttribute de los filtros globales:

public class MvcApplication : System.Web.HttpApplication 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new GlobalAuthorise()); 
     filters.Add(new OncHandleErrorAttribute()); 
     //filters.Add(new HandleErrorAttribute()); 
    } 

Esta es básicamente la misma. Puede leer my blog entry para obtener información más detallada, pero para la idea, lo anterior debería ser suficiente.

+2

Lo anterior funciona durante el desarrollo en IISExpress. Para que esto funcione cuando se implementa en el servidor web IIS real, necesitamos agregar 'context.HttpContext.Response.TrySkipIisCustomErrors = true;' al crear nuestro mensaje json ya que IIS otherwize anula el mensaje de error y muestra su código de estado predeterminado 500 página – mortb

Cuestiones relacionadas