0

I have an ASP.NET Core Web API service built using .NET 6 that makes http requests using C# HttpClientFactory to external services.

The issue I am facing is that the second request with different arguments returns same result as for the previous request.

I tried clearing default headers at the start of every request no luck.

What worked for me:

  1. RestSharp: https://restsharp.dev/
  2. Using new HttpClient() instance instead of httpClientFactory.CreateClient()

I would like to make it work with httpClientFactory as this is the recommended way. Any thoughts why much appreciated.

// Each request has different access token but same body
public async Task<MyResponse> GetXyz(object requestBody, string accessToken)
{
    var uri = "...";
    return await this.httpClientFactory.CreateClient("GetXyz").PostAsync<MyResponse>(uri, requestBody, GetHeaders(accessToken));
}

private static IList<(string, string)> GetHeaders(string accessToken)
{
    var headers = new List<(string, string)>
    {
        (HeaderNames.Accept, "application/json"), 
    };

    if (!string.IsNullOrWhiteSpace(accessToken))
    {
        headers.Add((HeaderNames.Authorization, "Bearer " + accessToken));
    }

    return headers;
}

public static async Task<T> PostAsync<T>(this HttpClient httpClient, string uri, object data, IList<(string, string)> headers = null)
    where T : class
{
    // httpClient.DefaultRequestHeaders.Clear();

    var body = data.Serialise(); // convert to JSON string
    
    using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
    {
        request.AddRequestHeaders(headers);
        request.Content = new StringContent(body, Encoding.UTF8, "application/json");

        using (var httpResponse = await httpClient.SendAsync(request))
        {
            var jsonResponse = await httpResponse.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<T>(jsonResponse);
        }
    }
}

EDIT 2: NETWORK TRAFFIC DIFF

Using Fiddler Classic with basic client httpclientfactory.CreateClient() here are the diffs between 2 requests headers that suffer from the issue: enter image description here

enter image description here

Dan Def
  • 1,836
  • 2
  • 21
  • 39
user1912383
  • 359
  • 2
  • 6
  • 16
  • Are the first and second requests shown in your code above? – codeMonkey Aug 23 '22 at 15:28
  • The requests are by calling GetXyz(body, accessToken1) & GetXyz(body, accessToken2). they have same body but different accesstoken in header – user1912383 Aug 23 '22 at 15:31
  • 1
    Have you tried to `curl`, or use Postman, to call the endpoint with the access tokens to see if the results are the same outside of your code? If so, have you set a debugger before the second `using` to check that the headers are being set with the correct values? – Stephen Gilboy Aug 23 '22 at 15:35
  • If the body and URI are the same, wouldn't they return the same result? My understanding is the access token only grants you access to the API, so a different access token with same body and URI would still generate the same result (unless maybe one access token confers additional privileges). – codeMonkey Aug 23 '22 at 15:35
  • https://stackoverflow.com/a/55850249/659190 – Jodrell Aug 23 '22 at 15:41
  • 2
    You are using the factory to create a named client, where do you call `services.AddHttpClient("GetXyz", ...`? – Jodrell Aug 23 '22 at 15:47
  • There's nothing wrong with HttpClientFactory. This code is definitely *not* how it's meant to work though, and leaks HttpClient instances. This `PostAsync` method could be replaced with `PostAsJsonAsync`. The bearer token only needs to be added once to the default headers, preferably in the named client configuration – Panagiotis Kanavos Aug 23 '22 at 15:49
  • To deserialize the response you can use [ReadFromJsonAsync](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.json.httpcontentjsonextensions.readfromjsonasync?view=net-6.0#system-net-http-json-httpcontentjsonextensions-readfromjsonasync-1(system-net-http-httpcontent-system-text-json-jsonserializeroptions-system-threading-cancellationtoken)). This eliminates the need for `Task PostAsync(...)` – Panagiotis Kanavos Aug 23 '22 at 15:52
  • @codeMonkey the called service recognizes each user from token and should return the relevant result (and yes it has been tested with postman a lot). – user1912383 Aug 23 '22 at 16:53
  • 1
    @PanagiotisKanavos it cant be in default header as the bearer token changes for each request – user1912383 Aug 23 '22 at 16:53
  • @Jordell i tried the basic and named client approaches and still same issue – user1912383 Aug 23 '22 at 19:58
  • 2
    @user1912383 I advise getting a tool that intercepts the network requests (e.g. Charles or Fiddler, if you go for Fiddler, then configure it for .NET core application as described in the doc here: https://docs.telerik.com/fiddler/configure-fiddler/tasks/configuredotnetapp) There you can see what HTTP requests are actually done / what responses are retrieved, based on that you may have a better insight into what's causing the issue. – DavisZ Aug 23 '22 at 20:22
  • Hello All, could you please have a look at the new update showing network traffic. The Bearer headers seem to be correct it is the cookie which looks suspicious. Thanks – user1912383 Aug 24 '22 at 10:04
  • 1
    Does this answer your question? [How do I set a cookie on HttpClient's HttpRequestMessage](https://stackoverflow.com/questions/12373738/how-do-i-set-a-cookie-on-httpclients-httprequestmessage). The problem is that httpclient reuses its handler AND cookies. – Poul Bak Aug 26 '22 at 11:03

0 Answers0