✅ Best practice when using HttpClient in a class
I have a class which essentially acts as a wrapper over an HttpClient as an abstraction for a web API. This class has a field
private readonly HttpClient client;
which is currently set through the constructor of the class, where I'm just kind of expecting the consuming code to have configured the base address and any other configuration in regards to the client itself. However, I don't know if this is considered good practice, or if there's some other way I'm not aware of. This class should also be usable with DI, so I don't know if I instead should have an IHttpClientFactory in the constructor or something instead.43 Replies
Tl;dr, I have this Is this bad?
as long as you don't register
ApiWrapper
as singleton (and recreate it somewhat regularly), i guess this is alright
you can use services.AddHttpClient<ApiWrapper>(...)
to configure the client and register ApiWrapper
as transient
i think ms calls this usage "typed client": https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#typed-clientsright, nice
In what package exactly is
AddHttpClient
defined? I can't find it
nvm, found itthat is IHttpClientFactory
specficically TypedClient
AddHttpClient<ApiWrapper>()
then just DI
and consume within the class
Actually, I don't think this will work if the wrapper is transient, because my API relies on state in the client, so I don't think recreating it for every request will work.
you can set the settings specifically for that implementation
<T>
it doesn't matter, ApiWrapper doesn't manage the HttpClients
its just a dependency
btw typedclients are transient aswell
so
there is nothing wrong
HttpClient might get created every time, but the Handler is reused
because the IHttpClientFactory persists
and you get all the benefits of creation/disposal/configurations from the service provider
Well I don't want the HttpClient to get created every time
then don't use
sure I guess
sry i thought your
ApiWrapper
is a thin wrapper for the api. basically just defining convenient functions that call the httpclient-functions.
have you checked out the "Basic usages" and "Named clients" in the link i posted?
you can basically call _httpClientFactory.CreateClient(...);
on a IHttpClientFactory
to get the HttpClient, when you need ityou can probably use it
inject it through DI
and use the "basic usage"
where you create a client
and keep that client
through the life of the apiwrapper life
eh, I'll just add the wrapper as a singleton
but you have to do it in the DI
which is not that cool but i know that you know what you are doing so whatever xd
the
IHttpClientFactory
will take care of caching the httpclient/handler for you and recreate them appropriatelyI have no idea what I'm doing
yes you do xd
So I should use
IHttpClientFactory
?let's go again
do you want a new client each time
So like, thing is that I'm relying on the client storing a cookie for the user being signed in, so I need that info to be retained across requests.
the factory takes care of that for you
well if it's some kind of long running application, yes
if it's just a cli command or something like that you don't have to worry about it that much
okay, nice
It's a Blazor WASM app
make sure you do not tell the handler to disable cookies
oh wait
WASM runs in sandbox
you can't manipulate cookies
https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.usecookies?view=net-8.0
this doesn't work on WASM
So... I can't do this?
you will probably have to create a delegating handler
and override sendasync
then create a custom service to add/remove headers
then add the DelegatingHandler to that implementation of HttpClient
which is what you should be doing, the cookies of IHttpClientFactory are automatic and shared
through CookieContainer
which you might not want
remember that blazor WASM uses
Microsoft.Extensions.Http
Severity Code Description Project File Line Suppression State
Warning CA1416 This call site is reachable on all platforms. 'HttpClientHandler.UseCookies' is unsupported on: 'browser'. BlazorApp15
check this:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-7.0#outgoing-request-middleware
that would be your DelegatingHandler
which you then can add to the config of your HttpClient
they are transient so don't worry about them
they just do stuff in the middleware of http requests
and to be fair, you should use them like 99% of the time
even if you can use cookies, i wouldn't let the Factory manage them automatically
recipe for disasterso...
use DelegatingHandlers
and typedclients
So I need to make a type deriving from
DelegatingHandler
?just make a class that derives from it yeah
and override SendAsync
which is the base of all your fancy http request methods
so everything will be hit
also
since you use TypedClients
you can specify which implementation uses what DelegatingHandler and which doesn't
so you can have one implementation that you do stuff in the middleware and one that does not
What do I need to do in SendAsync then?
whatever you want
check for headers
add headers
log
cache
error handling
you name it
yeah but what do I need to do to get cookies to work then?
if you can explain to me what you need to do
maybe i can point you in the right direction
When I call an endpoint in my API to log the user in, the API returns a login cookie, and that cookie should be retained throughout the rest of the app.
okay
what about determining what user is making the request
and attach the cookie
in the middleware
where do I get the cookie from?
database? MemoryCache?
whatever works for you
Except the API endpoint adds the cookie to the client
wait i think i misunderstood what you want
blazor does have cookies, maybe i expressed myself wrong, what doesn't work is the cookie sharing of IHttpClientFactory
it's a sandbox
try this
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.webassembly.http.webassemblyhttprequestmessageextensions.setbrowserrequestcredentials?view=aspnetcore-7.0
that way you get all the cookies from the client
How do I make the HttpClient I add through
AddHttpClient
use this handler?
Okay nvm, changed it to a DelegatingHandler
yeah if you
every typed client request will go through that custom middleware
yeah, I figured it out
The entire thing works now