Third Party API Integration

API is valuable for every website, it allows your website to talk to another product. In this tutorial, you will discover:

  • Why do you need to register the HttpClient?
  • Register HttpClient.
  • Interfere HttpClient.
  • HTTP methods.
  • Send request.
  • Process response.
  • Common mistakes.
You can download the example code used in this topic on GitHub.

Why do you need to register the 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.

website-integration-model.png


Register HttpClient

In this tutorial, we will assume you have 2 API endpoints http://localhost:5132 (First API) and http://localhost:5016 (Second API).

Named HttpClient

You 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 wrapper

A 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.

  1. Create a wrapper class with injected HttpClient. For example:
public class HttpClientWrapperClass
{
    private readonly HttpClient _httpClient;

    public HttpClientWrapperClass(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
}
  1. Add methods to integrate with the third party API. For example:
public async Task<string> GetWeatherDataAsync()
{
    var response = await _httpClient.GetAsync("/weatherforecast");
    string result = await response.Content.ReadAsStringAsync();

    return result;
}
  1. Register the wrapper class at 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

Interfere HttpClient

Some 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 middleware

This 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:

httpclient-middleware-chain.png

  1. Create a middleware class. The middleware class must extend the class 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 the base.Send() or base.SendAsync() when you are overriding the method Send or SendAsync respectively. If you don't, the chain is broken and the next middleware will not be called.
  1. Register all the middlewares are transient services at Program.cs. For example:
builder.Services.AddTransient<FirstMiddleware>();
builder.Services.AddTransient<SecondMiddleware>();
  1. Register the 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 wrapper

This technique provides you a centralized interfering code.

  1. Create the wrapper class. For example:
public class InterfereByHttpClientWrapper
{
    private readonly HttpClient _httpClient;

    public InterfereByHttpClientWrapper(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
}
  1. Expose a method to send the request. For example:
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 extension

This 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;
    }
}

HTTP methods

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.


Send request

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.

Sending data via URL

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.

Sending primitive data in the request body

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.

Sending complex data in the request body

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.

Sending stream data in the request body

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.


Process response

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.

Process primitive data in the response

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";
}

Automatically deserialize response data to object using Microsoft library

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();
    }
}

Deserialize response data to object using Newtonsoft library

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.

Process stream data in the response

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.

Common mistakes

When integrating with an API in Blazor Server, there are some common mistakes that you need to avoid. They are:

  • Use your first party API.
  • Extend HttpClient class.

Use your first party API

You should not build/use a first party API for Blazor Server. The reason is:

  1. You need to scale both the Blazor Server host and the API host. Without the first party API, you only need to scale the Blazor Server host.
  2. The requests are sent from the Blazor Server website host, not the client browser. This increase the work load for your Blazor Server website host unnecessarily.

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.

Extend HttpClient class

You 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.

What will happend if you don't manage 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:

BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2025 Blazor School
An unhandled error has occurred. Reload 🗙