6

I have the below code, working as expected (given correct URL etc) as a POST request. Seems I have a problem reading the Status Code (I receive a successful 201, and based on that number I need to continue processing). Any idea how to get the status code?

static async Task CreateConsentAsync(Uri HTTPaddress, ConsentHeaders cconsentHeaders, ConsentBody cconsent)
{
    HttpClient client = new HttpClient();

    try
    {
        client.BaseAddress = HTTPaddress;
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
        client.DefaultRequestHeaders.Add("Connection", "keep-alive");
        client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");

        client.DefaultRequestHeaders.Add("otherHeader", myValue);
        //etc. more headers added, as needed...

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);

        request.Content = new StringContent(JsonConvert.SerializeObject(cconsent, Formatting.Indented), System.Text.Encoding.UTF8, "application/json");

        Console.WriteLine("\r\n" + "POST Request:\r\n" + client.DefaultRequestHeaders + "\r\nBody:\r\n" + JsonConvert.SerializeObject(cconsent, Formatting.Indented) + "\r\n");

        await client.SendAsync(request).ContinueWith
        (
            responseTask => 
            {
                Console.WriteLine("Response: {0}", responseTask.Result + "\r\nBody:\r\n" + responseTask.Result.Content.ReadAsStringAsync().Result);
            }
        );

        Console.ReadLine();
    }
    catch (Exception e)
    {
        Console.WriteLine("Error in " + e.TargetSite + "\r\n" + e.Message);
        Console.ReadLine();
    }
}
Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Nick
  • 483
  • 1
  • 6
  • 15
  • You're already in an `async` function, so you don't need to use `ContinueWith`. – Dai Dec 11 '19 at 10:59

4 Answers4

8

There is a Status code in your Result.

responseTask.Result.StatusCode

