2013-06-03 39 views
12

在我的WebApi代碼中,我引發了一個HttpResponseException,它使請求管道短路並生成有效的Http響應。但是,我試圖將webApi與elmah日誌集成,但HttpResponseExeptions沒有顯示出來。Elmah不會使用WebAPI和HttpResponseException記錄異常

我有web.config中建立了ELMAH並具有以下代碼:

在Global.asx.cs:

static void ConfigureWebApi(HttpConfiguration config) 
{ 
    config.Filters.Add(new ServiceLayerExceptionFilter());    
    config.Filters.Add(new ElmahHandledErrorLoggerFilter()); 
    config.DependencyResolver = new WebApiDependencyResolver(ObjectFactory.Container);        
}  

篩選:

public class ElmahHandledErrorLoggerFilter : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext actionExecutedContext) 
    { 
     base.OnException(actionExecutedContext); 
     ErrorSignal.FromCurrentContext().Raise(actionExecutedContext.Exception); 
    } 
} 

發生異常的代碼:

public Task<FileUpModel> UploadFile() 
{ 
    if (Request.Content.IsMimeMultipartContent()) 
    {     
     var provider = new TolMobileFormDataStreamProvider("C:\images\"); 

     var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(
     t => 
     { 

      if (t.IsFaulted || t.IsCanceled) 
       throw new HttpResponseException(HttpStatusCode.InternalServerError); 

      var fileInfo = provider.FileData.FirstOrDefault(); 
      if (fileInfo == null) 
       // the exception here isn't logged by Elmah?! 
       throw new HttpResponseException(HttpStatusCode.InternalServerError);  

      var uploadModel = new FileUpModel { success = true }; 
      return uploadModel; 
     }); 

     return task; 
    } 
    else 
    { 
     throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted")); 
    }    
} 

誰能實施這個之前讓我知道我做錯了什麼嗎?

回答

4

Web API特殊情況HttpResponseException引發操作並轉換爲HttpResponseMessage,因此您沒有看到您的異常過濾器被調用。

在從過濾器中拋出HttpResponseException時,這不是真的。但是,理想情況下,您不需要從過濾器中拋出HttpResponseException,因爲您可以通過在提供的輸入上下文中設置Response屬性來短路請求。

+2

那麼我如何才能使它工作? – jaffa

+0

你不能。從動作拋出時,只會爲非HttpResponseExceptions調用過濾器。 –

+1

當我創建HttpResponseException時,我使用手動Elmah錯誤信號,這似乎工作正常。 – jaffa

3

您需要打開Elmah for HttpFilters才能使其按照WebApi的預期工作。

使用Elmah.Contrib.WebApi作爲NuGet Package可用,它將包含一個類,然後您可以按照Elmah.Contrib.WebApi項目網站上的說明進行連接。

如果你想自己做,Capturing Unhandled Exceptions in ASP.NET Web API's with ELMAH會引導你通過Elmah.Contrib.WebApi爲你做的事情。

此外,我不得不改變錯誤響應拋出它由ELMAH採摘的方式:

throw new HttpException((int)HttpStatusCode.NotAcceptable, "This request is not properly formatted"); 

我也建議使用Elmah.MVC NuGet Package的。

+5

無論是項目還是博客文章,你都引用了@jaffa提出的問題。使用屬性或全局過濾器來捕獲ASP.NET Web API項目中的異常在Web上已有詳細記錄。 * *沒有詳細記錄的事實是,Web API會在您的派生異常過濾器上爲每個異常調用ExceptionFilterAttribute.OnException(),除了從'ApiController'引發'HttpResponseExeption'時。在這種情況下,Web API會吞噬異常,並且您的異常過濾器永遠不會被調用。我一直在尋找解決方法,但尚未找到解決辦法。 –

+0

@KevinBabcock鏈接的解決方案爲我工作+1 – NimChimpsky

+0

這不處理HttpResponseException – lnaie

11

如上所述,當您引發HttpResponseException時,Elmah過濾器不捕獲並記錄任何內容。更具體地說,如果使用以下語法:

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "It was a bad request"); 
or 
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "HttpResponseException - This request is not properly formatted")); 

我想在兩種情況下捕獲並記錄一個錯誤。做到這一點的方法是使用「ActionFilterAttribute」,覆蓋「OnActionExecuted」,並檢查actionExecutedContext.Response.IsSuccessStatusCode。

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 
{ 
    // when actionExecutedContext.Response is null, the error will be caught and logged by the Elmah filter 
    if ((actionExecutedContext.Response != null) && !actionExecutedContext.Response.IsSuccessStatusCode) 
    { 
     try 
     { 
      var messages = (System.Web.Http.HttpError)((System.Net.Http.ObjectContent<System.Web.Http.HttpError>)actionExecutedContext.Response.Content).Value; 
      StringBuilder stringBuilder = new StringBuilder(); 
      foreach (var keyValuePair in messages) { 
       stringBuilder.AppendLine("Message: Key - " + keyValuePair.Key + ", Value - " + keyValuePair.Value); 
      } 
      Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Web API Failed Status Code returned - " + stringBuilder.ToString())); 
     } 
     catch (Exception ex) 
     { 
      Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Error in OnActionExecuted - " + ex.ToString())); 
     } 
    } 
} 

在附註中,我還覆蓋了「OnActionExecuting」來驗證模型狀態。這使我可以刪除我的行爲中的所有檢查。

public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) 
{ 
    if (actionContext.ModelState != null && !actionContext.ModelState.IsValid) 
    { 
     StringBuilder stringBuilder = new StringBuilder(); 
     foreach (var obj in actionContext.ModelState.Values) 
     { 
      foreach (var error in obj.Errors) 
      { 
       if(!string.IsNullOrEmpty(error.ErrorMessage)) { 
        stringBuilder.AppendLine("Error: " + error.ErrorMessage); 
       } 
      } 
     } 
     Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Invalid Model State -- " + stringBuilder.ToString())); 
     actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState); 
    } 
} 

當然,您需要使用「config.Filters.Add」添加過濾器。

+0

我認爲這是對這個問題的良好答案... – Dragouf

+0

是的,這也能夠捕獲HttpResponseException。 – lnaie

+0

幫了很多!謝謝。 – mike123