The default registration in a Blazor app for HttpClient is
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
According to Microsoft docs, HttpClient should be registered as a Singleton.
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.
https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netcore-3.1
Not only can this exhaust the number of available sockets (most likely in a Blazor Server app) but HttpClient also implements IDisposable, which means the dependency container will hold on to every HttpClient instance created until the user closes their browser window. See #21652
@mrpmorris thanks for contacting us.
That only applies to the server. In the wasm implementation its backed by the wasm handler, so it is not an issue.
@javiercn every time you have an HttpClient injected into a component you'll get a new instance, but because it implements IDisposable the container will hold a reference to it in until the container is disposed, which isn't until the user goes away.
This means you'll keep creating new instances that aren't garbage collected,and you'll have a memory leak.
If you aren't convinced then look at the repo in #21652 and/or read the explanation here https://blazor-university.com/dependency-injection/dependency-lifetimes-and-scopes/transient-dependencies/#avoiding-memory-leaks
PS: I think Blazor should probably register HttpClient as Scoped.
Yea this seems really wrong almost patch worthy for 3.1.
DryIoc won't even allow you to register disposable transients: https://bitbucket.org/dadhi/dryioc/wiki/ReuseAndScopes.md#markdown-header-disposable-transient
Other containers as well, or do not pass validation, so you cannot validate the container. This is an issue.
My proposition would be as follows:
Willing to code this solution and make a PR. But is this the right direction for the solution?
I went for a new component ScopedComponent with [InjectOwned]
https://mrpmorris.blogspot.com/2020/04/blazor-scoping-services-to-component.html
This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.
See our Issue Management Policies for more information.
Euh. msftbot? Does it really work that way? Open this please.
@javiercn this is an issue that has a lot of attention on the Gitter channel and we're confused why it's been marked by the bot as closed. Can you please re-open?
@simonziegler reopened.
Thanks @javiercn
+1
This has been an issue for me because I'm using JWT authentication and the authentication token is set on the httpclient header (httpClient.DefaultRequestHeaders.Authorization) after a successful authentication. Now when I inject the httpClient in a component to call a remote service requiring authentication, I get a new instance with a null authorization header! This is very inconvenient and it was working fine in 3.1 by the way (maybe it was injected as singleton in this version...).
Will be available in 3.2.1
Cool. That'll be 拢1, please :)
Most helpful comment
Yea this seems really wrong almost patch worthy for 3.1.