shahidbits
shahidbits

Reputation: 141

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

I am exploring how IIS/Owin pipeline works. I am trying to find the library/method used by IIS/Owin down the pipeline to convert IHttpActionResult (returned from controller) into the correct content-type like application/json as present in the request.

Controller -

[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() }
    });
}

Data received by API consumer -

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

When this conversion from IHttpActionResult to application/json takes place ?

Upvotes: 0

Views: 259

Answers (1)

Kahbazi
Kahbazi

Reputation: 15015

IHttpActionResult has a method ExecuteAsync which returns HttpResponseMessage

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

When you use Json() in your controller it will create a new JsonResult(link)

And this is the method which create a HttpResponseMessage which is a 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;
    }

in Owin there is a HttpMessageHandlerAdapter class which has a SendResponseMessageAsync method that return HttpResponseMessage to client. Here's the source from 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);
        }
    }

Upvotes: 2

Related Questions