Blazor, HttpClientFactory, and Web API
Tags: csharp, dotnet, webdev, tutorial
Published: 2019-12-02 09:01:27

---
title: Blazor, HttpClientFactory, and Web API
published: true
date: 2019-12-02 07:15:00 UTC
tags: csharp, dotnet, webdev, tutorial
canonical_url: https://wellsb.com/csharp/aspnet/blazor-httpclientfactory-and-web-api/
---

[Original Article](https://wellsb.com/csharp/aspnet/blazor-httpclientfactory-and-web-api/)

In this tutorial, you will learn how to create a server-side Blazor application that interacts with an external web API using HttpClientFactory. Later in the series, you will add IdentityServer4 authentication to protect the API and authorize the client web app.

**In this Blazor tutorial series**
- Part 1: Blazor with Web API Solution Structure
- Part 2: Consume API protected by IdentityServer4 (_Coming Soon_)
- Part 3: Cache IdentityServer4 API Access Token (_Coming Soon_)

In Part 1, you will create a public Web API, and you will learn the right way to interact with it from a server-side Blazor app. In the next tutorial, you will protect the API using IdentityServer4 and learn how to authorize your Blazor app using an access token.

Though this tutorial is written for server-side Blazor applications, the techniques can also be used in other ASP.NET web apps, including both MVC and Razor Pages projects.

## Create the Shared Models Project

Start by creating a shared library that will contain the models to be used in the solution. The models contained in the shared library will be referenced by both the API and the Blazor web application frontend, so this is a good place to start!

Launch Visual Studio and create a **New Project**. Select **Class Library (.NET Standard)**. A .NET Standard class library can be added as a reference to all .NET Core web applications (MVC, Razor Pages, and Blazor), and it can also be included as a reference in a Xamarin project if you ever decide to create a mobile frontend.

In this series, you will create a contact management application. For Solution Name, type **BlazorContacts**. Enter **BlazorContacts.Shared** for the Project Name, and click **Create** to scaffold the shared library from template.

In the Solution Explorer pane, right-click the **BlazorContacts.Shared** project and select **Add > New Folder**. Name the folder **Models**. This directory will contain all the shared models you will need in your application

For this application, you will need a model that contains information about individual contacts. Right-click the **Models** folder, and select **Add > Class**. Name the class **Contact.cs**. This will generate a file that should look like the following:

```csharp
using System;
using System.Collections.Generic;
using System.Text;
 
namespace BlazorContacts.Shared.Models
{
    class Contact
    {
    }
}
```

The Contact model should be public, so you can access it from outside the class. It should also include a unique identifier for the contact, and, for this example, the contact’s name and phone number. You may choose to split the Name property into two properties, one for FirstName and one for LastName, to provide for more robust sorting and filtering in your end product. You could also add more fields, such as Address, EmailAddress, and Location.

```csharp
namespace BlazorContacts.Shared.Models
{
    public class Contact
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string PhoneNumber { get; set; }
    }
}
```

There is a useful Nuget package for annotating data models that I recommend. Using it will make data validation much easier on both the backend database as well as the frontend UI. It can be used to define required fields, length constraints, valid characters, etc. Add the package to your project.

```
Install-Package System.ComponentModel.Annotations
```

Then include the package in your class library. By also including a JSON serialization library, you can ensure the public properties in your model are linked to the correct JSON property produced by the API.

```csharp
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;

```

I am using the new `System.Text.Json` namespace instead of NewtonSoft. With this package, your annotated Models class might look like the following:

```csharp
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
 
namespace BlazorContacts.Shared.Models
{
    public class Contact
    {
        [Key]
        [JsonPropertyName("id")]
        public long Id { get; set; }
 
        [Required]
        [JsonPropertyName("name")]
        public string Name { get; set; }
 
        [Required]
        [DisplayName("Phone Number")]
        [JsonPropertyName("phonenumber")]
        public string PhoneNumber { get; set; }
    }
}

```

The `[Key]` attribute can be used when attaching the model to a database. It is not actually necessary in this case, because a property with name `Id` will automatically be used as the key in a database entry. The `[Required]` attribute denotes a required field, and `DisplayName` allows you to denote a human readable name for a field. The `DisplayName` will be shown in the case of error messages, for example.

## Create the Web API

Now, it is time to create the Web API which will be used to add, delete, and fetch contacts. With the **BlazorContacts** solution open, add a **New Project** , and select **ASP.NET Core Web Application**. Name the project **BlazorContacts.API** , and click **Create**. On the next page, select the **API** project template.

Leave the Authentication setting as No Authentication. Later, you will configure IdentityServer4 to grant API access to your Blazor frontend. Click **Create** , and wait for the API project template to scaffold.

In the Solution Explorer pane of your newly created API project, right click the **BlazorContacts.API** project and select **Add > Reference**. In the Reference Manager, add **BlazorContacts.Shared** as a reference for your API project. This will allow you to reference the `Contact` model you just created.

Next, right-click the **Controllers** directory of the API project and select **Add** > **Controller**. In the Add New Scaffolded Item dialog, choose **API Controller – Empty** and click **Add**. In the next dialog, name the controller **ContactsController**. This will scaffold a blank API controller class called **ContactsController.cs** that looks like the following:

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
 
namespace BlazorSecure.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ContactsController : ControllerBase
    {
    }
}
```

Add a `using` directive to include the **BlazorContacts.Shared.Models** namespace.

```csharp
using BlazorContacts.Shared.Models;

