250

I'm trying to get content of HttpResponseMessage. It should be: {"message":"Action '' does not exist!","success":false}, but I don't know, how to get it out of HttpResponseMessage.

HttpClient httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.GetAsync("http://****?action=");
txtBlock.Text = Convert.ToString(response); //wrong!

In this case txtBlock would have value:

StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Vary: Accept-Encoding
  Keep-Alive: timeout=15, max=100
  Connection: Keep-Alive
  Date: Wed, 10 Apr 2013 20:46:37 GMT
  Server: Apache/2.2.16
  Server: (Debian)
  X-Powered-By: PHP/5.3.3-7+squeeze14
  Content-Length: 55
  Content-Type: text/html
}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Clem
  • 11,334
  • 8
  • 34
  • 48

10 Answers10

524

I think the easiest approach is just to change the last line to

txtBlock.Text = await response.Content.ReadAsStringAsync(); //right!

This way you don't need to introduce any stream readers and you don't need any extension methods.

rudivonstaden
  • 7,675
  • 5
  • 26
  • 41
  • 8
    Not sure why this isn't the accepted answer, especially since this gives you the ability to easily serialize contents into your objects. – Jason McKindly Jan 27 '16 at 16:59
  • 5
    ReadAsStringAsync does not handle errors well IMHO. – stannius Apr 15 '16 at 15:45
  • 29
    You could also use Response.Content.ReadAsStringAsync().Result instead of using await – Justin Jul 18 '16 at 17:53
  • 8
    Beware though: ReadAsStringAsync() can throw if you have emoticons or some other Unicode characters in the response. I had to use Streams (like in the accepted answer) to overcome that. – Ginkgo Apr 16 '17 at 09:36
  • That's soooo counter-intuitive! Why didn't they make it more obvious? Agree that this should be the accepted answer. Glad it's got the most votes. – Avrohom Yisroel May 16 '22 at 13:59
77

You need to call GetResponse().

Stream receiveStream = response.GetResponseStream ();
StreamReader readStream = new StreamReader (receiveStream, Encoding.UTF8);
txtBlock.Text = readStream.ReadToEnd();
Icemanind
  • 47,519
  • 50
  • 171
  • 296
  • 39
    Thanks, but why i get this error here: "System.Net.Http.HttpResponseMessage' does not contain a definition for 'GetResponseStream' and no extension method 'GetResponseStream' accepting a first argument of type 'System.Net.Http.HttpResponseMessage' could be found" – Clem Apr 10 '13 at 21:00
  • 19
    @Klemzy - Because you are calling it Asynchronisly. Try using `Content` property instead. Look at the [example here](http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh781239.aspx). Scroll down to the second step. – Icemanind Apr 10 '13 at 21:03
  • Yes, but don't know how :) Sorry i'm beginner in c# – Clem Apr 10 '13 at 21:08
  • 2
    @Klemzy - Look at the [example here](http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh781239.aspx). Scroll down to the second step. If you can't figure it out, I'll edit my answer and give you an example for you – Icemanind Apr 10 '13 at 21:08
  • 24
    This answer is totally off-topic, the OP is using `HttpClient`, not `HttpWebRequest` / `HttpWebResponse`. – Maxime Rossini Mar 16 '17 at 23:07
  • 3
    The question is in regard to HttpCient, your response is based on outdated and obsolete HttpWebRequest. – Payam Nov 28 '17 at 18:02
  • Is it purposefully not disposed of Streams? I know this might sound like a silly question for those who are used to dispose of everything that implements IDisposable but there are exceptions like for example HttpClient. – Almis Aug 20 '19 at 10:24
45

Try this, you can create an extension method like this:

    public static string ContentToString(this HttpContent httpContent)
    {
        var readAsStringAsync = httpContent.ReadAsStringAsync();
        return readAsStringAsync.Result;
    }

and then, simple call the extension method:

txtBlock.Text = response.Content.ContentToString();

I hope this help you ;-)

MCurbelo
  • 4,097
  • 2
  • 26
  • 21
  • By far the easiest to get up and running – Aage May 09 '17 at 12:34
  • 1
    Please use `await` instead of `.Result`... or use a synchronous HTTP client instead, if your code can't handle async programming. But any modern code should, otherwise it may be a sign your application is doing something wrong. – Maxime Rossini Jan 10 '20 at 08:50
17

If you want to cast it to specific type (e.g. within tests) you can use ReadAsAsync extension method:

object yourTypeInstance = await response.Content.ReadAsAsync(typeof(YourType));

or following for synchronous code:

object yourTypeInstance = response.Content.ReadAsAsync(typeof(YourType)).Result;

Update: there is also generic option of ReadAsAsync<> which returns specific type instance instead of object-declared one:

YourType yourTypeInstance = await response.Content.ReadAsAsync<YourType>();
taras-mytofir
  • 170
  • 1
  • 6
  • 3
    object yourTypeInstance = await response.Content.ReadAsAsync(typeof(YourType)); should be var yourTypeInstance = await response.Content.ReadAsAsync(); – Thomas.Benz Oct 25 '17 at 15:55
  • I used Request.Content.ReadAsAsync to parse Json and got horrible performance. – W.Leto Dec 20 '18 at 20:10
