162

I have a web request that is working properly, but it is just returning the status OK, but I need the object I am asking for it to return. I am not sure how to get the json value I am requesting. I am new to using the object HttpClient, is there a property I am missing out on? I really need the returning object. Thanks for any help

Making the call - runs fine returns the status OK.

HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept
  .Add(new MediaTypeWithQualityHeaderValue("application/json"));
var responseMsg = client.GetAsync(string.Format("http://localhost:5057/api/Photo")).Result;

The api get method

//Cut out alot of code but you get the idea
public string Get()
{
    return JsonConvert.SerializeObject(returnedPhoto);
}
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
user516883
  • 8,868
  • 23
  • 72
  • 114

7 Answers7

245

If you are referring to the System.Net.HttpClient in .NET 4.5, you can get the content returned by GetAsync using the HttpResponseMessage.Content property as an HttpContent-derived object. You can then read the contents to a string using the HttpContent.ReadAsStringAsync method or as a stream using the ReadAsStreamAsync method.

The HttpClient class documentation includes this example:

  HttpClient client = new HttpClient();
  HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
  response.EnsureSuccessStatusCode();
  string responseBody = await response.Content.ReadAsStringAsync();
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • 5
    Haven't tested this but the documentation of EnsureSuccessStatusCode says "If the Content is not null, this method will also call Dispose to free managed and unmanaged resources." so you may wish to read the content first. http://msdn.microsoft.com/en-us/library/system.net.http.httpresponsemessage.ensuresuccessstatuscode(v=vs.110).aspx – Ryan Williams Nov 29 '13 at 02:01
  • 4
    No reason for this. As evidenced by Reflector, EnsureSuccessStatusCode will dispose ONLY if the status code is unsuccesful, right before throwing an exception. Yet another case where the documentation text is slightly confusing. – Panagiotis Kanavos Nov 29 '13 at 07:49
  • 2
    Why not just `client.GetStringAsync(...)`? Was that not around in 2012. They'd both throw an exception if the response was not `200` right? – Simon_Weaver Jan 17 '18 at 05:08
  • 1
    @Simon_Weaver because that wasn't the question - the OP asked how to read the string from the response. There *are* differences. You can't inspect the response with `GetStringAsync` which means you don't know what the response message was. You probably *don't* want to throw if a 3xx response is returned. You probably want to *retry* without throwing if a throttling error is returned. – Panagiotis Kanavos Jan 17 '18 at 08:32
  • 1
    @Simon_Weaver there are a *lot* of ways to make that call - why not `GetAsync` ? Or GetStreamAsync and pass the stream to Json.NET, avoiding the temporary string? Again, it may be preferable to use `GetAsync` first then access the content object – Panagiotis Kanavos Jan 17 '18 at 08:33
  • @PanagiotisKanavos :-) I just wanted to raise the alternatives since this question has so many upvotes and this sample code (while I realize you got it straight from MSDN) does look a bit outdated. Thx for adding the extra info. – Simon_Weaver Jan 17 '18 at 08:37
  • @Liam that's not how HttpClient works. The encoding *is* a Content header. If you want to check the encoding you'd have to check `Content.Headers`, not `HttpResponseMessage.Headers`. `ReasAsStringAsync` *does* check the encoding, both in [.NET Old](https://github.com/microsoft/referencesource/blob/master/System/net/System/Net/Http/HttpContent.cs#L91) and .NET Core. – Panagiotis Kanavos Jul 23 '20 at 10:22
  • 1
    @Liam And here's the [.NET Core code that does check the encoding](https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs#L195). You'd get UTF8 if the header is *missing* or invalid. That's probably what happened in your case - invalid headers – Panagiotis Kanavos Jul 23 '20 at 10:29
74

Building on @Panagiotis Kanavos' answer, here's a working method as example which will also return the response as an object instead of a string:

using System.Text;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json; // Nuget Package

public static async Task<object> PostCallAPI(string url, object jsonObject)
{
    try
    {
        using (HttpClient client = new HttpClient())
        {
            var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
            var response = await client.PostAsync(url, content);
            if (response != null)
            {
                var jsonString = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<object>(jsonString);
            }
        }
    }
    catch (Exception ex)
    {
        myCustomLogger.LogException(ex);
    }
    return null;
}

Keep in mind that this is only an example and that you'd probably would like to use HttpClient as a shared instance instead of using it in a using-clause.

Wouter Vanherck
  • 2,070
  • 3
  • 27
  • 41
  • 2
    Be carefull httpclient does not dispose like that with the using statment – c-sharp-and-swiftui-devni May 25 '19 at 18:17
  • Since await returns immediately, it is possible that `if (response != null)` is executed before the post call has completed? – Nishant Jun 21 '19 at 00:40
  • I don't see a difference, even though you said "return the response as an object instead of a string.", if that is the case, why are you doing an extra manual step using JsonConvert.DeserializedObject(), i.e. you are converting string to object on the client after it has been received (as a string). – joedotnot Jan 08 '21 at 13:09
  • @Nishant: fair question. The code *after* the `await` in that method will NOT execute until the `Task` has completed. Then a thread will be assigned for code in this method to continue executing. The line: `if (response != null)` will not execute until the awaited `Task` on the line preceding has completed. – JohnB Mar 24 '21 at 21:49
58

Install this nuget package from Microsoft System.Net.Http.Json. It contains extension methods.

Then add using System.Net.Http.Json

Now, you'll be able to see these methods:

enter image description here

So you can now do this:

await httpClient.GetFromJsonAsync<IList<WeatherForecast>>("weatherforecast");

Source: https://www.stevejgordon.co.uk/sending-and-receiving-json-using-httpclient-with-system-net-http-json

alansiqueira27
  • 8,129
  • 15
  • 67
  • 111
11

I think the shortest way is:

var client = new HttpClient();
string reqUrl = $"http://myhost.mydomain.com/api/products/{ProdId}";
var prodResp = await client.GetAsync(reqUrl);
if (!prodResp.IsSuccessStatusCode){
    FailRequirement();
}
var prods = await prodResp.Content.ReadAsAsync<Products>();
Greg Z.
  • 1,376
  • 14
  • 17
  • 13
    Just thought id add that ReadAsAsync is an extension method. you will need to use System.Net.Http.Formatting for .net 4+ and Microsoft.AspNet.WebApi.Client for .net core. to get this working. – Squibly Jan 23 '20 at 02:21
2

What I normally do, similar to answer one:

var response = await httpClient.GetAsync(completeURL); // http://192.168.0.1:915/api/Controller/Object

if (response.IsSuccessStatusCode == true)
    {
        string res = await response.Content.ReadAsStringAsync();
        var content = Json.Deserialize<Model>(res);

// do whatever you need with the JSON which is in 'content'
// ex: int id = content.Id;

        Navigate();
        return true;
    }
    else
    {
        await JSRuntime.Current.InvokeAsync<string>("alert", "Warning, the credentials you have entered are incorrect.");
        return false;
    }

Where 'model' is your C# model class.

James Heffer
  • 686
  • 1
  • 6
  • 17
2

It's working fine for me by the following way -

public async Task<object> TestMethod(TestModel model)
    {
        try
        {
            var apicallObject = new
            {
                Id= model.Id,
                name= model.Name
            };

            if (apicallObject != null)
            {
                var bodyContent = JsonConvert.SerializeObject(apicallObject);
                using (HttpClient client = new HttpClient())
                {
                    var content = new StringContent(bodyContent.ToString(), Encoding.UTF8, "application/json");
                    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    client.DefaultRequestHeaders.Add("access-token", _token); // _token = access token
                    var response = await client.PostAsync(_url, content); // _url =api endpoint url
                    if (response != null)
                    {
                        var jsonString = await response.Content.ReadAsStringAsync();

                        try
                        {
                            var result = JsonConvert.DeserializeObject<TestModel2>(jsonString); // TestModel2 = deserialize object
                        }
                        catch (Exception e){
                            //msg
                            throw e;
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return null;
    }
bulbul bd
  • 166
  • 1
  • 1
  • 9
0

The code below is to access your HttpResponseMessage and extract your response from HttpContent.

string result = ret.Result.Content.ReadAsStringAsync().Result;

Convert your json in a structure according with your business In my case BatchPDF is a complex object that it is being populated by result variable.

BatchPDF batchJson = JsonConvert.DeserializeObject<BatchPDF>(result);

return batchJson;