API is valuable for every website, it allows your website to talk to another product. In this tutorial, you will discover:
HttpClient?HttpClient.HttpClient.You can download the example code used in this topic on GitHub.
HttpClient?When integrating with a third party API, your server (website host) became the client of another server. You will make http requests from your server to the API server by using HttpClient. You need to register the HttpClient first. Depend on how many APIs in your website, you will need to register them differently. The BaseAddress in the HttpClient is the address of your API and you must specify this value in order to make HttpClient to work. The following image illustrates the website integration model.

HttpClientIn this tutorial, we will assume you have 2 API endpoints http://localhost:5132 (First API) and http://localhost:5016 (Second API).
HttpClientYou name your API differently, then use the IHttpClientFactory and create the HttpClient by its name. This technique does not allow you to override methods of the HttpClient. Register your HttpClient instances at Program.cs. You must provide a name for each instance. For example:
builder.Services.AddHttpClient("First API", httpClient => httpClient.BaseAddress = new("http://localhost:5132"));
builder.Services.AddHttpClient("Second API", httpClient => httpClient.BaseAddress = new("http://localhost:5016"));
Whenever you need to make a request, you need to inject the IHttpClientFactory and create the HttpClient by its name. For example:
@inject IHttpClientFactory HttpClientFactory
...
@code {
protected override async Task OnInitializedAsync()
{
var httpClient = HttpClientFactory.CreateClient("Second API");
...
}
}
HttpClient wrapperA wrapper is a class that takes HttpClient from the service provider, then hiding all the methods of HttpClient. The wrapper class then expose its own methods for other classes.
HttpClient. For example:public class HttpClientWrapperClass
{
private readonly HttpClient _httpClient;
public HttpClientWrapperClass(HttpClient httpClient)
{
_httpClient = httpClient;
}
}
public async Task<string> GetWeatherDataAsync()
{
var response = await _httpClient.GetAsync("/weatherforecast");
string result = await response.Content.ReadAsStringAsync();
return result;
}
Program.cs. For example:builder.Services.AddHttpClient<HttpClientWrapperClass>(httpClient => httpClient.BaseAddress = new("http://localhost:5132"));
Whenever you need to make a request, you can inject the wrapper class and use the exposed method of the wrapper class to make the request. For example:
@inject HttpClientWrapperClass HttpClientWrapperClass
HttpClientSome APIs are protected by JWT, some require additional request header, sometimes you need to interact with the loading indicator whenever a request goes and a response comes. This is why you need to interfere the HttpClient. There are many ways to interfere the HttpClient:
HttpClient middleware.HttpClient wrapper.HttpClient extension.HttpClient middlewareThis technique is build on the chain of responsibility pattern. You will have many middlewares, a request is processed by the first middleware in the chain to the last middleware in the chain, then a response is processed by the last middleware in the chain to the first middleware in the chain. The following image illustrates this pattern:

