IIS/Owin 如何在管道中将 IHttpActionResult 转换为 application/json?

How IIS/Owin converts IHttpActionResult to application/json down the pipeline?

我正在探索 IIS/Owin 管道的工作原理。我正在尝试找到 IIS/Owin 使用的 library/method 在管道中将 IHttpActionResult (从控制器返回)转换为正确的内容类型,如请求中存在的 application/json。

控制器 -

[Route("")]
public IHttpActionResult Get()
{
    IEnumerable<Product> productList = ProductService.GetAllProducts();
    if (!productList.Any())
        return Ok();

    return Json(productList, new JsonSerializerSettings
    {
        ContractResolver = new WebContractResolver(),
        Converters = new List<JsonConverter> { new TrimStringDataConverter() }
    });
}

API 消费者收到的数据 -

[
    {
        "code": "prod101",
        "title": "LAPTOP"
    },
    {
        "code": "prod102",
        "title": "MOBILE"
    }
]

从 IHttpActionResult 到 application/json 的转换何时发生?

IHttpActionResult 有一个方法 ExecuteAsync 其中 returns HttpResponseMessage

public interface IHttpActionResult
{
    Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken);
}

当您在控制器中使用 Json() 时,它将创建一个新的 JsonResult(link)

这是创建 HttpResponseMessage 的方法,它是 json.(link)

public virtual Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
    return Task.FromResult(Execute());
}

private HttpResponseMessage Execute()
{
    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);

    try
    {
            ArraySegment<byte> segment = Serialize();
            response.Content = new ByteArrayContent(segment.Array, segment.Offset, segment.Count);
            MediaTypeHeaderValue contentType = new MediaTypeHeaderValue("application/json");
            contentType.CharSet = _encoding.WebName;
            response.Content.Headers.ContentType = contentType;
            response.RequestMessage = _dependencies.Request;
        }
        catch
        {
            response.Dispose();
            throw;
        }

        return response;
    }

Owin 中有一个 HttpMessageHandlerAdapter class 有一个 SendResponseMessageAsync 方法 return HttpResponseMessage 给客户端。这是来自 github 的来源:HttpMessageHandlerAdapter

private Task SendResponseMessageAsync(HttpRequestMessage request, HttpResponseMessage response,
        IOwinResponse owinResponse, CancellationToken cancellationToken)
    {
        owinResponse.StatusCode = (int)response.StatusCode;
        owinResponse.ReasonPhrase = response.ReasonPhrase;

        // Copy non-content headers
        IDictionary<string, string[]> responseHeaders = owinResponse.Headers;
        foreach (KeyValuePair<string, IEnumerable<string>> header in response.Headers)
        {
            responseHeaders[header.Key] = header.Value.AsArray();
        }

        HttpContent responseContent = response.Content;
        if (responseContent == null)
        {
            SetHeadersForEmptyResponse(responseHeaders);
            return TaskHelpers.Completed();
        }
        else
        {
            // Copy content headers
            foreach (KeyValuePair<string, IEnumerable<string>> contentHeader in responseContent.Headers)
            {
                responseHeaders[contentHeader.Key] = contentHeader.Value.AsArray();
            }

            // Copy body
            return SendResponseContentAsync(request, response, owinResponse, cancellationToken);
        }
    }