Why should you use IHttpClientFactory
The main reason to use IHttpClientFactory
instead of HttpClient
directly is to manage the life cycle of HttpClient instances. HttpClient was designed to be instantiated once and reused throughout the application life cycle. If you continually instantiate new HttpClients you may unnecessarily be squandering resources.
Another use case is for simplicities sake, you can define all Named and Typed clients in the Program.cs file and use them throughout the application via Dependency Injection.
Benefits of IHttpClientFactory
- Centralized location for Named/Typed
HttpClient
instances in Program.cs. - Integrates with Polly for transient fault handling.
- Avoid common DNS problems by managing
HttpClient
lifetimes. - Adds logging for all requests sent through clients created by the factory.
- Manage the lifetime of HttpMessageHandler to avoid the mentioned problems/issues that can occur when managing
HttpClient
lifetimes yourself.
What you may have done in the past
Here you can see we instantiate HttpClient
directly in our method. This approach is not advisable for the reasons mentioned above.
public async Task> GetAllRecipes()
{
HttpClient client = new HttpClient();
var results = await _httpClient?.GetFromJsonAsync>("/Data/recipes");
return results.ToList();
}
Lets see below how to implement this better with IHttpClientFactory
How to Implement a Typed Client with Blazor Web Assembly
IRecipeService
example
public class RecipeViewModel
{
public int Rid { get; set; }
public string? Title { get; set; }
public byte[]? ImageData { get; set; }
public string? ImageFileName { get; set; }
public string? ImageFormat { get; set; }
public int? Duration { get; set; }
public DateTime? CreatedDateTime { get; set; }
public string? CreatedBy { get; set; }
public DateTime? ModifiedDateTime { get; set; }
public string? ModifiedBy { get; set; }
public bool? IsDisabled { get; set; }
public short? Rating { get; set; }
public string? Description { get; set; }
}
IRecipeService.cs
We create an interface and a service for fetching data from an external API and map it to a view model. The methods are self explanatory.
public interface IRecipeService
{
Task CreateRecipe(RecipeViewModel recipe);
Task UpdateRecipe(RecipeViewModel recipe);
Task> GetAllRecipes();
Task DeleteRecipe(RecipeViewModel recipe);
}
public class RecipeService : IRecipeService
{
private readonly HttpClient _httpClient;
public RecipeService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task CreateRecipe(RecipeViewModel recipe)
{
var result = await _httpClient?.PostAsJsonAsync("/data/create-recipe", recipe);
if (!result.IsSuccessStatusCode)
{
throw new Exception("Failed to save. Invalid Http Status Code");
}
}
public async Task UpdateRecipe(RecipeViewModel recipe)
{
var result = await _httpClient?.PutAsJsonAsync("/data/update-recipe", recipe);
if (!result.IsSuccessStatusCode)
{
throw new Exception("Failed to save. Invalid Http Status Code");
}
}
public async Task> GetAllRecipes()
{
var results = await _httpClient?.GetFromJsonAsync>("/Data/recipes");
return results.ToList();
}
public async Task DeleteRecipe(RecipeViewModel recipe)
{
await _httpClient?.PostAsJsonAsync("/data/delete-recipe", recipe);
}
IRecipeService
, making it available throughout the application via Dependency Injection.
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add("#app");
builder.RootComponents.Add("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddHttpClient().ConfigureHttpClient(x=>x.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
await builder.Build().RunAsync();
Using a Typed Client in our Blazor Component
IRecipeService
to fetch data from an external API. From there you can use the AllRecipes
object throughout the Razor component.
public partial class ListRecipes
{
[Inject]
private IRecipeService? RecipeService { get; set; }
private List? AllRecipes { get; set; }
protected override async Task OnInitializedAsync()
{
AllRecipes = await RecipeService?.GetAllRecipes();
}
}
This concludes our tutorial of using IHttpClientFactory with Blazor Web Assembly using a Typed Client. I hope you found this useful. Feel free to leave feedback below.
Want to learn more?
Service Collections with Blazor Server
What is a service collection? Service collections are a way of registering and resolving dependencies in C# applications using the built-in dependency injection (DI) system. Blazor Server is a web framework that allows you to run C# code on the server and interact with the user interface through a SignalR connection. To use service collections…
Read moreIn Memory State Management with Blazor Server
Creating your first In Memory State Container with Blazor Server Web technology has come along way in the relatively recent past. With the surge in popularity of SPAs and Javascript Frameworks a lot of developers have come to expect certain functionality out of the box. Blazor Server being a stateful application framework offers us a…
Read more