8

By the answer of rudivonstaden

txtBlock.Text = await response.Content.ReadAsStringAsync();

but if you don't want to make the method async you can use

txtBlock.Text = response.Content.ReadAsStringAsync();
txtBlock.Text.Wait();

Wait() it's important, becаuse we are doing async operations and we must wait for the task to complete before going ahead.

chwarr
  • 6,777
  • 1
  • 30
  • 57
stanimirsp
  • 2,548
  • 2
  • 26
  • 36
  • 3
    using `.Result` any different?, `httpContent.ReadAsStringAsync().Result` – mkb Sep 05 '19 at 21:40
  • `.Result` would block the thread's execution on that line... where as `txtBlock.Text.Wait()` blocks on the wait() call... so you're correct that basically there is no difference. But I suspect `txtBlock.Text.Wait()` would take a optional integer parameter so the GUI does not hang if the previous `ReadAsStringAsync()` call never returns. For example the following would block for no more than 1 second `txtBlock.Text.Wait(1000)` – benhorgen Jun 30 '20 at 20:33
7

The quick answer I suggest is:

response.Result.Content.ReadAsStringAsync().Result

benhorgen
  • 1,928
  • 1
  • 33
  • 38
  • 4
    Do NOT call `Result` on tasks. You risk locking up your application. Use async/await instead. – eltiare Jun 14 '20 at 00:00
  • I would not say never... sometimes quick and dirty gets it done. But I agree you do run the risk of `ReadAsStringAsync()` not returning, so make sure not to call it on your GUI or main application thread. – benhorgen Jun 15 '20 at 15:39
  • Good or almost good. I needed to code like this: HttpResponseMessage response = ....; var responseBody = await response?.Content.ReadAsStringAsync(); – Gerard Jaryczewski Dec 02 '20 at 12:15
  • If I understand your question correctly, I would answer "almost good". Depending on your code execution pattern (e.g. single thread or multi-threaded) should determine your approach. In regards to this answer which you're commenting on (assuming single threaded execution is ok) then I would call `var responseBody = response.Content.ReadAsStringAsync().Result;` – benhorgen Dec 03 '20 at 04:36
  • 1
    It's generally bad practice to call `.Result` on a task, you'll block the main thread. – db2 Jun 24 '21 at 13:10
  • Response does not have a Result property. Correct would be `string result = await response.Content.ReadAsStringAsync()` – John Sivertsen Mar 23 '22 at 13:05
  • 1
    Doesn't calling `await` implicitly block the main thread too? I.e. the same as getting `.Result` – OneCricketeer Aug 26 '22 at 23:11
1

I think the following image helps for those needing to come by T as the return type.

enter image description here

0

You can use the GetStringAsync method:

var uri = new Uri("http://yoururlhere");
var response = await client.GetStringAsync(uri);
Hinrich
  • 13,485
  • 7
  • 43
  • 66
0

Using block:

using System;
using System.Net;
using System.Net.Http;

This Function will create new HttpClient object, set http-method to GET, set request URL to the function "Url" string argument and apply these parameters to HttpRequestMessage object (which defines settings of SendAsync method). Last line: function sends async GET http request to the specified url, waits for response-message's .Result property(just full response object: headers + body/content), gets .Content property of that full response(body of request, without http headers), applies ReadAsStringAsync() method to that content(which is also object of some special type) and, finally, wait for this async task to complete using .Result property once again in order to get final result string and then return this string as our function return.

static string GetHttpContentAsString(string Url)
    {   
        HttpClient HttpClient = new HttpClient();
        HttpRequestMessage RequestMessage = new HttpRequestMessage(HttpMethod.Get, Url);
        return HttpClient.SendAsync(RequestMessage).Result.Content.ReadAsStringAsync().Result;
    }

Shorter version, which does not show the full "transformational" path of our http-request and uses GetStringAsync method of HttpClient object. Function just creates new instance of HttpClient class (an HttpClient object), uses GetStringAsync method to get response body(content) of our http request as an async-task result\promise, and then uses .Result property of that async-task-result to get final string and after that simply returns this string as a function return.

static string GetStringSync(string Url)
    {
        HttpClient HttpClient = new HttpClient();
        return HttpClient.GetStringAsync(Url).Result;
    }

Usage:

const string url1 = "https://microsoft.com";
const string url2 = "https://stackoverflow.com";

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; /*sets TLC protocol version explicitly to modern version, otherwise C# could not make http requests to some httpS sites, such as https://microsoft.com*/

Console.WriteLine(GetHttpContentAsString(url1)); /*gets microsoft main page html*/
Console.ReadLine(); /*makes some pause before second request. press enter to make second request*/
Console.WriteLine(GetStringSync(url2)); /*gets stackoverflow main page html*/
Console.ReadLine(); /*press enter to finish*/

Full code:

enter image description here

vritme
  • 1
  • 2
0

Updated answer as of 2022-02:

var stream = httpResponseMessage.Content.ReadAsStream();
var ms = new MemoryStream();
stream.CopyTo(ms);
var responseBodyBytes = ms.ToArray();
Conway
  • 47
  • 2
  • 5