I’m creating an API that serves as the bridge between the app and 2 other APIs. I want to know if what is the best way to do this. I’m using HttpClient. The app has almost a thousand users.
I read this article https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/. Should I really not use the using statement? Also I am doing synchronous api calls. Does this have any effect? Is what I did efficient?
Here is my code:
[HttpGet]
[Route("api/apiname")]
public String GetNumberofP([FromUri]GetNumberofPRequest getNPRequest){
var request = JsonConvert.SerializeObject(getNPRequest);
string errorMessage = "";
try{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.gettoken());
var response = httpClient.GetAsync("api/MobileApp/GetNumberP?"
+ "strCardNumber=" + getNPRequest.strCardNumber
+ "&strDateOfBirth=" + getNPRequest.strDateOfBirth).Result;
return response;
}
catch (Exception e){
throw utils.ReturnException("GetNumberofP", e, errorMessage);
}
}
HttpClient does not need to be disposed and you should hold on to it to reuse it later.
One thing you can use (from the thread you linked):
You just provide your HttpClient factory and dispose methods and the
LimitedPool does the rest:
_httpClientPool = new LimitedPool<httpclient>(
CreateHttpClient, client => client.Dispose(), HttpClientLifetime);
using (var httpClientContainer = _httpClientPool.Get())
{ ... use httpClientContainer.Value ... }
When httpClientContainer is disposed, the HttpClient is actually returned back to the pool for other threads to use. When
lifetime is reached next dispose will eventually call the Dispose
method.
See code here
Alternative for .Net Core
Implement it as described in this document.
The IHttpClientFactory can be registered by calling the AddHttpClient extension method on the IServiceCollection, inside the Startup.ConfigureServices method.
services.AddHttpClient();
Once registered, code can accept an IHttpClientFactory anywhere services can be injected with dependency injection (DI). The IHttpClientFactory can be used to create a HttpClient instance:
public MyConstructor(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
....
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
...
}
No need to use using().
If you are using asp.net core the right way to use HttpClient is explained in this article from Microsoft:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2#typed-clients
I usually use the typed client approach explained in the article.
This basically means that I delegate to the asp.net core container the injection of the http client in my class (a controller class, a service, a filter, whatever)
Doing so you can safely modify the http client in your class by adding all the request headers you need (you usually do it inside the constructor of your class).
You do not have to call dispose on the injected http client, you simply use it.
The asp.net core container will manage the http client lifetime for you and the pool of resources used by http client instances so that your app do not leak resources. All of this happens automatically.
Do not use sync calls. Make your action method async, and await on async methods of http client. Asp.net core fully support async code and make blocking requests does not make sense, doing so you will limit the scalability of your app.
Related
So, I need to implement a Consumer in a WebAPI (.Net core 3.1) application, and reading the Microsoft Documentations and seeing several videos about it, I got to this solution.
This is an extension method for IServiceCollection, I'm calling it from the Startup.cs to instantiate my Consumer (the connection strings and container names are there for tests only):
private static async Task AddPropostaEventHub(this IServiceCollection services)
{
const string eventHubName = "EVENT HUB NAME";
const string ehubNamespaceConnectionString = "EVENT HUB CONNECTION STRING";
const string blobContainerName = "BLOB CONTAINER NAME";
const string blobStorageConnectionString = "BLOB CONNECTION STRING";
string consumerGroup = EventHubConsumerClient.DefaultConsumerGroupName;
BlobContainerClient storageClient = new BlobContainerClient(blobStorageConnectionString, blobContainerName);
EventProcessorClient processor = new EventProcessorClient(storageClient, consumerGroup, ehubNamespaceConnectionString, eventHubName);
processor.ProcessEventAsync += ProcessEvent.ProcessEventHandler;
processor.ProcessErrorAsync += ProcessEvent.ProcessErrorHandler;
await processor.StartProcessingAsync();
}
The ProcessorEventHandler class:
public static class ProcessEvent
{
public static async Task ProcessEventHandler(ProcessEventArgs eventArgs)
{
var result = Encoding.UTF8.GetString(eventArgs.Data.Body.ToArray());
//DO STUFF
await eventArgs.UpdateCheckpointAsync(eventArgs.CancellationToken);
}
public static Task ProcessErrorHandler(ProcessErrorEventArgs eventArgs)
{
//DO STUFF
return Task.CompletedTask;
}
}
This code is working, but my question is: is it okay to implement it like that? Is there a problem if the consumer nevers stops? Can it block other tasks (or requests) in my code?
Is there a better way to implement it using Dependecy Injection in .Net Core?
I couldn't find any example of someone implementing in a WebApi, is there a reason for that?
As Jesse Squire mentioned, WebAPI isn't necessarily the correct method of implementation, but it primarily depends on what your goals are.
If you are making an API that also includes an Event Hub listener, you should implement it under the IHostedService interface. Your existing AddPropostaEventHub() method goes inside the interface's StartAsync(CancellationToken cancellationToken) which is what .NET Core uses to startup a background task. Then, inside your Startup.cs, you register the handler as services.AddHostedService<EventHubService>();. This ensures that the long running listener is handled properly without blocking your incoming HTTP requests.
If you don't also have an API involved or are able to split the processes completely, then you should consider creating this as a console app instead of as a hosted service, which further separates the roles of API and event listener.
You didn't mention where you are deploying this, but if you happen to be deploying to an Azure App Service, you do have a few options for splitting the receiver from your API, and in that case I would definitely recommend doing so. Inside of App Services, there is a feature called WebJobs which specifically exists to handle things like this without making it part of your API. A good alternative is Functions. In that case you don't have to worry about setting up the DI for Event Hub at all, the host process takes care of that for you.
I have got an web application that lacks to free memory.
I suspect HttpClient to be one of the issues, because the object count of HttpClient is increasing over time.
Therefore I want to migrate to the managed IHttpClientFactory, but now I'm stuck with how to best implement the call to the token service (I thought about using the typed client variant).
Right now it's implemented this way:
var myClient = new MyClient(credentials, baseUri, tokenUri, timeout);
Inside of MyClient HttpClient(1) takes care of calling the token service (credentials, tokenUri), storing the expiry date and returning the bearer token to HttpClient(2) that calls the endpoint (baseUri, timeout).
If myClient now tries to fetch some data, it checks if the token needs to be refreshed, if not it fetches the data.
How would I do this with IHttpClientFactory? Do I still need to handle HttpClient(1) myself (expiry date) or will the factory somehow detect if it needs to refresh the token or not?
I at least understood, that the factory decides if a connection stays open or not.
It sounds like you're on the right track with the transition to HttpClientFactory, and particularly a typed HttpClient.
Under the hood, HttpClientFactory's default implementation manages the pooling and disposal of the underlying primary message handler, which means that the actual HttpClient sitting on top of it can start being generated and disposed in a scoped fashion rather than trying to manage some global, long-running instance of it or creating and tearing down one-off instances, which is well described in Microsoft's own documentation: Use IHttpClientFactory to implement resilient HTTP requests
In cases like yours where the HttpClient was potentially long-lived, it may have made sense for the client itself to manage state within its instance (such as the token), but you end up needing to take a different path now that the client can (and should) be disposed of more frequently.
Do I still need to handle HttpClient(1) myself (expiry date) or will the factory somehow detect if it needs to refresh the token or not?
Yes you still need to handle it, but the HttpClientFactory pattern gives you some tools to help manage it. Since you're inherently leaning into dependency injection with the use of HttpClientFactory, there's a couple different paths you might go.
At the most basic would be just to add some sort of singleton token provider that manages the tokens for you and can be injected into the typed client by the DI container:
public interface ITokenProvider
{
string GetToken(string key);
void StoreToken(string key, string token);
}
// Incredibly basic example, not thread safe, etc...
public class InMemoryTokenProvider : ITokenProvider
{
private readonly Dictionary<string, string> _tokenList = new Dictionary<string, string>();
public string GetToken(string key)
{
return _tokenList.GetValueOrDefault(key);
}
public void StoreToken(string key, string token)
{
_tokenList.Remove(key); // upsert, you get the point...
_tokenList.Add(key, token);
}
}
public class TypedClient
{
private readonly HttpClient _client;
private readonly ITokenProvider _tokenProvider;
public TypedClient(HttpClient client, ITokenProvider tokenProvider)
{
_client = client;
_tokenProvider = tokenProvider;
}
public async Task DoYourThing()
{
var token = _tokenProvider.GetToken("token_A");
// ... if it failed, then UpdateTheAuth()
}
private async Task UpdateTheAuth()
{
var result = await _client.GetAsync("the auth process");
string token = "whatever";
// ...
_tokenProvider.StoreToken("token_A", token);
}
}
When you do your service registration at the start and register the token provider as a singleton, all your state (such as the token) is no longer part of the client itself, so your client can now be disposed and injected wherever. That provider could also be written off to a cache or a database, too.
This can still be a little clunky because its still putting all the logic for calling, failing, updating auth, retrying, etc. within your typed client logic -- it might be good enough if that covers what you need, or you may want something more robust. HttpClientFactory makes it easy to add a delegating handler pipeline as well as policies for resiliency with Polly, such as retry:
services.AddTransient<ExampleDelegatingHandler>();
services.AddHttpClient<IMyHttpClient, MyHttpClient>()
.AddHttpMessageHandler<TokenApplicationHandler>()
.AddPolicyHandler(GetRetryPolicy()); // see Microsoft link
The delegating handler pipeline attaches to your typed client and runs like middleware for every request and response (and can modify them in flight), so you could even move some of this token management off into a delegating handler instead:
public class TokenApplicationHandler : DelegatingHandler
{
private readonly ITokenProvider _tokenProvider;
private readonly IAuthRenewerClient _authRenewer;
public TokenApplicationHandler(ITokenProvider tokenProvider, IAuthRenewerClient authRenewer)
{
_tokenProvider = tokenProvider;
_authRenewer = authRenewer;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
// All just demo level, take the implementation with a grain of salt...
string token = _tokenProvider.GetToken("token_A");
request.Headers.Add("x-token-header", token);
var response = await base.SendAsync(request, cancellationToken);
if (!response.IsSuccessStatusCode && response.StatusCode == HttpStatusCode.Unauthorized)
{
string newToken = _authRenewer.RefreshAuth();
_tokenProvider.StoreToken("token_A", newToken);
}
return response;
}
}
Paired with a retry policy, now any time a request goes out and comes back with an Unauthorized response, your delegating handler can handle the renewal and then the request gets resent the new token, and your typed HttpClient doesn't need to be any the wiser (or even necessarily deal with auth at all).
Key takeaways, make sure as you transition to this pattern that you're disposing of the clients you're creating when you're done with whatever scope they're in so HttpClientFactory can do its background magic.
This is the document https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1
we can see that IHttpClientFactory is registered :
services.AddHttpClient();
and the model class that consume it as:
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
...
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
...
}
but how about we don't register it, and we just create a new instance of it as:
public async Task OnGet()
{
...
var client = new HttpClient();
var response = await client.SendAsync(request);
...
}
so that the BasicUsageModel's constructor doesn't need to take any argument, and when do unit testing , I don't need to use Moq to mock it, isn't that ever better?
and for the first case, how can I mock the IHttpClientFactory to test OnGet() without actually send a request?
when do unit testing , I don't need to use Moq to mock it, isn't that ever better
No it's not. The whole point of a unit test is to test the unit without it's dependencies. In this case, without an actual server to connect to.
Assuming you have one unit test for your client actually getting the data and one unit test for when your client fails to get the data, there is no way you can reasonably do that with your way.
You need to mock it to be able to have multiple test-cases for the different outcomes of your http call.
Quite aside from the UnitTesting point already raised, the document you linked specifies one of the main reasons to use the IHttpClientFactory over instatiating a new HttpClient directly:
Manages the pooling and lifetime of underlying HttpClientMessageHandler instances. Automatic management avoids common DNS (Domain Name System) problems that occur when manually managing HttpClient lifetimes.
I'm using the basic template that VS 2019 provides with the weather forecasting data when creating a ASP.NET WebAPI project and added some very basic authentication with user login and support for JWT Token which all works fine.
I'm trying to create a blazor client project to consume the API and display the data on the page. AFAIK Blazor doesn't support localstorage so I'm using Blazored LocalStorage package to give me this ability. My problem stems from fact using JS via OnInitializedAsync() is not possible in server-side blazor (https://github.com/aspnet/AspNetCore/issues/13396) as a result I'm not sure how one is suppose to consume these web api calls. As this will produce a null reference exception
protected override async Task OnInitializedAsync()
{
var client = HttpFactory.CreateClient();
var token = await LocalStorage.GetItemAsync<string>("authToken");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetAsync("url/WeatherForecast");
var str = await response.Content.ReadAsStringAsync();
Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);
}
One suggestion was to use OnAfterRenderAsync() method to call them as JS would be ready by then. Which semi-works but obviously the UI doesn't match because it needs to be refreshed - however to manually refresh it seems I have to call StateHasChanged(); which in turn calls OnAfterRender method again and as a result I had to put a check but this ultimately feels incredibly hacky.
private bool hasRendered;
protected override async Task OnAfterRenderAsync(bool _)
{
if (!hasRendered) return;
var client = HttpFactory.CreateClient();
var token = await LocalStorage.GetItemAsync<string>("authToken");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetAsync("https://url/WeatherForecast");
var str = await response.Content.ReadAsStringAsync();
Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);
StateHasChanged();
hasRendered = true;
}
What is the correct way to consume an API with authnetication and display the data correctly on the client side?
Side question HttpClient doesn't seem to be injectable in server-side and it's recommended to use HttpClientFactory - is it a good idea to create a client on every request or make a singleton and re-use thoughout the client project?
Q1
One suggestion was to use OnAfterRenderAsync() method to call them as JS would be ready by then. Which semi-works but obviously the UI doesn't match because it needs to be refreshed - however to manually refresh it seems I have to call StateHasChanged(); which in turn calls OnAfterRender method again and as a result I had to put a check but this ultimately feels incredibly hacky.
All people with the same issue, because this, at Lifecycle methods, new OnAfterRenderAsync with firstRender parm is documented:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await ... /// your auth code here.
}
}
Q2
Side question HttpClient doesn't seem to be injectable in server-side and it's recommended to use HttpClientFactory - is it a good idea to create a client on every request or make a singleton and re-use thoughout the client project?
Simplifying: I suggest to you to create two external libraries for your backend calls: one using http requests (for blazor wasm hosted model) and the other one just calling c# backend functions (for blazor server). Both with a common interface for backend calls. Use DI to set right library for each hosted model.
I am trying to create layer for webservice using HttpClient in my Xamarin.Forms mobile app.
without singlton pattern
with singleton pattern
in first approach i am creating new http client object in each new request made
by mobile applicaiton.
here is my code
public HttpClient GetConnection()
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(baseAddress);
httpClient.Timeout = System.TimeSpan.FromMilliseconds(timeout);
return httpClient;
}
post request code
public async Task<TResult> PostAsync<TRequest, TResult>(String url, TRequest requestData)
{
HttpClient client = GetConnection();
String responseData = null;
if (client != null)
{
String serializedObject = await Task.Run(() => JsonConvert.SerializeObject(requestData, _jsonSerializerSettings));
var jsonContent = new StringContent(serializedObject, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(new Uri(url, UriKind.Relative), jsonContent);
responseData = await HandleResponse(response);
return await Task.Run(() => JsonConvert.DeserializeObject<TResult>(responseData, _jsonSerializerSettings));
}
else
{
throw new NullReferenceException("NullReferenceException # PostAsync httpclient is null WebRequest.cs");
}
}
client will use following code to execute request
new LoginService(new WebRequest()).UserLogin(userRequest);
inside class that implements IWebRequest
_webRequest.PostAsync<UserRequest,bool>(Constants.USER_LOGIN, userRequest);
in second approach i am reusing the same http client object in each new request
here , my singleton class is thread safe too.
private static readonly Lazy<HttpService> lazy =
new Lazy<HttpService>(() => new HttpService());
public static HttpService Instance { get { return lazy.Value; } }
private HttpClient getConnection()
{
client = new HttpClient();
client.Timeout = System.TimeSpan.FromMilliseconds(timeout);
//client.MaxResponseContentBufferSize = 500000;
client.BaseAddress = new Uri(baseAddress);
return client;
}
post request code
public Task<HttpResponseMessage> sendData(String url,String jsonData)
{
var jsonContent = new StringContent(jsonData, System.Text.Encoding.UTF8, "application/json");
return getConnection().PostAsync(new Uri(url, UriKind.Relative), jsonContent);
}
client will use following code to execute
HttpService.Instance.sendData(...)
i have gone through many libraries like RestSharp over web just to explore the best and i found that most of them are creating new objects per request. so i am confused which pattern fits best.
Update: It seems that using a single static instance of HttpClient doesn't respect DNS changes, so the solution is to use HttpClientFactory. See here for Microsoft docs about it.
To use the HttpClientFactory you have to use Microsoft's dependency injection. This is the default for ASP.NET Core projects, but for others you will have to reference Microsoft.Extensions.Http and Microsoft.Extensions.DependencyInjection.
Then when you're creating your service container, you simply call AddHttpClient():
var services = new ServiceCollection();
services.AddHttpClient()
var serviceProvider = services.BuildServiceProvider();
And then you can inject IHttpClientFactory into your services, and behind the scenes HttpClientFactory will maintain a pool of HttpClientHandler objects - keeping your DNS fresh and preventing problems with connection pool exhaustion.
Old answer:
Singleton is the correct way to use HttpClient. Please see this article for full details.
Microsoft docs state:
HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors. Below is an example using HttpClient correctly.
And indeed, we found this in our application. We have code that can potentially make hundreds of API requests in a foreach loop, and for each iteration we were creating an HttpClient wrapped in a using. We soon started getting red herring errors from our MongoClient saying that it had timed out trying to connect to the database. After reading the linked article, we found that even after disposing of HttpClient, and realised that we were exhausting the available sockets.
The only thing to note is that things like DefaultRequestHeaders and BaseAddress will be applied anywhere that HttpClient is used. As a singleton, this is potentially throughout the application. You can still create multiple HttpClient instances in your application, but just be aware that each time you do, they create a new connection pool and, as such, should be created sparingly.
As pointed out by hvaughan3, you also can't change the instance of HttpMessageHandler used by the HttpClient, so if this matters to you, you would need to use a separate instance with that handler.
While HttpClient is supposed to be reused, it does not necessarily mean we have to use singleton to organize our code. Please refer to my answer here. Also quoted below.
I'm late to the party, but here is my learning journey on this tricky topic.
1. Where can we find the official advocate on reusing HttpClient?
I mean, if reusing HttpClient is intended
and doing so is important,
such advocate is better documented in its own API documentation,
rather than being hidden in lots of "Advanced Topics", "Performance (anti)pattern"
or other blog posts out there.
Otherwise how is a new learner supposed to know it before it is too late?
As of now (May 2018), the first search result when googling "c# httpclient"
points to this API reference page on MSDN, which does not mention that intention at all.
Well, lesson 1 here for newbie is,
always click the "Other Versions" link right after the MSDN help page headline,
you will probably find links to the "current version" there.
In this HttpClient case, it will bring you to the latest document
here containing that intention description.
I suspect many developers who was new to this topic
did not find the correct documentation page either,
that's why this knowledge is not widely spread,
and people were surprised when they found it out
later,
possibly in a hard way.
2. The (mis?)conception of using IDisposable
This one is slightly off-topic but still worth pointing out that, it is not a coincidence to see people
in those aforementioned blog posts blaming how HttpClient 's IDisposable interface
makes them tend to use the using (var client = new HttpClient()) {...} pattern
and then lead to the problem.
I believe that comes down to an unspoken (mis?)conception:
"an IDisposable object is expected to be short-lived".
HOWEVER, while it certainly looks like a short-lived thing when we write code in this style:
using (var foo = new SomeDisposableObject())
{
...
}
the official documentation on IDisposable
never mentions IDisposable objects have to be short-lived.
By definition, IDisposable is merely a mechanism to allow you to release unmanaged resources.
Nothing more. In that sense, you are EXPECTED to eventually trigger the disposal,
but it does not require you to do so in a short-lived fashion.
It is therefore your job to properly choose when to trigger the disposal,
base on your real object's life cycle requirement.
There is nothing stopping you from using an IDisposable in a long-lived way:
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
With this new understanding, now we revisit that blog post,
we can clearly notice that the "fix" initializes HttpClient once but never dispose it,
that is why we can see from its netstat output that,
the connection remains at ESTABLISHED state which means it has NOT been properly closed.
If it were closed, its state would be in TIME_WAIT instead.
In practice, it is not a big deal to leak only one connection open after your entire program ends,
and the blog poster still see a performance gain after the fix;
but still, it is conceptually incorrect to blame IDisposable and choose to NOT dispose it.
3. Do we have to put HttpClient into a static property, or even put it as a singleton?
Based on the understanding of the previous section,
I think the answer here becomes clear: "not necessarily".
It really depends on how you organize your code,
as long as you reuse an HttpClient AND (ideally) dispose it eventually.
Hilariously, not even the example in the
Remarks section of the current official document
does it strictly right. It defines a "GoodController" class,
containing a static HttpClient property that will not be disposed;
which disobeys what another example in the Examples section
emphasizes: "need to call dispose ... so app doesn't leak resources".
And lastly, singleton is not without its own challenges.
"How many people think global variable is a good idea? No one.
How many people think singleton is a good idea? A few.
What gives? Singletons are just a bunch of global variables."
-- Quoted from this inspiring talk, "Global State and Singletons"
PS: SqlConnection
This one is irrelevant to the current Q&A, but it is probably a good-to-know.
SqlConnection usage pattern is different.
You do NOT need to reuse SqlConnection,
because it will handle its connection pool better that way.
The difference is caused by their implementation approach.
Each HttpClient instance uses its own connection pool (quoted from
here);
but SqlConnection itself is managed by a central connection pool,
according to this.
And you still need to dispose SqlConnection, same as you are supposed to do for HttpClient.
.NET Core 2.1+
When you can use DI:
using System.Net.Http;
public class SomeClass
{
private readonly IHttpClientFactory _httpClientFactory;
public SomeClass(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public void Foo()
{
var httpClient = _httpClientFactory.CreateClient();
...
}
}
When you can't use DI:
using System.Net.Http;
public class SomeClass
{
private static readonly HttpClient Client;
static SomeClass()
{
var handler = new SocketsHttpHandler
{
// Sets how long a connection can be in the pool to be considered reusable (by default - infinite)
PooledConnectionLifetime = TimeSpan.FromMinutes(1),
};
Client = new HttpClient(handler, disposeHandler: false);
}
...
}
Reference https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0#alternatives-to-ihttpclientfactory
As others mentioned, mostly HttpClient should be used as singleton, but there is one exception - you should not use HttpClient as singleton when you use HTTP long polling technique, because you will block other requests execution.
For long polling requests you should create separate HttpClient.
If you will use HttpClient as static property in WebApi applicaion, you can get following error
System.InvalidOperationException: Concurrent reads or writes are not supported.\r\n at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()\r\n at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)\r\n at System.IO.Pipelines.Pipe.GetReadAsyncResult()\r\n at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext.WriteBody(Boolean flush)","ClassName":"IISHttpContext","MethodName":"WriteBody","EventId":{"Id":3,"Name":"UnexpectedError"},"SourceContext":"Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer"
Error will appear, when inside of you action in webapi controller you are making 2 concurrent requests to same url using HttpClient static instance
therefore i think usage of
_httpClientFactory.CreateClient(Guid.NewGuid().ToString()) in action is most safe approach. According to documentation of the method -
" It is generally not necessary to dispose of the System.Net.Http.HttpClient as the System.Net.Http.IHttpClientFactory tracks and disposes resources used by the System.Net.Http.HttpClient."