某些404响应中缺少内容

时间:2017-10-31 14:37:53

标签: c# asp.net-web-api asp.net-web-api2 owin delegatinghandler

我正在尝试从web.api返回自定义错误响应。让它是格式化为json的简单字符串"Oops!"。所以我创建了简单的委托处理程序来替换错误响应,如下所示:

public class ErrorMessageHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
       HttpRequestMessage request, CancellationToken cancellationToken)
    {
       var response = await base.SendAsync(request, cancellationToken);

       if (response.IsSuccessStatusCode)
           return response;

       var formatter = new JsonMediaTypeFormatter();
       var errorResponse = request.CreateResponse(response.StatusCode, "Oops!", formatter);
       return errorResponse;
    }
}

接下来,我确保这是管道中唯一的一个消息处理程序:

httpConfig.MessageHandlers.Clear();
httpConfig.MessageHandlers.Add(new ErrorMessageHandler());

// Only default route
httpConfig.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

app.UseWebApi(httpConfig); // OWIN self-hosting

控制器也是最简单的一个:

public class ValuesController : ApiController
{
   public IHttpActionResult Get(int id)
   {
      if (id == 42)
        return Ok("Answer to the Ultimate Question of Life, the Universe, and Everything");

      return NotFound();
   }
}

这很有趣:

  • /api/values/42为我提供了200个带有值字符串
  • 的回复
  • /api/values/13通过我的自定义"Oops!"字符串
  • 为我提供了404回复
  • /api/values/42/missing为我提供 404回复

最后一个案例是我的问题。当我在委托处理程序的最后一行设置断点时,我清楚地看到errorResponse包含ObjectContent<string>且值正确。但为什么这个价值会在以后清除掉呢?

1 个答案:

答案 0 :(得分:2)

原因是HttpMessageHandlerAdapter.InvokeCore中的代码(基本上在UseWebApi中间件中):

response = await _messageInvoker.SendAsync(request, cancellationToken);
// ...
if (IsSoftNotFound(request, response)) {
       callNext = true;
}
else { 
    // ...
}

IsSoftNotFound的位置:

private static bool IsSoftNotFound(HttpRequestMessage request, HttpResponseMessage response)
{
    if (response.StatusCode == HttpStatusCode.NotFound)
    {
        bool routingFailure;
        if (request.Properties.TryGetValue<bool>(HttpPropertyKeys.NoRouteMatched, out routingFailure)
            && routingFailure)
        {
            return true;
        }
    }
    return false;
}

所以基本上是在&#34; soft&#34; 404,其中&#34;软&#34;表示没有匹配的路由(并且由request.Properties中的特定键的属性指示) - 中间件将调用下一个组件。否则 - 只会发送回复。

这个IsSoftDelete适用于您的情况(因为确实没有路由匹配),而下一个组件(没有时间弄清楚那是什么)会清除您的响应内容。

To&#34; fix&#34;此问题 - 在请求由前一个处理程序处理后,从请求中删除具有该键的属性:

public class ErrorMessageHandler : DelegatingHandler {
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {
        var response = await base.SendAsync(request, cancellationToken);

        if (response.IsSuccessStatusCode)
            return response;

        // here, can also check if 404
        request.Properties.Remove(HttpPropertyKeys.NoRouteMatched);
        var formatter = new JsonMediaTypeFormatter();
        var errorResponse = request.CreateResponse(response.StatusCode, "Oops!", formatter);
        return errorResponse;
    }
}