The RIGHT Way To Use HttpClient In .NET

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
if you're building a modern web application chances are high that you'll need to talk to external apis over HTTP the easiest way to achieve that in.net is using the HTTP client class unfortunately it's also easy to misuse it and end up introducing some potential problems in your code so I'm going to show you the right way to use the HTTP client so that you don't make these mistakes ever again what I have here is a single minimal API endpoint which is integrating with the GitHub API so I'm creating a new HTTP client setting the authorization and user agent headers from the GitHub settings which I'm pulling from the application settings Json file I'm setting the Base address to the GitHub API and then I'm sending a request to the user's endpoint with this username and I'm getting back a GitHub user response from the GitHub API if I send this request to my API API from Postman I'm going to get back a Json response for my GitHub profile and the public information that is returned from the API the problem is I'm using the HTTP client in an incorrect way the HTTP client is supposed to be long-lived and reused throughout the lifetime of your application so if I check out the HTTP client Constructor it accepts an HTTP message Handler the default implementation is called HTTP client Handler but the more popular one which is used in newer.net versions is the sockets HTTP Handler what's actually expensive about instantiating the HTTP client is the underlying HTTP message Handler this object is responsible for managing a connection pool for that HTTP message Handler if you end up creating and then disposing of too many of these connection pools you could dry up the available ports on the server which is going to to lead to Port exhaustion and new clients will not be able to connect to that server alright now we know what the problem is but how do we fix it so I'm going to create another endpoint here just so that you can see everything side by side we're going to call this version 2 and I'm going to inject one more service in our request Handler delegate and this is going to be the I HTTP client Factory so let's give it a name of factory and how you use the HTTP client Factory is by saying Factory and you call the create client method which is going to give you back an HTTP client instance the benefit of using the HTTP client Factory over directly instantiating the HTTP client is that the factory is going to Cache the underlying HTTP message Handler and this already solves most of the issues of incorrectly using the HTTP client the downside is you have to configure the HTTP client every time you get back a new instance from the create client method you also need to register the HTTP client Factory with dependency injection and you can do that by saying Builder services at HTTP client and this is going to add the appropriate implementation of the iactp client Factory interface if I send the request to our version 2 endpoint this time which is the one creating the client using the factory you're going to see that everything is working just fine and we get back our response both of these approaches suffer from the same problem and that is that you have to configure the HTTP client every time that you want to use it so this is where the HTTP client Factory is actually really useful because you can introduce named clients so how you can do that is here let's say we want to introduce a name client called GitHub we can say add HTTP client give it the name and then we have a chance to configure our HTTP client instance so I'm going to use the overload which gives me access to the service provider and the HTTP client instance so that I can resolve the settings from my services so I'm going to say service provider get required service I'm going to take the i options of GitHub settings and we want to take the value and store that in a variable so we have our GitHub settings and then on the HTTP client instance I can configure all of these values ahead of time so I'm going to say this I'm going to replace this with HTTP client and these are going to come from my GitHub settings so now my HTTP client with the name of GitHub is going to come pre-configured with the default request headers and the Base address and I don't have to repeat this configuration every time I want to use it so I'm going to introduce a version 3 endpoint and show you how to use a named client so we're still using our HTTP client Factory the only difference is we're passing the name to the create client method so now we're getting back a named client with this name and it already has all of this configuration applied so I can get rid of it and this also means I can get rid of this argument and this is what I'm left with now compare these two versions The One using the client without configuration and the one using the named client you can see the advantage of named clients and applying configuration ahead of time of course if I send the get request to the version free endpoint everything is still working the same as before there's one more approach to how you can use the HTTP client and it's called the typed client so what you do is you create a class let's add a class called GitHub service let's say it's public and sealed and it has a method returning the same GitHub user as our endpoint is returning let's call it get by username async it accepts a username and we're going to be using the HTTP client to get the user by the username so I'm going to copy this code here what I'm missing is my actual HTTP client I'm going to solve that in a moment and let's just return this content so how you create a type client is you can just inject the HTTP client instance from The Constructor so I'm going to inject it from The Constructor and I'm going to use it in the body of my method of course if the GitHub user can be null we should make this explicit where does this HTTP client actually come from this is why it's called a typed client because this HTTP client instance is going to be tied to our GitHub service type how you configure this is by saying Builder services at HTTP client and there's this generic overload which accepts your typed client instance so I'm going to pass in the GitHub service class and we're going to configure it the same way that we have here so that we can add our configuration for the request headers and the Base address and everything else Remains the Same what happens under the hood is this is actually just a named client where the name which we had here is simply derived from the name of the type that you specify as the generic argument with this configuration in place I can inject my HTTP client in the Constructor and I'm going to get back an instance with this configuration applied now the interesting part is how you use this in your code so now I'm going to add a version 4 endpoint and this one is no longer going to inject the ihttp client Factory I'm just going to inject the GitHub service and let's give it the name of GitHub service so this is going to be coming from dependency injection and now I can just say content is going to come from my GitHub service and we're going to say get by username async and we're going to pass it the username you can already see the advantage of working with a type client you don't need to know which route to send the request to you don't need to know how to call the HTTP client you just abstract away everything behind your service and you worked with the client inside of that service if I send this request to my version 4 endpoint this time I'm again going to get back the same response and this is going to work like the other three versions just the advantage is we have strong typing because we are using a service class there's one more thing that you need to be aware of if you are using type client and that is the fact that this call here will register GitHub Service as a transient service with dependency injection this means that every time this is injected you're going to get back a new instance of the GitHub service class and the problem is you can inject this inside of a Singleton service which means that the HTTP client that is captured here as part of your GitHub service will be alive during the lifetime of that Singleton service so this is something that you need to be aware of if for some reason you still want to use the transient type client from inside of a Singleton service then you need to make a few adjustments so here you need to configure the primary message Handler you can do that by calling the configure primary message Handler method and you just need to pass it the function which is going to return the HTTP message Handler Microsoft recommends that in this Factory you return a new instance of the sockets HTTP Handler class and on it you need to set the pooled connection lifetime to some value that makes sense for example we can say time span from minutes and let's say the pulled connection lifetime is 5 minutes what this is going to do is make this HTTP message Handler the primary message Handler for the HTTP client which is passed to our typed service and the lifetime of the connections that are alive in the pool is going to be five minutes so all of these connections are going to get recycled every five minutes which is going to solve the problem of Port exhaustion and also reacting to DNS changes these sockets HTTP Handler class is responsible for its own connection pool so you can get rid of the recycling that is natively available on the HTTP client Factory by setting the Handler lifetime to timeout infinite time span and with this configuration in place you can use the transient GitHub service inside of some Singleton service if you want to now you know the right way to use the HTTP client in.net I prefer working with type clients but let me know in the comments which approach you like to use don't forget to smash that like button and until next time stay awesome
Info
Channel: Milan Jovanović
Views: 26,623
Rating: undefined out of 5
Keywords: httpclient, httpclient c#, httpclientfactory c#, httpclient c# web api, httpclient post c#, httpclient c# post json data, httpclient c# tutorial, httpclient vs httpclientfactory, httpclient post, httpclient c# get json, httpclient named client, httpclient typed client, httpclient json, httpclient put, httpclient get, httpclient delete, httpclient factory, httpclient .net, httpclient .net 7, httpclient port exhaustion, httpclient dns changes, httpclient connection pool
Id: g-JGay_lnWI
Channel Id: undefined
Length: 11min 46sec (706 seconds)
Published: Fri Jun 30 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.