If you’ve worked with the ASP.NET Core Web API before, chances are you used HttpClient
to call them. Although HttpClient
directly initializing is a common use, there is a better alternative. Instead of initializing the HttpClient
, you use the IHttpClientFactory
to get a copy of the HttpClient
. Therefore, the resulting HttpClient
object can be used to call the Web API. In this article I will discuss 3 ways to get an instance of HttpClient
using IHttpClientFactory
.
The examples discussed in the article assume you have a Web API as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token punctuation">[</span> <span class="token class-name">Route</span> <span class="token punctuation">(</span> <span class="token string">"api/[controller]"</span> <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ValuesController</span> <span class="token punctuation">:</span> <span class="token class-name">Controller</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span> <span class="token class-name">HttpGet</span> <span class="token punctuation">]</span> <span class="token keyword">public</span> IEnumerable <span class="token operator"><</span> <span class="token keyword">string</span> <span class="token operator">></span> <span class="token function">Get</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token keyword">string</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token string">"Hello World!"</span> <span class="token punctuation">,</span> <span class="token string">"Hello Galaxy!"</span> <span class="token punctuation">,</span> <span class="token string">"Hello Universe!"</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
ValuesController
(a Web API) contains the Get()
action, this function returns a string array – Hello World! , Hello Galazy! , and Hello Universe! This Web API is invoked at HomeController
. As such, you will need the HttpClient
object to complete its task.
See different ways to get an HttpClient
instance using the IHttpClientFactory
.
The basic technique for obtaining HttpClient
In this technique you use the AddHttpClient()
with IServiceCollection
inside the ConfigureServices()
as shown below:
1 2 3 4 5 6 7 | <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">ConfigureServices</span> <span class="token punctuation">(</span> <span class="token class-name">IServiceCollection</span> services <span class="token punctuation">)</span> <span class="token punctuation">{</span> services <span class="token punctuation">.</span> <span class="token function">AddControllers</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> services <span class="token punctuation">.</span> <span class="token function">AddControllersWithViews</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> services <span class="token punctuation">.</span> <span class="token function">AddHttpClient</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Next you can inject IHttpClientFactory
into HomeController
:
1 2 3 4 5 6 7 | <span class="token keyword">private</span> <span class="token class-name">IHttpClientFactory</span> factory <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token function">HomeController</span> <span class="token punctuation">(</span> <span class="token class-name">IHttpClientFactory</span> factory <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> factory <span class="token operator">=</span> factory <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Next, you can get the HttpClient
instance like this:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">public</span> <span class="token class-name">IActionResult</span> <span class="token function">Index</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">HttpClient</span> client <span class="token operator">=</span> factory <span class="token punctuation">.</span> <span class="token function">CreateClient</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> client <span class="token punctuation">.</span> BaseAddress <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Uri</span> <span class="token punctuation">(</span> <span class="token string">"https://localhost:44393"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">var</span> response <span class="token operator">=</span> client <span class="token punctuation">.</span> <span class="token function">GetAsync</span> <span class="token punctuation">(</span> <span class="token string">"/api/values"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> Result <span class="token punctuation">;</span> <span class="token keyword">string</span> jsonData <span class="token operator">=</span> response <span class="token punctuation">.</span> Content <span class="token punctuation">.</span> <span class="token function">ReadAsStringAsync</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> Result <span class="token punctuation">;</span> List <span class="token operator"><</span> <span class="token keyword">string</span> <span class="token operator">></span> data <span class="token operator">=</span> JsonSerializer <span class="token punctuation">.</span> Deserialize <span class="token operator"><</span> List <span class="token operator"><</span> <span class="token keyword">string</span> <span class="token operator">></span> <span class="token operator">></span> <span class="token punctuation">(</span> jsonData <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">View</span> <span class="token punctuation">(</span> data <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Notice how the CreateClient()
of the IHttpClientFactory
is used to get the HttpClient
instance? How to create the instance is the job of CreateClient()
. Once you have it, you can configure it according to your needs. For example, here you set the BaseAddress
property to create the base address of the Web API. Next you handle to call GetAsync()
which is the call to Get()
action of Web API.
The JSON data returned from the Get()
action is deserialized using the JsonSerializer
class of System.Text.Json
. Next the data is sent to the Index
view on the page.
Obtained from previous configuration and Client name
Sometimes you need instances of HttpClient
each have a separate configuration. While calling the AddHttpClient()
you can also specify configuration information and names like the following code:
1 2 3 4 5 | services <span class="token punctuation">.</span> <span class="token function">AddHttpClient</span> <span class="token punctuation">(</span> <span class="token string">"myclient"</span> <span class="token punctuation">,</span> client <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">{</span> client <span class="token punctuation">.</span> BaseAddress <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Uri</span> <span class="token punctuation">(</span> <span class="token string">"https://localhost:44393"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Here, you have created a client named ‘ myclient ‘ that has a certain configuration (in this case, BaseAddress
). Whenever you need this instance you can get it like this:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">public</span> <span class="token class-name">IActionResult</span> <span class="token function">Index</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">HttpClient</span> client <span class="token operator">=</span> factory <span class="token punctuation">.</span> <span class="token function">CreateClient</span> <span class="token punctuation">(</span> <span class="token string">"myclient"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">var</span> response <span class="token operator">=</span> client <span class="token punctuation">.</span> <span class="token function">GetAsync</span> <span class="token punctuation">(</span> <span class="token string">"/api/values"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> Result <span class="token punctuation">;</span> <span class="token keyword">string</span> jsonData <span class="token operator">=</span> response <span class="token punctuation">.</span> Content <span class="token punctuation">.</span> <span class="token function">ReadAsStringAsync</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> Result <span class="token punctuation">;</span> List <span class="token operator"><</span> <span class="token keyword">string</span> <span class="token operator">></span> data <span class="token operator">=</span> JsonSerializer <span class="token punctuation">.</span> Deserialize <span class="token operator"><</span> List <span class="token operator"><</span> <span class="token keyword">string</span> <span class="token operator">></span> <span class="token operator">></span> <span class="token punctuation">(</span> jsonData <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">View</span> <span class="token punctuation">(</span> client <span class="token punctuation">.</span> <span class="token function">GetData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Notice that the CreateClient()
now specifies the name of the client. When ‘ myclient ‘ already has BaseAddress
configured in the Startup class, the above code no longer sets the BaseAddress
property and handles the GetAsync()
method call.
Get a typed client
A typed client is a required configuration packaging, and the Web API calls through a set of methods. The following class implements a typed client:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyTypedClient</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token class-name">HttpClient</span> Client <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">;</span> <span class="token keyword">set</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token function">MyTypedClient</span> <span class="token punctuation">(</span> <span class="token class-name">HttpClient</span> client <span class="token punctuation">)</span> <span class="token punctuation">{</span> client <span class="token punctuation">.</span> BaseAddress <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Uri</span> <span class="token punctuation">(</span> <span class="token string">"https://localhost:44393"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> Client <span class="token operator">=</span> client <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> List <span class="token operator"><</span> <span class="token keyword">string</span> <span class="token operator">></span> <span class="token function">GetData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> response <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> Client <span class="token punctuation">.</span> <span class="token function">GetAsync</span> <span class="token punctuation">(</span> <span class="token string">"/api/values"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> Result <span class="token punctuation">;</span> <span class="token keyword">string</span> jsonData <span class="token operator">=</span> response <span class="token punctuation">.</span> Content <span class="token punctuation">.</span> <span class="token function">ReadAsStringAsync</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> Result <span class="token punctuation">;</span> List <span class="token operator"><</span> <span class="token keyword">string</span> <span class="token operator">></span> data <span class="token operator">=</span> JsonSerializer <span class="token punctuation">.</span> Deserialize <span class="token operator"><</span> List <span class="token operator"><</span> <span class="token keyword">string</span> <span class="token operator">></span> <span class="token operator">></span> <span class="token punctuation">(</span> jsonData <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> data <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
As you can see, the MyTypedClient
class has a public property named Client, which is the type of HttpClient
. This property is assigned a value in the constructor through dependency injection. The GetData()
does all the configuration of the Web API call and returns the requested data to the client.
Therefore, other parts of the application do not need to know how the API is called or what configuration is needed. Other parts of the system only need to use the MyTypedClient
object to get their work done.
When MyTypedClient
ready to register in ConfigureServices()
as the code below:
1 2 3 4 5 6 7 | <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">ConfigureServices</span> <span class="token punctuation">(</span> <span class="token class-name">IServiceCollection</span> services <span class="token punctuation">)</span> <span class="token punctuation">{</span> services <span class="token punctuation">.</span> <span class="token function">AddControllers</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> services <span class="token punctuation">.</span> <span class="token function">AddControllersWithViews</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> services <span class="token punctuation">.</span> <span class="token generic-method"><span class="token function">AddHttpClient</span> <span class="token punctuation"><</span> <span class="token class-name">MyTypedClient</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
To inject the MyTypedClient
object in HomeController
you would write the following:
1 2 3 4 5 6 7 | <span class="token keyword">private</span> <span class="token class-name">MyTypedClient</span> client <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token function">HomeController</span> <span class="token punctuation">(</span> <span class="token class-name">MyTypedClient</span> client <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> client <span class="token operator">=</span> client <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Next, you can use the typed client object in the Index()
action as shown below:
1 2 3 4 5 | <span class="token keyword">public</span> <span class="token class-name">IActionResult</span> <span class="token function">Index</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">View</span> <span class="token punctuation">(</span> client <span class="token punctuation">.</span> <span class="token function">GetData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
summary
This article showed 3 ways to create an instance of HttpClient
through IHttpClientFactory
. HttpClient
is popular and easy to use, but it has issues that we need to consider when using. About IHttpClientFactory
gives us many more configuration options and features, while making sure to replace what HttpClient
can do. You can learn more about their advantages and disadvantages in the article Use HttpClientFactory to implement resilient HTTP requests . Hope to bring you useful things.
The article was translated from source: http://www.binaryintellect.net/articles/1ec182b1-6d47-42da-92b6-c38279b28b20.aspx