```

For demonstration purposes, this API will simply store the contacts in memory. In production applications, you could use a database. Declare a collection of contacts, and add a method to populate the collection.

```csharp
private static readonly List<Contact> contacts = GenerateContacts(5);
private static List<Contact> GenerateContacts(int number)
{
    return Enumerable.Range(1, number).Select(index => new Contact
    {
        Id = index,
        Name = $"First{index} Last{index}",
        PhoneNumber = $"+1 555 987{index}",
    }).ToList();
}
```

The `GenerateContacts()` method will generate and return a list of a given number of unique contacts. You could also generate contacts one by one and add them to the `contacts` variable. Again, this is all just sample data stored in memory, so do whatever you’d like.

```csharp
contacts.Add(new Contact { Id = 1, Name="First1 Last1", PhoneNumber="+1 555 123 9871" });

```

Next, add public methods for interacting with the API. Below are sample methods.

```csharp
// GET: api/contacts
[HttpGet]
public ActionResult<List<Contact>> GetAllContacts()
{
    return contacts;
}
 
// GET: api/contacts/5
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Contact> GetContactById(int id)
{
    var contact = contacts.FirstOrDefault((p) => p.Id == id);
    if (contact == null)
        return NotFound();
    return contact;
}
 
// POST: api/contacts
[HttpPost]
public void AddContact([FromBody] Contact contact)
{
    contacts.Add(contact);
}
 
// PUT: api/contacts/5
[HttpPut("{id}")]
public void EditContact(int id, [FromBody] Contact contact)
{
    int index = contacts.FindIndex((p) => p.Id == id);
    if(index != -1)
        contacts[index] = contact;
    
}
 
// DELETE: api/contacts/5
[HttpDelete("{id}")]
public void Delete(int id)
{
    int index = contacts.FindIndex((p) => p.Id == id);
    if (index != -1)
        contacts.RemoveAt(index);
}
```

There are two GET methods, one for fetching all contacts and one for getting individual contacts by ID. Next, there is a POST method for adding a new contact. The PUT method can be used to update an existing contact, and the DELETE method will delete a contact by ID.

One final note regarding the **BlazorContacts.API** project: I am using the following launch settings (Properties > launchSettings.json) to start the project on `http://localhost:5001`. This address will be used when configuring the Identity Server authentication and when setting the base api address for the web frontend.

```
{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:5001",
      "sslPort": 0
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchUrl": "api/contacts",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "BlazorContacts.API": {
      "commandName": "Project",
      "launchUrl": "api/contacts",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5001"
    }
  }
}
```

## Create the Blazor Web App

Now it is time to create the web interface to interact with the API. Create a New Project within the **BlazorContacts** solution. Select **Blazor App** and name the project **BlazorContacts.Web**. On the next page, select **Blazor Server App**.

First, from the new **BlazorContacts.Web** project, **Add > Reference** that points to the **BlazorContacts.Shared** project, just like you did when creating the API. Then add a new folder called **Services** to the **BlazorContacts.Web** project. Right-click the new folder and **Add > New Class** called **ApiService.cs**.

The **ApiService** service will use the `IHttpClientFactory` interface, which is the best way to use `HttpClient` in a server-side Blazor application. `HttpClientFactory` ensures that the sockets associated with each `HttpClient` instance are shared, thus preventing the issue of socket exhaustion.

