Web API
.NET .NET Core ASP.NET Core Blazor C# Dependency Injection REST Visual Studio Web API

How to Execute Web API Requests from a .NET Core Blazor WebAssembly

Welcome to today’s post.

In today’s post I will be showing you how to execute Web API calls from an ASP.NET Core Blazor WebAssembly application.

In the previous post I defined Blazor WebAssembly applications and how they differ from Blazor Server applications.

The reason why we do not (in most cases) have a need to execute Web API calls from .NET Core Blazor Server applications is that Blazor Server hosted applications already have easier integration and accessibility to many server resources, such as databases, cloud services, web services, network resources and so on. Integration to server resources is already available in NuGet package libraries for .NET Core such as: ASP.NET Core, Http, EntityFramework and so on. 

In the first section, I will distinguish between executions of Web API requests from client and server applications.

Executions of Web API Requests from Client and Server Applications

ASP.NET Core Blazor WebAssembly applications are native web client applications that have their entire logic rendered within the confines of a client web browser. This is a strength and a limitation: The strength lies in being able to run optimized graphics or interface rich applications that take advantage of the resources within the machine running the client web browser. The disadvantage lies in any server calls requiring executing web API calls, then converting the response output from JSON into a structured .NET data type, such as List, Array, or Dictionary. The bandwidth and network latency required to make these API calls is an additional overhead.

The diagram below shows the case where we execute web API calls from a Blazor WebAssembly to a web API service.

I will elaborate on the above in the next section.

When executing Web API calls from an application, the application that is executing the call acts as a client, and the Web API acts as a service. In the case where a server application, such as an ASP.NET Core web application, ASP.NET Core web API service, or ASP.NET Core Blazor Web Server application makes the call, we need to use client HTTP libraries to make the API execution calls. We still need to read the output response as JSON, then convert it to a familiar .NET collection data type. As you can see, even a server-to-server API call requires some overhead before we can implement Web API calls. 

To get some idea of how server to server API calls are implemented, in my previous posts I have showed how to execute Web API calls from ASP.NET Core API applications, including execution of HTTP GET REST API calls from a Web API, and execution of HTTP POST REST API calls from a Web API.

In this post, I am focusing on the case where we make calls from a native web application hosted on the client side. These can include JavaScript, Angular, React and so on. In a previous post I showed how to execute Web API calls from an Angular front-end application. If you have already experienced executing Web API calls from both client and server-side applications, then running them from a Blazor WebAssembly should be straightforward.

Execution of Web API Requests from a Blazor WebAssembly Application

A Blazor WebAssembly application has almost the identical folder structure in its development environment as a Blazor Server application. There are Shared and Pages subfolders. We have App.razor, NavMenu.razor and MainLayout.razor components that are provided from the template project. We can use a similar technique that we did for an ASP.NET Core Blazor Server application where we implemented a service class that calls (or uses) our service resource(s), inject it into our Razor component, and make calls to the service methods from within our Razor component’s code segment. 

In the next section is will show how to create a service within our WebAssembly that will wrap HTTP REST execution calls to a web API method.

A Service Wrapper for Web API Calls

Did you know that as we did for Blazor Server applications, when we implemented service classes and injected them into Razor components, we can do likewise in Blazor WebAssembly web client hosted applications.  

Recall that when we implement service classes, to be consistent with SOLID principles, we can declare an interface for our service, then implement a service class that extends the interface.

The interface is shown below:

Services\IBookService.cs:

using System.Collections.Generic;
using BookLoanBlazorWASMApp.Models;

namespace BookLoanBlazorWASMApp.Services
{
    public interface IBookService
    {
        Task<List<BookViewModel>> GetBooks();
    }
}

Before we can execute calls to web API services using the HttpClient service class, we will need to import the following namespace into the source:

using System.Net.Http;

In addition, we will need to add the HttpClient service class to the service container with a scoped lifetime. This is done in Program.cs as shown:

builder.Services.AddScoped(sp => new HttpClient { 
    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) 
});

Notice that when you create a new WebAssembly project using the Visual Studio templates, the above line is added to your program startup code.

The HttpClient extension method that we use to make HTTP GET calls to external web API methods is shown below:

public static System.Threading.Tasks.Task<object?> GetFromJsonAsync (
    this System.Net.Http.HttpClient client, 
    string? requestUri, Type type, 
    System.Threading.CancellationToken cancellationToken = default
);

The above method is just one of 12 overloads that are available of the GetFromJsonAsync() method.  I have chosen the one applicable for the scenario I am demonstrating.

In addition, before we can use this method, we will need to import the following namespace:

using System.Net.Http.Json;

To simplify the scenario slightly, I will re-use an existing minimal web API service and run that in a separate instance of Visual Studio. Refer to one of my previous posts where I have explained details on the implementation of a minimal Web API, and another post where I showed how to implement a web API that integrates with Entity Framework Core and a backend SQL database.  

In the example of the service class, the URI for calling the API will be:

http://localhost:5013/

You may have a different URI for your web API, which may be running under IISExpress within another Visual Studio instance or is hosted locally as a web application on a local IIS webserver.

In the code example for the service class that will follow, I will include the URI parameter within the GetFromJsonAsync() call. For your benefit, it is advisable before finalising the code for the service class and before building and a running the WebAssembly, that you verify the correct web API HTTP GET call that you will need to use. I discuss this is the next main section Testing Web API Calls from our Blazor WebAssembly Application, where I discuss running and determining the HTTP GET method URI.

Given the above explanations, the service class implementation is shown below:

Services\IBookService.cs:

using BookLoanBlazorWASMApp.Models;
using System.Net.NetworkInformation;
using System.Net.Http;
using System.Net.Http.Json;

namespace BookLoanBlazorWASMApp.Services
{
    public class BookService : IBookService
    {
        private readonly ILogger _logger;
        private readonly HttpClient _http;
        private readonly string _apiUri = "http://localhost:5013/"; 

        public BookService(
            ILogger<BookService> logger, HttpClient http)
        {
            _logger = logger;
            _http = http;
        }

        /// <summary>
        /// GetBooks()
        /// </summary>
        /// <returns></returns>
        public async Task<List<BookViewModel>> GetBooks()
        {
            var books = await _http.GetFromJsonAsync<List<BookViewModel>>(_apiUri + "bookitems");
            return books!.ToList();
        }
    }
}

The service class is then added to the application service container in Program.cs as shown:

builder.Services.AddTransient<IBookService, BookService>();

Before we can use and inject the dependent service class(es) that we have just implemented within any other classes or Razor components and make use of the HttpClient service class to make execution calls to external web API methods, we will need to add the above excerpts of code within Program.cs to ensure the dependency classes are visible to our application Razor components.  

Program.cs:

using BookLoanBlazorWASMApp;
using BookLoanBlazorWASMApp.Services;

using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddTransient<IBookService, BookService>();

await builder.Build().RunAsync();

Injecting Dependent Services to our Razor Component

The final step in our quest to make the web API call is to integrate it into our Razor component. The most common example I can think of is to re-use an existing Razor component that displays a table of records from a data source. In one of my previous posts I showed how to display data in Blazor Server application from a database data source using EntityFramework. Our data source in this case will be JSON data that is converted to a list collection. Once we have converted the JSON records to the data within a List collection, we will not need to change any of our HTML Razor presentation code or C# code segment that calls the service class.

The Razor component is shown below:

Pages\ListBooks.razor:

@page "/listbooks"
@using BookLoanBlazorWASMApp.Models
@using BookLoanBlazorWASMApp.Services
@inject IBookService LibraryBookService

<PageTitle>list books</PageTitle>

<h3>List Books</h3>

