2013-06-03 1 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

Специальные случаи API-интерфейса API API HttpResponseException, выведенные в действие и преобразованные в HttpResponseMessage, и, следовательно, вы не видите, что ваш фильтр исключения вызывается.

Это неверно в случае исключения HttpResponseException из фильтров. Однако в идеале не нужно выбрасывать HttpResponseException из фильтров, так как вы могли бы коротко закоротить запрос, установив свойство Response в предоставленном исходном контексте.

+2

Так как я могу заставить его работать? – jaffa

+0

Вы не можете. Ваш фильтр будет вызываться только для исключений, отличных от HttpResponseExceptions, когда они выкидываются из действий. –

+1

Я использовал ручную сигнализацию ошибок Elmah, когда создаю исключение HttpResponseException, и это, похоже, работает нормально. – jaffa

3

Вам нужно включить Elmah для 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 API вызывает ExceptionFilterAttribute.OnException() в вашем производном фильтре исключений для каждого исключения * кроме *, когда 'HttpResponseExeption' вызывается из' ApiController'. В этом случае Web API проглатывает исключение, и фильтр исключений никогда не вызывается. Я искал обходной путь, но еще не нашел его. –

+0

@KevinBabcock связанное решение работало для меня +1 – NimChimpsky

+0

Это не обрабатывает HttpResponseException – lnaie

11

Как уже упоминалось выше, фильтр Elmah не захватывает и не записывает ничего, когда вы поднимаете исключение HttpResponseException. Более конкретно, если используется следующий синтаксис:

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» и проверить действиеExecutedContext.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