```caharp
using BlazorContacts.Shared.Models;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
 
namespace BlazorContacts.Web.Services
{
 
    public class ApiService
    {
        public HttpClient _httpClient;
 
        public ApiService(HttpClient client)
        {
            _httpClient = client;
        }
 
        public async Task<List<Contact>> GetContactsAsync()
        {
            var response = await _httpClient.GetAsync("api/contacts");
            response.EnsureSuccessStatusCode();
 
            using var responseContent = await response.Content.ReadAsStreamAsync();
            return await JsonSerializer.DeserializeAsync<List<Contact>>(responseContent);
        }
 
        public async Task<Contact> GetContactByIdAsync(int id)
        {
            var response = await _httpClient.GetAsync($"api/contacts/{id}");
            response.EnsureSuccessStatusCode();
 
            using var responseContent = await response.Content.ReadAsStreamAsync();
            return await JsonSerializer.DeserializeAsync<Contact>(responseContent);
        }
    }
}

```

In this example, I have written two methods for the **ApiService** class. One will return a `List<Contact>` and the other will return an individual `Contact` by its unique ID property. You could also just use a single method that returns a string and perform the deserialization in your page controller, instead.

```csharp
return await response.Content.ReadAsStringAsync();
```

Now that the service is created, you must register the HttpClientFactory interface. Still in **BlazorContacts.Web** , open **Startup.cs** and locate the `public void ConfigureServices(IServiceCollection services)` method and register the ApiService typed client.

```csharp
services.AddHttpClient<Services.ApiService>(client =>
{
    client.BaseAddress = new Uri("http://localhost:5001");
});
```

Go ahead and assign `BaseAddress` to the address where your web API is located, as shown above. The path argument in the the `GetApiAsync()` method of the **ApiService** class will append to this base address. Passing “api/contacts” to the method, for example, will fetch the result from `http://localhost:5001/api/contacts` which is configured in the API’s **ContactsController.cs** file to return a list of all contacts.

### Create the Blazor Page

All that is left is to create Blazor pages that will interact with the API, through the ApiService. Create a new Razor component in the Pages folder called **Contacts.Razor**. To make this page appear at the /contacts route, add a page directive to the top of the page.

```csharp
@page "/contacts"

```

Next, inject the HttpClientFactory interface you previously registered, and import the namespace of the shared contact model.

```csharp
@inject Services.ApiService apiService
@using BlazorContacts.Shared.Models
```

You can use the service in your page code as follows. In this case, I am overriding the `OnInitialized` method of the Blazor component so I can use the `List<Contact>` in the web interface.

```csharp
List<Contact> contacts;
 
protected override async Task OnInitializedAsync()
{
    contacts = await apiService.GetContactsAsync();
}
```

A complete Blazor page that relies on `apiService.GetContactsAsync()` may look like the following.

```html
@page "/contacts"
@inject Services.ApiService apiService
@using BlazorContacts.Shared.Models
 
 
<h3>Contacts</h3>
@if (contacts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Phone Number</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contact in contacts)
            {
                <tr>
                    <td>@contact.Id</td>
                    <td>@contact.Name</td>
                    <td>@contact.PhoneNumber</td>
                </tr>
            }
        </tbody>
    </table>
}
 
@code {
    List<Contact> contacts;
 
    protected override async Task OnInitializedAsync()
    {
        contacts = await apiService.GetContactsAsync();
    }
}
 

```

To use the `GetContactByIdAsync()` method, simply pass the `id` value of the contact whose information you want to retrieve to the method.

```csharp
Contact contact3 = await apiService.GetContactByIdAsync(3);

```

## Putting it all together

To test your Blazor solution, you will need to launch the Web API and the Blazor App at the same time. To do this, you must configure multiple projects to startup when you launch the debugger.

Right click the **BlazorContacts** solution in the Solution Explorer. Select **Set StartUp Projects**. In the dialog that opens, choose **Multiple startup projects** and set the action for **BlazorContacts.API** and **BlazorContacts.Web** to **Start**.

Now, when you start debugging, the API will run on `http://localhost:5001` and the web server will run on another port. I have configured mine to run on `http://localhost:5002`, for example. When you navigate to the `/contacts` page, the server-side Blazor frontend will fetch data from the external API using techniques that will properly dispose HttpClient and not result in socket exhaustion.

Source code for this project is [available on GitHub](https://github.com/bradwellsb/blazor-contacts/tree/tutorial-part1). In the coming tutorials, we will build off this application by adding IdentityServer4 protection to the API.

[Source](https://wellsb.com/csharp/aspnet/blazor-httpclientfactory-and-web-api/)