-2

Two years ago, in an ASP.NET Core 8 MVC web app, I used HttpClient to make HTTP requests to an API, like this:

HttpClientHandler httpClientHandler = new HttpClientHandler()
{
    Credentials = new NetworkCredential(configuration[Id], configuration[Pwd])
};

using var client = new HttpClient(httpClientHandler);
client.DefaultRequestHeaders.Add("Accept", "application/xml");

var result = client.GetAsync($"{configuration[Host]}/api/example").Result;

I know this is not the recommended way to use HttpClient but I needed to set the basic authentication credentials and the API's base address (host) dynamically so I couldn't register a static HttpClient with the DI container of the app; doing so seemed to be extremely complicated because the Host, Id, and Pwd settings exist both in appsettings.json and appsettings.Development.json and are user-profile based, for example:

"API": {
  "Debug": {
      "Host": "...",
      "Id": "...",
      "Pwd": "..."
  },
  "Production": {
    "Host": "...",
    "PartnerId": "...",
    "Pwd": "..."
  }
}

where "Debug" and "Production" are two profiles and the actual profile is based on the logged-in user and therefore it's determined at runtime.

For two years the above code worked fine until yesterday when all requests started to fail with response:

<?xml version="1.0" encoding="UTF-8"?>
<error>
  <message context="ForbiddenException">Forbidden resource</message>
</error>

Of course, at first, I suspected that something has changed on the API side. Nevertheless, sending the same requests from Postman worked fine! Replacing HttpClient with HttpWebRequest worked fine, too!

Anyone knows how can I discover what is suddenly wrong with the HttpClient requests?

11
  • 6
    HttpClient works fine, probably the server got unhappy with what you were sending it. Almost certainly a missing/incorrect header. Use a transparent proxy such as Fiddler to compare working and non-working response to see what the difference is. Also don't ever use .Result use var result = await client.GetAsync($"{configuration[Host]}/api/example"); instead Commented Feb 5 at 12:28
  • Have a look into this answer: stackoverflow.com/a/12023307/982149 Is it for you, perhaps? Commented Feb 5 at 12:35
  • 3
    Totally understand your frustration. However I would recommend removing the superfluous diatribe at the end of your question. I think that's why you're getting downvoted. Commented Feb 5 at 13:35
  • 1
    Your own question proves that nothing's wrong with HttpClient - in .NET 8 (and all .NET Core versions) HttpWebRequest is nothing more than a compatibility wrapper over HttpClient. The credentials may be wrong, or there may be something wrong on the server. You can easily use settings loaded from configuration in AddHttpClient as several of the overloads pass IServiceProvider as a parameter. Commented Feb 5 at 14:26
  • 1
    Are you sure that Basic Authentication was used? NetworkCredential is used for multiple authentication types, including NTLM, Basic, Kerberos. The NetworkCredentials documentation adds the credential to a CredentialCache with an explicit authentication type. Perhaps the code was using NTLM until now and the server disabled it? Commented Feb 5 at 14:47

1 Answer 1

1

After taking all comments into serious consideration here's what I came up with:

Program.cs

services.AddHttpClient<MyService>();

MyService.cs

private readonly HttpClient _httpClient;

public MyService(HttpClient httpClient)
{
  _httpClient = httpClient;
  _httpClient.BaseAddress = new Uri(baseAddress);
  _httpClient.DefaultRequestHeaders.Add("Accept", "application/xml");        
  _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
}

all requests are made by setting up a HttpRequestMessage and calling SendAsync:

var request = new HttpRequestMessage
{
    Method = method,
    RequestUri = new Uri(endpoint, UriKind.Relative),
    Content = !string.IsNullOrEmpty(body) ? new StringContent(body, Encoding.UTF8, "application/xml") : null,
};            
            
var response = await _httpClient.SendAsync(request);

Goals achieved:

  • Successful requests to the API
  • Use of Basic authentication
  • Single, static, typed HttpClient injected as per the guidelines
  • async/await instead of .Results

Thanks to all commentators. @PanagiotisKanavos, most probably you're right. It used to work. The response error suggests that something was wrong with the authentication. Maybe something was changed on the API side. Whatever it was it affected HttpClient but not HttpWebRequest. The latter is something I would very much like to know exactly why.

Sign up to request clarification or add additional context in comments.

1 Comment

Whatever it was it affected HttpClient but not HttpWebRequest. that means the problem is in the application code. Look at the source code of HttpWebRequest.cs private static volatile HttpClient? s_cachedHttpClient; ... private HttpClient? _httpClient;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.