@if (books == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Title</th>
                <th>Author</th>
                <th>ISBN</th>
                <th>Year Published</th>
                <th>Genre</th>
                <th colspan="2">Action</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var book in books)
            {
                <tr>
                    <td>@book.Title</td>
                    <td>@book.Author</td>
                    <td>@book.ISBN</td>
                    <td>@book.YearPublished</td>
                    <td>@book.Genre</td>
                    <td>
                        <a href="editbook/?id=@book.ID">Edit</a>
                    </td>
                    <td>
                        <a href="viewbook/?id=@book.ID">View</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private List<BookViewModel>? books = new List<BookViewModel>();

    protected override async Task OnInitializedAsync()
    {
        List<BookViewModel>? tempList = await LibraryBookService.GetBooks();
        foreach (var book in tempList)
            if (!book!.Title!.Contains("Test"))
                books!.Add(book);
    }
}

Before we complete this section, you will need to link the ListBooks.razor component to the navigation menu. This is done by adding the following markup to the shared NavMenu.razor file

Shared\NavMenu.razor:

<div class="nav-item px-3">
    <NavLink class="nav-link" href="listbooks">
        <span class="oi oi-plus" aria-hidden="true"></span> List Books
    </NavLink>
</div>

In the next section, I will show how to test Web API calls in our application.

Testing Web API Calls from our Blazor WebAssembly Application

To be able to test web API execution of our Blazor WebAssembly application, we will need the following two applications to be running:

  1. A web API service
  2. A web client application

I will start with the Web API service.

Running the Web API Service

As I mentioned earlier, we can run our web API service application either under IIS web application hosted within IIS server, in the cloud (as a web application within Azure App Service) or running as an ASP.NET Core web API application running under an IIS Express web server. To not overcomplicate the discussion, I will choose the latter option.   

I have used the minimal Web API service application that I implemented from one of my previous posts. When our ASP.NET Core web API service is running under Visual Studio, you should see it running under the KestrelServer reverse proxy in the debug console as shown:

When the minimal web API has completed startup, your Swagger API definitions will show:

From here you can select one of the API definitions to determine the URI that we will use within our WebAssembly client call. In the example below, we have viewed the \bookitems HTTP GET API call, which returns all the books in JSON response:

From the above, we can see how the HTTP GET call URI is structured. Using CURL we can use:

curl -X 'GET' \
  'http://localhost:5013/bookitems' \
  -H 'accept: */*'

The HTTP URI is then:

http://localhost:5013/bookitems

Given what we need to know from the running Web API, we are now able to configure our WebAssembly components to execute calls to the method within our running web API service. I will show how this executes in the next section.

Running the Blazor Web Assembly Application

After you have determined configurations for your web API service and included the API method within the URI for the web API call, then the application will be ready to build and run. When the WebAssembly is running, you should see the landing page as shown:

Next, click on the List Books link in the navigation menu.

Below is a snapshot of what the variable values within the service class, BookService object look like:

You can see that the HttpClient service class dependency has been injected successfully into our custom BookService service class.

After the Web API method has been executed from the GetBooks() method within the service class, we will see some records returned from that method in the form of a List collection:

From the browser, open the Developer Tools.

Select the Header tab. The response from the web API method bookitems has returned a status code of 200:

The above indicates the execution of the web API is successful.

From the browser Developer Tools Response tab, the output response shows the records returned in JSON format:

Now close the Developer Tools and you will see the list of books is displaying from the ListBooks.razor component in the browser as shown:

In the above discussion, we have seen how to setup, configure, and implement a Web API execution call from a Blazor WebAssembly application to a method within an ASP.NET Core Web API service.

In future posts I will cover HTTP POST, PUT, and DELETE calls and cover some troubleshooting and diagnostics of Web API calls from a WebAssembly.

That is all for today’s post.

I hope you have found this post useful and informative.

Social media & sharing icons powered by UltimatelySocial