Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core Httpclient works but .Net Framework 4.7.2 httpclient doesn't

Sorry for the awful title, I'm not really sure how to phrase my issue in a short title format.

I'm trying to communicate with an external API. I make a basic authentication request to that API and get an x-csrf-token and a session token from the api.

I then make another request to that API, now using the x-csrf-token as a header and attach the session token to the header as "cookie".

The team that maintains the API sent me an example project that handles all of the above, and it looks like this:

public static async Task<string> Send(string apiname, string value)
{
    // Fetch the authorization tokens from SAP
    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri(basePath);
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(user + ":" + password)));
    client.DefaultRequestHeaders.Add("x-csrf-token", "Fetch");
    string csrfToken = "";
    string sessionCookie = "";
    HttpResponseMessage response = await client.GetAsync(string.Empty);
    IEnumerable<string> values;
    if (response.Headers.TryGetValues("x-csrf-token", out values))
    {
        csrfToken = values.FirstOrDefault();
    }
    if (response.Headers.TryGetValues("set-cookie", out values))
    {
        sessionCookie = values.Where(s => s.StartsWith("SAP_SESSION")).FirstOrDefault();
    }

    // Reinstantiate the HttpClient, adding the tokens we just got from SAP
    client = new HttpClient();
    client.DefaultRequestHeaders.Add("x-csrf-token", csrfToken);
    client.DefaultRequestHeaders.Add("cookie", sessionCookie);
    client.BaseAddress = new Uri(basePath);
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    // Have to parse the string this way otherwise it'll break the dates
    JToken token;
    using (var sr = new StringReader(value))
    using (var jr = new JsonTextReader(sr) { DateParseHandling = DateParseHandling.None })
    {
        token = JToken.ReadFrom(jr);
    }
    HttpResponseMessage response2 = await client.PostAsJsonAsync(apiname, token);
    string responseBody = await response2.Content.ReadAsStringAsync();
    return responseBody;
}

This all works great as a .NET Core webAPI (and also as a .netcore console app).

Interestingly enough (in my opinion anyway), when I use the exact same code in a .net 4.7.2 project, it doesn't append the "cookie" header properly, and so I'm getting an unauthorized redirect back from the API.

To be absolutely sure that I didn't change any code, I started from scratch with a brand new .netcore 2.0 console app and a brand new .net 4.7.2 console app and copy-pasted the exact same code and installed the same nuget packages (Newtonsoft.JSON and Microsoft.WebApi.Client). I inspected my web traffic with fiddler (seen below) and you can see that in .netcore, the cookie appends properly and everything works, but in .net 4.7.2, the API returns a redirect to authenticate.

enter image description here

like image 604
Alex Kibler Avatar asked Aug 06 '19 13:08

Alex Kibler


1 Answers

HttpClient will eat the custom cookie if you do not setUseCookies to false,

using (var handler = new HttpClientHandler { UseCookies = false })
using (client = new HttpClient(handler) { BaseAddress = new Uri(Path) }){
      client.DefaultRequestHeaders.Add("cookie", cookieValue);
}

It will try to use the cookie container and at the same time ignore any custom cookie headers, very frustrating behavior if you ask me.

like image 80
Andrew Pier Avatar answered Sep 28 '22 13:09

Andrew Pier