Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fails to read response content twice #21

Closed
di97mni opened this issue Sep 15, 2016 · 4 comments
Closed

Fails to read response content twice #21

di97mni opened this issue Sep 15, 2016 · 4 comments

Comments

@di97mni
Copy link

di97mni commented Sep 15, 2016

public class MockHttpMessageHandlerTests
{
    //this test is OK and copied from tests in this repo
    [Fact]
    public void Should_respond_with_basic_requests()
    {
        var mockHandler = new MockHttpMessageHandler();

        mockHandler
            .When("/test")
            .Respond("application/json", "{'Status' : 'OK'}");

        var httpClient = new HttpClient(mockHandler);
        var result = httpClient.GetAsync("http://invalid/test").Result;

        Assert.Equal(System.Net.HttpStatusCode.OK, result.StatusCode);
        Assert.Equal("application/json", result.Content.Headers.ContentType.MediaType);
        var responseDto = result.Content.ReadAsAsync<ResponseDto>().Result;
        Assert.Equal("OK", responseDto.Status);
    }

    //this test fails
    [Fact]
    public void Should_respond_with_basic_requests_2()
    {
        var mockHandler = new MockHttpMessageHandler();

        mockHandler
            .When("/test")
            .Respond("application/json", "{'Status' : 'OK'}");

        var httpClient = new HttpClient(mockHandler);
        var result = httpClient.GetAsync("http://invalid/test").Result;

        Assert.Equal(System.Net.HttpStatusCode.OK, result.StatusCode);
        Assert.Equal("application/json", result.Content.Headers.ContentType.MediaType);
        var responseDto = result.Content.ReadAsAsync<ResponseDto>().Result;
        Assert.Equal("OK", responseDto.Status);

        result = httpClient.GetAsync("http://invalid/test").Result;
        Assert.Equal(System.Net.HttpStatusCode.OK, result.StatusCode);
        Assert.Equal("application/json", result.Content.Headers.ContentType.MediaType);
        responseDto = result.Content.ReadAsAsync<ResponseDto>().Result;

        //this fails due to responseDto is null. 
        Assert.Equal("OK", responseDto.Status);
    }
}

public class ResponseDto
{
    public string Status { get; set; }
}
@di97mni
Copy link
Author

di97mni commented Sep 15, 2016

If I change to this

mockHandler
  .When("/test")
  .Respond(HttpStatusCode.OK, new ObjectContent<ResponseDto>(new ResponseDto("OK"), new JsonMediaTypeFormatter()));

Then response content is not null the second time. But it would be good if the json string would work because that's the format I have in my expected payloads. I would like to avoid creating the Dtos before the mocks.

@richardszalay
Copy link
Owner

richardszalay commented Sep 16, 2016

Hi Martin,

This is actually a limitation with how ReadAsAsync<T> uses HttpContent, and has nothing to do with MockHttp.

HttpContentExtensions.ReadAsAsync<T> calls HttpContent.ReadAsStreamAsync, which reuses the existing memory buffer without resetting it's position, which causes ReadAsAsync<T> to return null since it thinks there's no data.

There's not much point attempting to workaroud this in my opinion, so I'd advise simply limiting your application to only call ReadAsAsync<T> once.

Cheers,
Richard

@richardszalay
Copy link
Owner

It just occurred to me that you are actually making the request twice, so the real HttpClient would actually send back two different responses. This is definitely a bug in MockHttp's behavior. Thanks for bringing it to my attention.

I'll look at fixing this behavior, but in the meantime you can workaround it by using a different Respond overload that creates a new HttpConent each time:

mockHandler
    .When("/test")
    .Respond(req => new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new StringContent("{'Status' : 'OK'}", Encoding.UTF8, "application/json")
    });

@richardszalay
Copy link
Owner

This has been resolved in v1.3.1, now available on NuGet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants