2014-02-05 42 views
3

我使用WebApi 2.1創建了一個面向公衆的API,擁有一個專用的WebApi項目(無MVC),在自己的服務器上擁有IIS 7.5託管的API,並且設計目標爲只返回JSON或空內容,並且從不返回HTML。我愉快地使用ExceptionFilterAttribute應對的WebAPI管道內出現異常如何爲WebApi管道外的錯誤返回JSON?

,如下:

public class GlobalExceptionHandler : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext context) 
    { 
     // Log the exception to Elmah 
     Elmah.Error error = new Elmah.Error(context.Exception, HttpContext.Current); 
     error.Detail = ActionState.GetRequestParameters(context) + error.Detail; 
     Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(error); 

     if (context.Exception is NotImplementedException) 
     { 
      context.Response = context.Request.CreateErrorResponse(
       HttpStatusCode.NotImplemented 
       , "The API method has not yet been implemented" 
      ); 
     } 
     else 
     { 
      context.Response = context.Request.CreateErrorResponse(
       HttpStatusCode.InternalServerError 
       , "A " + context.Exception.GetType().ToString() + " was thrown" 
      ); 
     } 

     base.OnException(context); 
    } 
} 

過濾器被正確地添加在App_Start:

config.Filters.Add(new SecureVideoApiGlobalExceptionHandler()); 

問題是當一個錯誤出現在WebApi管道之外。例如,一個請求帶有Web根目錄的URI,https://mysite.com/,響應是一個403.11,其中HTML主體聲明「Web服務器配置爲不列出此目錄的內容」。另一種可能性是global.asax的Application_Start方法中調用的代碼存在錯誤,例如在AutoMapper代碼中,該代碼聲明所有映射都是有效的。

我的問題是:我怎麼能這樣做,當API服務器發生任何錯誤時,只返回一個JSON錯誤消息,而不會返回HTML錯誤消息?

我已經試過

<modules runAllManagedModulesForAllRequests="true"> 

這讓我來處理的Application_Error()在Global.asax中的任何錯誤,但我沒有訪問Response對象那裏發出JSON的能力。

回答

3

你可以做財產以後這樣的屬性

[AttributeUsageAttribute(AttributeTargets.All, Inherited = true, AllowMultiple = true)] 
public class ExceptionActionFilter : ExceptionFilterAttribute 
{ 
    private static Logger _log ;//= LogManager.GetLogger("mysite"); 

    public override void OnException(HttpActionExecutedContext contex) 
    { 
     if (_log == null) 
      _log = LogManager.GetCurrentClassLogger(); 

     var ex = contex.Exception; 

     _log.Error(ex); 

     contex.Response = contex.Request.CreateResponse(HttpStatusCode.OK, 
      new 
      { 
       ErrorMessage = contex.Exception.Message, 
       RealStatusCode = (int)(ex is NotImplementedException || ex is ArgumentNullException ? HttpStatusCode.NoContent : HttpStatusCode.BadRequest), 
       ReturnUrl = CommonContext.ErrorUrl 
      }, 
      new JsonMediaTypeFormatter()); 

     base.OnException(contex); 
    }  
} 

然後把屬性的一類EXC並在CLIEN側

或過濾

public class ExceptionLoggerFilter : System.Web.Http.Filters.IExceptionFilter 
{ 
    private static Logger _log; 
    public ExceptionLoggerFilter() 
    { 
     if (_log == null) 
      _log = LogManager.GetCurrentClassLogger(); 
    } 

    public bool AllowMultiple { get { return true; } } 

    public System.Threading.Tasks.Task ExecuteExceptionFilterAsync(
      System.Web.Http.Filters.HttpActionExecutedContext contex, 
      System.Threading.CancellationToken cancellationToken) 
    { 
     return System.Threading.Tasks.Task.Factory.StartNew(() => 
     { 
      _log.Error(contex.Exception); 

      contex.Response = contex.Request.CreateResponse(HttpStatusCode.OK, 
       new { RealStatusCode = (int)HttpStatusCode.Forbidden, ReturnUrl = "#/error.html"}, 
       contex.ActionContext.ControllerContext.Configuration.Formatters.JsonFormatter); 

     }, cancellationToken); 
    } 
} 

然後在全球.asax.cs

protected void Application_Start() 
{ 
    GlobalConfiguration.Configure(WebApiConfig.Register); 
    Database.SetInitializer<MySiteContext>(null); 
} 

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config)//RouteCollection config)// 
    { 
     config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 
     config.Filters.Add(new ExceptionLoggerFilter()); 
     // Web API routes 
     config.MapHttpAttributeRoutes(); 
     config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: new { id = RouteParameter.Optional }); 

    } 
} 

而在客戶端梅比財產以後像

$.controller.ajax.promise = controller.ajax.promise = function (obj) 
{ 
    var deferred = q.defer(); 
    $.ajax({ 
     type: obj.type || "GET", 
     url: obj.url, 
     context: obj.context || null, 
     data: obj.data || null, 
     contentType: obj.contentType || "application/json; charset=utf-8", 
     dataType: obj.dataType || "json", 
     success: function (res, textStatus, jqXHR) 
     { 
      if (res.RealStatusCode) 
      { 
       switch (res.RealStatusCode) 
       { 
        case 400://x error 
         res.ClientMessage = res.ErrorMessage; 
         deferred.reject(res); 
         break; 
        case 408://y errors 
         location.href = res.ReturnUrl; 
         return false; 
        case 403://ext 
         msgbox.alert({ 
          message: 'Ma belle msg', 
          title: "Error" 
         }); 
         deferred.reject(); 
         location.href = res.ReturnUrl; 
         return false; 
        default: 
         deferred.reject(); 
         location.href = res.ReturnUrl; 
         break; 
       } 
      } 
      deferred.resolve(res); 
      return true; 
     }, 
     error: function (jqXHR, textStatus, errorThrown) 
     { 
      deferred.reject({ msg: jqXHR.statusText, jqXHR: jqXHR, textStatus:textStatus, errorThrown:errorThrown }); 
     } 
    }); 

    return deferred.promise; 
}; 

我希望這可以幫助其他的Google那裏! (就像@Thomas CG de Vilhena說的那樣=)

+1

兩年後,我用google搜索了一下,結果在這裏,看到我的名字xD –

+1

yess [taht ans](https://stackoverflow.com/a/19480499/1509853 )幫助,再次10倍=) – oCcSking