Creating a Blazor WebAssembly Application — Part 2
Blazor WebAssembly is a great way to create Single Page Application (SPA) apps using C# language. In this series, I present how to create a Blazor WebAssembly Application from scratch. This is the second article of this series, in which I demonstrate how to implement the Model classes, Interfaces and the Service classes, which are responsible for communicating with the Web API.
The project we are going to use for this demonstration was created during the Part 1 of this series, where I presented an introduction to a Blazor WebAssembly project, and explained how to get started with it. You can read the first article by clicking here.
Blazor WebAssembly Project
Let’s start cleaning the solution that was created, removing what we don’t need for this project. Delete the following files:
Overview of the Back-End Project
Before we dive into the Blazor App, let me give some background information about the project we are going to create in this series. In previous articles, I demonstrated how to create an application using .NET Web API and Angular, and for that, I created the “BookStore” project. So now we are going to create a similar front-end project but with Blazor WebAssembly. And this app will make use of the existent back-end service (Web API).
You can check the code of the back-end project on my GitHub repository by clicking here. And if you want to check the series of articles about this project, check the series “Creating an Application from Scratch using .NET Core and Angular” here on my medium blog. These are the links for the back-end service:
- Part 1: Creating the initial structure
- Part 2: Implementing the Models and creating the Database with EF Core
- Part 3: Implementing the Service classes and the Repository Pattern
- Part 4: Implementing the API layer
The back-end service contains the following endpoints:
Note: this back-end service was created to be consumed by another SPA project, which was made using Angular, and now we are going to consume the same back-end service but in a Blazor app. This is another benefit of having SPA apps for the front-end solutions, they are totally independent of the technology that is used in the back-end service.
Creating the Model classes
Let’s start creating the model classes that we need for our project, one for Category and one for Book:
If we check the API on Swagger, in the POST
method we can see the properties of a Book and a Category. In the image below you can see an example of that:
For Category we only have two properties: Id and a Name:
On line 5 and 6, we added some notations for making the property required, when using it in the UI. With that, when we implement the component, we only need to add a tag for DataAnnotationsValidator
, and it will understand that the validation of the field is coming from these notations.
For the Book model, we need the following properties:
The CategoryId
(on line 21) is the value we are going to use to save the book’s category, and there is another property named CategoryName
on line 23, and this is to be used when we display the category name of a book in the list of books.
IHttpClientFactory
The communication between the SPA and the back-end is done via HTTP requests, and for that we can use the HttpClient
or the IHttpClientFactory
. For this project we are going to use the IHttpClientFactory
(which is the recommendation for most cases). If you want to know the difference between them, you can check an article that I recently wrote about this topic, which can be found on this link.
To use the IHttpClientFactory
we need to install the package Microsoft.Extensions.Http
in our project. To do that, right-click in your solution > select “Manager NuGet Packages…”:
Then search for the extension Microsoft.Extensions.Http
and install it (for this example I’m using the latest current version which is 6.0.10):
Now let’s register the IHttpClientFactory
in the Program.cs
file. When using IHttpClientFactory
, there are many ways to configure it, you can choose between the Named clients
, Typed clients
, Generated clients
, or the Basic usage
— if you want to know more about it, and understand when it’s better to use each one, check the documentation about Making HTTP requests using IHttpClientFactory in ASP.NET Core on Microsoft Docs by clicking on this link. For this project, let’s use the default implementation, which can be configured by adding AddHttpClient
. In the Program.cs
file:
builder.Services.AddHttpClient();
We will need to come back to this same file (Program.cs
) to also include the configuration for the Service classes after we create them.
Creating the appsettings.json file
Inside of wwwroot
folder, let’s also create an appsettings.json
file. To do that, right-click in the folder > Add a new item:
In this file, add the API URL (in this example I’m using localhost
):
{
"BookStoreApi": {
"Url": "https://localhost:5001/"
}
}
Creating the Services classes
Now let’s create the services classes, which will be responsible for handling the requests to the back-end service. For that, let’s create a folder for Interfaces and a folder for the Services, and we will later configure the Dependency Injection (DI) for these classes:
Configuring Dependency Injection (DI)
Now we need to configure the DI for the service classes. If you are not familiar with DI or want to know more about DI and Service Lifetimes in .NET, you can check an article I wrote about this topic by clicking here. To configure it for the service classes, add the following configuration in the Program.cs
class:
builder.Services.AddScoped<ICategoryService, CategoryService>();
builder.Services.AddScoped<IBookService, BookService>();
In this example, we added the Scoped lifetime, this means that the services are going to be created each time they are requested.
Implementing the Service classes
For both Service classes, we need a method to Add, Read, Update and Delete (CRUD). For demonstration purpose, I’m going to use the BookService as an example, and you can find the complete code in my GitHub by clicking on this link. This is the Interface IBookService:
We can now implement the Service classes for Book and Category. This is the initial of the BookService
class, which implements the interface IBookService
:
First, we create some private properties, which are going to be used by the methods in this class.
- On line 3 there is the variable for
IConfiguration
, which will be used to get the API Url from theappsettings.json
file. - On line 4 there is the
IHttpClientFactory
, which will be used to create the HTTP client. - On line 5 there is a variable for
baseUri
, which value comes from the configuration fileappsettings.json
. - On line 7 there is the constructor of the class, which receive the
IConfiguration
and theIHttpClientFactory
via Dependency Injection. - On line 10, we are using the
_configuration
to read the API Url (which is coming from theappsettings.json
file), and the value is added to the_baseUri
variable.
Now let’s implement in the BookService class the Get methods, one GetAll
, which will return a list of all books, and the GetById
, which receives the id of a book as a parameter, and returns the book.
- On line 3, we create an instance of the
HttpClient
by calling theCreateClient
. - On line 5, is where the request to the back-end service is being made, and we are using the
GetFromJsonAsync
passing the type of data that we want to deserialize — which in this case is anIEnumerable<Book>
— in an asynchronous operation. - On line 7 we return the list of books.
- The
GetById
method (line 10) follows the same structure, and there are two differences in this method: first difference, is that this method receives the id of a book as a parameter, and returns a single book instead of a list of books, the second difference is that there is a validation on line 16 (response.IsSuccessStatusCode
) to check if the response has a success status code, and in case it has, it will return the book, otherwise, return null. The reason for this check it’s because for theGetById
, when there is no book with the searched id, the API returns not found — which means it is not success — , and for theGetAll
, in case there are no books, the API returns null.
Next, let’s implement the Add method:
- On line 1, the Add method receives as a parameter, the book we are going to add.
- On line 3, we create an instance of the
HttpClient
by calling theCreateClient
. - On line 4 serialize the book to a JSON variable.
- On line 7 we made the
Post
request to the back-end, with the book to be added. - On line 9, we call the
response.IsSuccessStatusCode
, in order to know if the response of the request on line 7 was successful or not, in case of Successful, it will return true. - On line 11 we deserialize the content of the response of the request (the added book), and return it.
- On line 16 we return null, for the case when the response is not successful.
Next, let’s implement the Update method, which follows a similar structure of the Add method,
- On line 7 we made a
Put
request with the updated book. - On line 9, in case the response of the request is successful, the method return true, otherwise returns false.
Next, let’s implement the Delete method:
- On line 5 we make the
Delete
request informing the id of the book we want to delete. - On line 7, in case the response of the request is successful, the method return true, otherwise returns false.
Conclusion
Now we have the Model classes and the Services classes implemented and ready to be used. In the next part, we are going to create the components and pages for Categories and Books.
This is the link for the project in GitHub:
https://github.com/henriquesd/BlazorSPABookStore
If you like this project, I kindly ask you to give a ⭐️ in the repository.
Thanks for reading!