Or even better

    var response = await client.SendAsync(request);
    var statusCode = response.StatusCode;
Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61
  • Will the above not simply return with the response `OK` if successful? Isn't OP also asking for the code number? – JamesS Dec 11 '19 at 11:21
  • This will return the status code. Ok is 200, if it is something else, it will be that value. – Athanasios Kataras Dec 11 '19 at 11:21
  • 2
    Yeah, to return the statuscode value you would need to do `(int)response.StatusCode` – JamesS Dec 11 '19 at 11:28
  • There are multiple enums for status code. https://learn.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode?view=netframework-4.8 You can compare with it. – Athanasios Kataras Dec 11 '19 at 11:30
  • @Athanasios Kataras: extremely useful tip. I do var response await client.SendAsync(request).ContinueWith(responseTask => {Console.WriteLine("RESPONSE: {0}", responseTask.Result.... and then "int statusCode = (int)response.StatusCode;" but I get an error message on the first statement (the var response await...) : Implicitly typed variables must be initialized. What am I missing please?... – Nick Dec 11 '19 at 12:02
  • 1
    The continue with, returns a `Task` not a response value so the var needs to be changed to `HttpResponseMessage response = await ...`. I would suggest that you remove the continueWith as it is not needed at all, and proceed with the code I shared with you above (withou the continueWith). – Athanasios Kataras Dec 11 '19 at 12:15
2
  • It helps to avoid using ContinueWith if you're already inside an async function because you can use the (much cleaner) await keyword.

  • If you await the SendAsync call you'll get a HttpResponseMessage object you can get the status code from:

  • Also, wrap your IDisposable objects in using() blocks (except HttpClient - which should be a static singleton or better yet, use IHttpClientFactory).

  • Don't use HttpClient.DefaultRequestHeaders for request-specific headers, use HttpRequestMessage.Headers instead.

  • The Connection: Keep-alive header will be sent by HttpClientHandler automatically for you.
  • Are you sure you need to send Cache-control: no-cache in the request? If you're using HTTPS then it's almost guaranteed that there won't be any proxy-caches causing any issues - and HttpClient does not use the Windows Internet Cache either.
  • Don't use Encoding.UTF8 because it adds a leading byte-order-mark. Use a private UTF8Encoding instance instead.
  • Always use .ConfigureAwait(false) with every await on code that does not run in a thread-sensitive context (such as WinForms and WPF).
private static readonly HttpClient _httpClient = new HttpClient();
private static readonly UTF8Encoding _utf8 = new UTF8Encoding( encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true );

static async Task CreateConsentAsync( Uri uri, ConsentHeaders cconsentHeaders, ConsentBody cconsent )
{
    using( HttpRequestMessage req = new HttpRequestMessage( HttpMethod.Post, uri ) )
    {
        req.Headers.Accept.Add( new MediaTypeWithQualityHeaderValue("*/*") );
        req.Headers.Add("Cache-Control", "no-cache");
        req.Headers.Add("otherHeader", myValue);
        //etc. more headers added, as needed...

        String jsonObject = JsonConvert.SerializeObject( cconsent, Formatting.Indented );
        request.Content = new StringContent( jsonObject, _utf8, "application/json");

        using( HttpResponseMessage response = await _httpClient.SendAsync( request ).ConfigureAwait(false) )
        {
            Int32 responseHttpStatusCode = (Int32)response.StatusCode;
            Console.WriteLine( "Got response: HTTP status: {0} ({1})", response.StatusCode, responseHttpStatusCode );
        }
    }
}
Dai
  • 141,631
  • 28
  • 261
  • 374
  • thank you very much for your response (pun not intended :-) - how could I "get a HttpResponseMessage object" and read the number (i.e. 200 or 201 etc) - could you post a snipet please? Also important: how may I avoid the ContinueWith in the above code? THANK you in advance! – Nick Dec 11 '19 at 11:31
  • Thank you very much, as a matter of fact is a good upgrade on my code. However, the ConsoleWriteLine("Got response... returns a string ("Created" in my case, depends on the rest API of course - but not the HTTP code, I was expecting int, i.e. 200, 201 etc) – Nick Dec 11 '19 at 15:54
  • @Nick To get the `Int32`/`int` status code, cast the `StatusCode` property. I've updated my answer. – Dai Dec 11 '19 at 16:02
1

You could simply check the StatusCode property of the response:

https://learn.microsoft.com/en-us/previous-versions/visualstudio/hh159080(v=vs.118)?redirectedfrom=MSDN

static async void dotest(string url)
{
    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response = await client.GetAsync(url);

        if (response.IsSuccessStatusCode)
        {
            Console.WriteLine(response.StatusCode.ToString());
        }
        else
        {
            // problems handling here
            Console.WriteLine(
                "Error occurred, the status code is: {0}", 
                response.StatusCode
            );
        }
    }
}
Ankur Tripathi
  • 671
  • 9
  • 35
  • The `response` object should be wrapped in a `using` block. Also, `HttpClient` objects should not be short-life'd (so don't dispose of the `HttpClient` immediately). – Dai Dec 11 '19 at 11:05
0

@AthanasiosKataras is correct for returning the status code itself but if you would also like to return the status code value (ie 200, 404). You can do the following:

var response = await client.SendAsync(request);
int statusCode = (int)response.StatusCode

The above will give you the int 200.

EDIT:

Is there no reason why you cannot do the following?

using (HttpResponseMessage response = await client.SendAsync(request))
{
    // code
    int code = (int)response.StatusCode;
}
JamesS
  • 2,167
  • 1
  • 11
  • 29
  • this seems soooo close!! How may I modified my statement? await client.SendAsync(request).ContinueWith(responseTask => { Console.WriteLine("RESPONSE: {0}", responseTask.Result.StatusCode); }); When I use this, I get a string, i.e. "Created" etc. but when I use responseTask.Result.StatusCode.GetTypeCode(); I receive Int32 !!! Where is this 200 or 201 number....? – Nick Dec 11 '19 at 11:58
  • @Nick `(int)responseTask.Result.StatusCode` – JamesS Dec 11 '19 at 12:01
  • As per previous comment: extremely useful tip. I do var response await client.SendAsync(request).ContinueWith(responseTask => {Console.WriteLine("RESPONSE: {0}", responseTask.Result.... and then "int statusCode = (int)response.StatusCode;" but I get an error message on the first statement (the var response await...) : Implicitly typed variables must be initialized. What am I missing please?... – Nick Dec 11 '19 at 12:03
  • @Nick If you stop it on `response`, does it have a value? – JamesS Dec 11 '19 at 12:46
  • you mean at var response = await client... etc.. ? It throws error there unfortunately, and I desperately want to debug it.. Says "Implicitly-typed variables must be initialized" but i don't know as what to initialize it.. – Nick Dec 11 '19 at 14:13
  • Trying it right now.. I have modified as per Dai's my code – Nick Dec 11 '19 at 16:03
  • SUCCESS ! @Dai: I used your code - BUT - I used the (int) code = (int)response.StatusCode as per JamesS comment. Unfortunately, I tried JamesS using (HttpResponseMessage response = await client.SendAsync(request)) but couldn't make it - ALTHOUGH I tried in a smalled brand new project and worked. However, I have to admit Dai's code was significantly closer. Kindly accept my sincere THANKS for the help, this thing was a headache.. – Nick Dec 11 '19 at 16:07