In my previous post Making HTTP Requests in Blazor Server Apps, I covered different techniques of making HTTP requests in Blazor Server apps where you have access to all .NET libraries and components. If you are creating a Blazor WebAssembly App, then your code is running on the client within the browser sandbox and your options are somehow limited. In this tutorial, I will show you how you can make HTTP requests from Blazor WebAssembly Apps.
Table of Contents
Overview of HttpClient in Blazor WebAssembly Apps
Blazor WebAssembly apps call web APIs using a preconfigured HttpClient service. This preconfigured HttpClient is implemented using the use browser Fetch API and has some limitations. HttpClient can also use Blazor JSON helpers or HttpRequestMessage object to make API calls. By default, the API call requests can only be made to the same server of origin but you can call third-party APIs available on other servers if they support Cross-origin resource sharing (CORS).
The System.Net.Http.Json namespace provides extension methods for HttpClient that perform automatic serialization and deserialization using System.Text.Json. These extension methods send requests to a Web API URI and process the response accordingly. The common methods include:
- GetFromJsonAsync: Sends an HTTP GET request and parses the JSON response body to create an object.
- PostAsJsonAsync: Sends a POST request to the specified URI containing the value serialized as JSON in the request body.
- PutAsJsonAsync: Sends an HTTP PUT request, including JSON-encoded content.
To understand how to use these methods along with HttpClient, we need to create two projects. The first project will be a Web API project that will expose a Web API for clients. The second project will be Blazor WebAssembly App that will make HTTP requests to a Web API created in the first project.
Implementing an ASP.NET Core Web API
In this section, we will implement a Web API with Cross-origin resource sharing (CORS) support so that this API can be called by Blazor WebAssembly apps. Create a new Web API project BlazorClientWebAPI in Visual Studio 2019. We will create a simple API that will return the list of products so let’s first create a Models folder in the project and add the following Product class to it.
Product.cs
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Next, create a Controllers folder and add the following ProductsController in it. The controller is simply returning some fake product data from the GetProducts method.
ProductsController.cs
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult GetProducts()
{
var products = new List<Product>()
{
new Product()
{
Id = 1,
Name = "Wireless Mouse",
Price = 29.99m
},
new Product()
{
Id = 2,
Name = "HP Headphone",
Price = 79.99m
},
new Product()
{
Id = 3,
Name = "Sony Keyboard",
Price = 119.99m
}
};
return Ok(products);
}
}
If you will run your project and try to access the API using the URI api/products in the browser, you should be able to see the product data returned in JSON format.
Enable CORS in ASP.NET Core Web API
By default, browser security doesn’t allow a web page to make requests to a different domain other than the one from where the web page is served. This restriction is called the same-origin policy. If we want Blazor WebAssembly Apps or other client apps to consume the above Web API then we have to enable cross-origin resource sharing (CORS). Open the Startup.cs file and call the AddCors method in the ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(policy =>
{
policy.AddPolicy("CorsPolicy", opt => opt
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
});
services.AddControllers();
}
Also add the following line in the Configure method of Startup.cs file
app.UseCors("CorsPolicy");
For detailed information on CORS with ASP.NET Core apps, see Enable Cross-Origin Requests (CORS) in ASP.NET Core.
Implementing Blazor WebAssembly App
Add a new Blazor WebAssembly App project BlazorClientWebAPIsDemo in the same solution in which you created the above Web API project.
The first thing we need to make sure of is that we have the reference of System.Net.Http.Json in the project file. If it’s not available then you can add the reference.
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.1" PrivateAssets="all" />
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
</ItemGroup>
</Project>
Next, we need to configure the HttpClient service in Program.cs file. Make sure to provide the base address of the Web APIs you want to call from Blazor WebAssembly Apps
Program.cs
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient
{
BaseAddress = new Uri("http://localhost:5000/api/")
});
await builder.Build().RunAsync();
}
To consume the products API, let’s create a Products.razor component in the Pages folder. The view is very straightforward as it is simply iterating the list of products and displaying them using a simple HTML table.
Products.razor
@page "/products"
<h1>Products</h1>
@if (products == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in products)
{
<tr>
<td>@forecast.Id</td>
<td>@forecast.Name</td>
<td>@forecast.Price</td>
</tr>
}
</tbody>
</table>
}
Create a Products.razor.cs code-behind file and inject the configured HttpClient instance in the class as a private member. Finally, use the GetFromJsonAsync method to call the products API.
Products.razor.cs
public partial class Products
{
private List<Product> products;
[Inject]
private HttpClient Http { get; set; }
protected override async Task OnInitializedAsync()
{
products = await Http.GetFromJsonAsync<List<Product>>("products");
}
}
You also need to create a local copy of the Product class in the Blazor WebAssembly project to deserialized the results of the products API into a list of product objects.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Run the project and you will see the page with products loaded from a backend Web API.
Hi
I have tried this as best to my knowledge but cannot get it to work – do you have a solution that I can download?
Thanks
I uploaded the demo project on github so you can download from the following link.
https://github.com/ezzylearning/BlazorClientWebAPIsDemo