DelegatingHandler. The class must override at least one method in Send or SendAsync. For example:public class FirstMiddleware : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Interfering code before sending the request
var response = await base.SendAsync(request, cancellationToken);
// Interfering code after sending the request
return response;
}
}
You must call thebase.Send()orbase.SendAsync()when you are overriding the methodSendorSendAsyncrespectively. If you don't, the chain is broken and the next middleware will not be called.
Program.cs. For example:builder.Services.AddTransient<FirstMiddleware>(); builder.Services.AddTransient<SecondMiddleware>();
HttpClient by named HttpClient or HttpClient wrapper technique, then add the chain in your desired sequence. For example:builder.Services.AddHttpClient("HttpClient with Middleware", httpClient => httpClient.BaseAddress = new("http://localhost:5276"))
.AddHttpMessageHandler<FirstMiddleware>()
.AddHttpMessageHandler<SecondMiddleware>();
builder.Services.AddHttpClient<SecondApiHttpClientWrapper>(httpClient => httpClient.BaseAddress = new("http://localhost:5276"))
.AddHttpMessageHandler<FirstMiddleware>()
.AddHttpMessageHandler<SecondMiddleware>();
HttpClient wrapperThis technique provides you a centralized interfering code.
public class InterfereByHttpClientWrapper
{
private readonly HttpClient _httpClient;
public InterfereByHttpClientWrapper(HttpClient httpClient)
{
_httpClient = httpClient;
}
}
public class InterfereByHttpClientWrapper
{
...
public async Task<T?> GetAsync<T>(string requestUrl)
{
// Interfering code before sending the request
var response = await _httpClient.GetFromJsonAsync<T>(requestUrl);
// Interfering code after sending the request
return response;
}
}
HttpClient extensionThis technique provides you a centralized interfering code.
Create the extension class. Create a method to send request with the first parameter is this HttpClient httpClient. For example:
public static class HttpClientExtension
{
public static async Task<T?> GetResponse<T>(this HttpClient httpClient, string url)
{
// Interfering code before sending the request
var result = await httpClient.GetFromJsonAsync<T>(url);
// Interfering code after sending the request
return result;
}
}
There are many HTTP methods, and you should follow the method to standardize your website. You can find out more at https://www.w3schools.com/tags/ref_httpmethods.asp.
Sending requests is a must-know technique when working with the API. In this section, we will get you through how to send a request to an API endpoint.
You can put some data in the URL and send it to the API. This commonly used in API with GET method. The data in the URL should be primitive data type and small. For a big data, do not send it via URL. You can use HttpClient to send data via URL as follows:
await httpClient.GetAsync($"example/ProcessPrimitiveUrlData?data=Blazor School");
If you have then one parameter, you can use the symbol & to separate them. For example: example/ProcessPrimitiveUrlData?data=Blazor School&book=Blazor Server .NET 6 Fundamentals.
For HTTP methods other than GET, you need to put the data in the request body instead of the URL. You can send primitive data in the request body as follows:
await httpClient.PostAsync("example/ProcessPrimitiveData", new StringContent("\"Blazor School\"", Encoding.UTF8, "application/json"));
This technique is only applicable if your API endpoint has only 1 parameter. If your API endpoint has more than 1 parameter, use the sending complex data technique.
Similar to sending primitive data in the request body, this technique is used for HTTP methods other than GET. You need to serialize your object to JSON then send the JSON to the API. There are a few methods in the System.Net.Http.Json that helps you to do that. For example:
var data = new ExampleClass()
{
ExampleString = "Blazor School"
};
await httpClient.PostAsJsonAsync<ExampleClass>("example/ProcessComplexData", data);
The PostAsJsonAsync will serialize your object to JSON and then send it to the API with POST method. You can also use the similar methods for other HTTP methods.
A stream is a sequence of bytes. The bytes can be a file content, a video, etc… Most case stream is used to upload a file to the API. Here is an example code to upload a file from your Blazor Server host to the API endpoint:
using var formDataContent = new MultipartFormDataContent();
using var stream = ExampleFile.OpenReadStream(long.MaxValue);
using var streamContent = new StreamContent(stream);
streamContent.Headers.ContentType = new(ExampleFile.ContentType);
formDataContent.Add(streamContent, "FileStream", ExampleFile.Name);
var message = await httpClient.PostAsync("example/ProcessStreamdata", formDataContent);
In the above example, the ExampleFile is the object of IBrowserFile type. You can also add more files to the formDataContent in the example.
After your request is received at the API endpoint, the API will process your request and give you a response. This section will give you an idea on how to process the response of an API endpoint.
After sending a request to the API, the API will process the request then return the response to your HttpClient. Sometimes, the response has the data, sometimes it doesn't. When the response has data, you can process the data as follows:
var response = await httpClient.GetAsync("example/ReturnPrimitiveData");
if(response.IsSuccessStatusCode)
{
DataReceived = await response.Content.ReadAsStringAsync();
}
else
{
DataReceived = "Failed";
}
When your API returns a JSON, you can use the Microsoft library System.Net.Http.Json to automatically deserialize the JSON to a C# object. This library will use System.Text.Json underlying to deserialize the JSON. Http For example:
@inject IHttpClientFactory HttpClientFactory
<div>Data Received: @ExampleInstance.ExampleString</div>
@code {
public ExampleClass ExampleInstance { get; set; } = new();
protected override async Task OnInitializedAsync()
{
var httpClient = HttpClientFactory.CreateClient("Second API");
ExampleInstance = await httpClient.GetFromJsonAsync<ExampleClass>("example/ReturnComplexData") ?? new();
}
}
Newtonsoft.Json is a famous JSON process library with awesome features that System.Text.Json doesn't have. You can also use the Newtonsoft.Json to deserialize the JSON to a C# object as follows:
@using Newtonsoft.Json
@inject IHttpClientFactory HttpClientFactory
<div>Data Received: @ExampleInstance.ExampleString</div>
@code {
public ExampleClass ExampleInstance { get; set; } = new();
protected override async Task OnInitializedAsync()
{
var httpClient = HttpClientFactory.CreateClient("Second API");
var response = await httpClient.GetAsync("example/ReturnComplexData");
if(response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
ExampleInstance = JsonConvert.DeserializeObject<ExampleClass>(responseContent) ?? new();
}
}
}
You can improve this technique to not repeat the same code over again by using one of the technique in Interfere HttpClient section.
Some APIs will return a stream, you can also process the stream by the method ReadAsStreamAsync(). The following example code will process an image file stream.
@inject IHttpClientFactory HttpClientFactory
<img src="@ImageSrc"/>
@code {
public string ImageSrc { get; set; } = "";
protected override async Task OnInitializedAsync()
{
var httpClient = HttpClientFactory.CreateClient("Second API");
var response = await httpClient.GetAsync("example/ReturnStreamData");
if(response.IsSuccessStatusCode)
{
using var stream = await response.Content.ReadAsStreamAsync();
byte[] buffer = new byte[stream.Length];
await stream.ReadAsync(buffer, 0, (int)stream.Length);
string base64 = Convert.ToBase64String(buffer);
ImageSrc = $"data:image/png;base64,{base64}";
}
StateHasChanged();
}
}
You need to process the stream according to its type. It's not always an image file stream as in the example.
When integrating with an API in Blazor Server, there are some common mistakes that you need to avoid. They are:
HttpClient class.You should not build/use a first party API for Blazor Server. The reason is:
If you already have an API and want to reuse the logic in the API, you need to split the logic to a Class Library project and then use that Class Library project in your Blazor Server website.
HttpClient classYou should not extend HttpClient in Blazor Server (however in Blazor WebAssembly, you can use this technique). The method AddHttpClient do not support a derived HttpClient class and you have to manage the life cycle of your extended class manually.
HttpClient's life cycle correctly?Your Blazor Server website host will suffer socket exhaustion.
Consider the following code:
@page "/extend-http-client"
<h3>ExtendHttpClient</h3>
<div>@((MarkupString)Log)</div>
@code {
public string Log { get; set; } = "";
protected override async Task OnInitializedAsync()
{
foreach (int index in Enumerable.Range(1, 10))
{
using var httpClient = new HttpClient();
var response = await httpClient.GetAsync("https://blazorschool.com");
if(response.IsSuccessStatusCode)
{
Log += $"Request {index} was sucessfully.<br/>";
}
else
{
Log += $"Request {index} was failed.<br/>";
}
}
}
}
The following video will demonstrate what will happend with the code: