5

When testing my web API with Postman my API get executes fine!

When it comes to running the code with HttpClient in my client application the code executes without error but without the expected result on the server. What could be happening?

From my client application:

private string GetResponseFromURI(Uri u)
{
    var response = "";
    HttpResponseMessage result;
    using (var client = new HttpClient())
    {
        Task task = Task.Run(async () =>
        {
            result = await client.GetAsync(u);
            if (result.IsSuccessStatusCode)
            {
                response = await result.Content.ReadAsStringAsync();
            }
        });
        task.Wait();
    }
    return response;
}

Here is the API controller:

[Route("api/[controller]")]
public class CartsController : Controller
{
    private readonly ICartRepository _cartRepo;

    public CartsController(ICartRepository cartRepo)
    {
        _cartRepo = cartRepo;
    }

    [HttpGet]
    public string GetTodays()
    {
        return _cartRepo.GetTodaysCarts();
    }

    [HttpGet]
    [Route("Add")]
    public string GetIncrement()
    {
        var cart = new CountedCarts();
        _cartRepo.Add(cart);

        return _cartRepo.GetTodaysCarts();
    }

    [HttpGet]
    [Route("Remove")]
    public string GetDecrement()
    {
        _cartRepo.RemoveLast();
        return _cartRepo.GetTodaysCarts();
    }


}

Note these API calls work as expected when called from Postman.

user3079834
  • 2,009
  • 2
  • 31
  • 63
CAD.Dev
  • 187
  • 1
  • 1
  • 12
  • 2
    Word of warning, `HttpClient` is meant to be reused as a single instance. Wrapping it in a using statement or newing one up for every call can have [adverse](http://stackoverflow.com/questions/15705092/do-httpclient-and-httpclienthandler-have-to-be-disposed) effects. – maccettura Mar 31 '17 at 19:26
  • 1
    Use Fiddler to compare both Requests. Probably missing Headers. – burnsi Mar 31 '17 at 19:27
  • Thanks for the warning @maccettura I pulled the httpclient out into a static field, same results. – CAD.Dev Mar 31 '17 at 19:55
  • Sorry, I did not mean to imply that would fix your issue. I just wanted to point out that `HttpClient` is one of few instances where you wouldn't want to dispose after every use. – maccettura Mar 31 '17 at 19:58
  • 1
    I just wanted to point out, any 'adverse' effects from disposing of HTTPClient, in my case, did not attribute to the issue. – CAD.Dev Mar 31 '17 at 20:02
  • How do you access those action methods - GetTodays, GetIncrement and GetDecrement? Could you show the URLs? – Win Mar 31 '17 at 22:00

5 Answers5

21

You shouldn't use await with client.GetAsync, It's managed by .Net platform, because you can only send one request at the time.

just use it like this

var response = client.GetAsync("URL").Result;  // Blocking call!

            if (response.IsSuccessStatusCode)
            {
                // Parse the response body. Blocking!
                var dataObjects = response.Content.ReadAsAsync<object>().Result;

            }
            else
            {
                var result = $"{(int)response.StatusCode} ({response.ReasonPhrase})";
               // logger.WriteEntry(result, EventLogEntryType.Error, 40);
            }
Joe
  • 2,381
  • 1
  • 17
  • 17
  • 1
    i didn't understand why. but it works as you said, otherwise my debugger would stop on the await line and never catches back again! I guess I need to revise again how await and result work! .. Thanks you saved my day – A Khudairy Jul 02 '18 at 12:15
  • This saved my day. My debugger was skipping the rest of the method after the `await client.GetAsync(..)`. – Nir Lanka Jul 30 '19 at 04:41
8

You are doing fire-and-forget approach. In your case, you need to wait for the result.

For example,

static async Task<string> GetResponseFromURI(Uri u)
{
    var response = "";
    using (var client = new HttpClient())
    {
        HttpResponseMessage result = await client.GetAsync(u);
        if (result.IsSuccessStatusCode)
        {
            response = await result.Content.ReadAsStringAsync();
        }
    }
    return response;
}

static void Main(string[] args)
{
    var t = Task.Run(() => GetResponseFromURI(new Uri("http://www.google.com")));
    t.Wait();

    Console.WriteLine(t.Result);
    Console.ReadLine();
}
Win
  • 61,100
  • 13
  • 102
  • 181
  • I implemented this and the behavior didn't change. I am starting to think i am using get when i should be using put. The path in the api is a get response that is incrementing a counter... it only works the first call. – CAD.Dev Mar 31 '17 at 19:37
  • Before we go any further, could you check with `http://www.google.com` URL? – Win Mar 31 '17 at 19:39
  • It does, it also "appears" to work using my Uri. When the Uri is called, the counter increments and the result is returned. I also have an api call for decrementing using a similar approach. It just isn't incrementing. – CAD.Dev Mar 31 '17 at 19:42
  • CartsController violates basic REST principle - HttpGet should not change anything on the server - idempotent and safe. – Win Mar 31 '17 at 20:01
1

Simple sample used to get page data.

public string GetPage(string url)
{
    HttpResponseMessage response = client.GetAsync(url).Result;

    if (response.IsSuccessStatusCode)
    {
        string page = response.Content.ReadAsStringAsync().Result;
        return "Successfully load page";
    }
    else
    {
        return "Invalid Page url requested";
    }
}
niek tuytel
  • 899
  • 7
  • 18
0

I've had a problem with chace control when using httpclient.

HttpBaseProtocalFilter^ filter = ref new HttpBaseProtocolFilter();
filter->CacheControl->ReadBehavior = Windows::Web::Http::Filters::HttpCacheReadBehavior::MostRecent;
HttpClient^ httpClient = ref new HttpClient(filter);

I'm not really sure what the expected results are or what results your getting at all so this is really just a guessing game right now.

When I POST something using HttpClient I found adding headers by hand seemed to work more often than using default headers.

auto httpClient = ref new HttpClient();
Windows::Web::Http::Headers::HttpMediaTypeHeaderValue^ type = ref new Windows::Web::http::Headers::HttpMediaTypeHeaderValue("application/json");
content->Headers->ContentType = type;

If I don't do these 2 things I found, for me anyways, that half the time my web requests were either not actually being sent or the headers were all messed up and the other half of the time it worked perfectly.

I just read a comment where you said it would only fire once, that makes me think it is the cachecontrol. I think what happens is something (Windows?) sees 2 requests being sent that are the exact same, so to speed things up it just assumes the same answer and never actually sends the request a 2nd time

user3164339
  • 165
  • 14
0

Since you are able to hit the API endpoint with Postman, you should be able to get the working code of HttpClient for the same in Postman. Just click "</>" on the right-hand side. It gives code in many languages including C#'s HttpClient