12

在我的 WebApi 代码中,我引发了一个 HttpResponseException ,它使请求管道短路并生成一个有效的 Http 响应。但是,我正在尝试将 webApi 与 elmah 日志记录集成,但 HttpResponseExeptions 没有出现。

我为 elmah 设置了 web.config 并具有以下代码:

在 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

3 回答 3

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”添加过滤器。

于 2013-09-26T17:27:23.097 回答
4

Web API 特殊情况 HttpResponseException 在操作中引发并转换为 HttpResponseMessage,因此您没有看到您的异常过滤器被调用。

在从过滤器中抛出 HttpResponseException 的情况下,情况并非如此。但是,理想情况下不需要从过滤器中抛出 HttpResponseException,因为您可以通过在提供的输入上下文上设置 Response 属性来短路请求。

于 2013-06-03T20:50:40.427 回答
3

您需要为 HttpFilters 打开 Elmah 以使其按您对 WebApi 的预期工作。

使用作为NuGet 包提供的Elmah.Contrib.WebApi,它将包含一个类,然后您可以按照 Elmah.Contrib.WebApi 项目站点上的说明进行连接。

如果您想自己执行此操作,使用 ELMAH 在 ASP.NET Web API 中捕获未处理的异常将引导您了解 Elmah.Contrib.WebApi 正在为您做什么。

此外,我必须更改引发错误响应的方式,以便 Elmah 选择它:

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

我还建议使用Elmah.MVC NuGet Package

于 2013-06-04T16:57:44.113 回答