Welcome to today’s post.
In today’s post I will show how to execute HTTP DELETE REST calls to a web API service from a .NET Core Blazor WebAssembly.
In a previous post where I showed how HTTP GET REST requests are executed from a Blazor WebAssembly I explained how Blazor WebAssembly and Blazor Server web applications differ in the way they interact with server resources.
In other posts I showed how to execute remote Web API methods from HTTP POST requests and HTTP PUT requests.
In those posts I showed how to structure our WebAssembly application to use a service class that is injected into a Razor component. In the service class we then made the calls to external web API method using HTTP REST calls using one of the following web API client calls:
GetFromJsonAsync<T>(string Uri)
PostAsJsonAsync(string Uri, object)
PutAsJsonAsync(string Uri, object)
With HTTP GET REST calls with GetFromJsonAsync(), we can optionally include an identifier in the Uri parameter to select one record from the backend resource. With HTTP PUT REST calls with GetFromJsonAsync(), we are required to include a JSON payload parameter, and an identifier in the Uri string parameter to select the record that we wish to have updated within the backend resource. With the HTTP POST REST calls with PostAsJsonAsync(), we are required to include a JSON payload parameter, that will be inserted into backend resource.
In today’s post I will show a different API client call that will allow us to execute HTTP DELETE REST calls to an external web API service.
In one other previous post I showed how to include server calls to the backend databases within a Blazor Server web applications. Because the service class making the database calls was injected into the Razor interface component, we showed how to replace the service class with another service class that makes HTTP REST calls to our external web API methods.
In the next section I will show how to execute HTTP DELETE REST calls from a Blazor WebAssembly.
Execution of an HTTP DELETE REST Call to a Web API Service
Before I show how to make the HTTP DELETE REST call from the Blazor WebAssembly, I will demonstrate how the equivalent execution is made directly to the HTTP REST web API service. I will also show how we determine the exact URI pattern we use to make the call.
As we did in the previous posts, where I showed how to make HTTP REST calls to GET, POST and PUT methods, I will show how to make the call from the Swagger interface of the running web API service that contains the HTTP web methods.
Below is the definition for the HTTP DELETE REST method that we intend to execute calls to:

Notice that there is one parameter id, that is required for the call to be permitted. This parameter is an integer that corresponds to the identity key of the record within the backend resource that we wish to delete.

For the deletion of the resource to be successful, we also require the identifier to correspond to an existing record within the backend resource. In this case the backend resource is our backend database. We can verify that the identifier that we will use as a parameter to the call will correspond to an existing record. We do this with the execution of an HTTP GET call to attempt to retrieve the details of an existing record from the backend resource.
Below is the HTTP GET call I have made to the web API backend. The result has been a successful retrieval of the record with a status code (200) returned and the existing record content returned as a JSON object:

The equivalent HTTP GET call from the CURL command is below:
curl -X 'GET' \
'http://localhost:5013/bookitems/234' \
-H 'accept: */*'
And from the browser navigation bar, the equivalent HTTP GET call is shown:
http://localhost:5013/bookitems/234
Now that we have established the existence of the record corresponding to the above identifier, we can run the HTTP DELETE REST call using the Swagger interface. The call with the correct parameter is shown below:

Following execution, we can see that the result is a successful status (200) code, with content returned as JSON containing the details of the deleted record.

Recall that in our previous post, when we ran the HTTP PUT REST call to the web API service, the result was also successful (200), but there was no content returned in the response. We could have chosen to return content when the call was successful, and no content for an unsuccessful call. Either way, what we do with the response in the interface following the call would determine if we return any content within the response.
The equivalent call made with the CURL command is shown below:
curl -X 'DELETE' \
'http://localhost:5013/bookitems/234' \
-H 'accept: */*'
Given this, the URI request pattern will look like this:
/bookitems/{Id}
If we had attempted the deletion with an identifier that we are certain has no existing record in the backend resource, then a different response status would be returned.
In the case of an identifier that does not delete any resource, the server response code returned is an Error Not Found, with a status code of 404. This result is shown below:

Now that we have seen how to make the HTTP DELETE call is made through the web API service, I will show how it is done through the Blazor WebAssembly in the next section.
Execution of HTTP DELETE Web API calls from the Blazor WebAssembly
In this section I will implement an additional method, DeleteBook() within the BookService class to execute the web API call to the HTTP PUT web API method. The EditBook.razor component, in addition to permitting updates, allows deletion of the record with an execution of the call to the service method DeleteBook().
The implementation for the EditBook.razor component, which is predominantly like that for the updating of records we covered in the previous post on using HTTP PUT requests is shown below:
EditBook.razor:
@page "/editbook"
@using Microsoft.AspNetCore.Components
@using BookLoanBlazorWASMApp.Services
@using BookLoanBlazorWASMApp.Models
@using BookLoanBlazorWASMApp.Validations
@inject IBookService LibraryBookService
@inject NavigationManager PageNavigation
@inject IJSRuntime JS
<PageTitle>Edit Book</PageTitle>
<h3>Edit Book</h3>
@if (book == null)
{
<p><em>Loading...</em></p>
}
else
{
<EditForm Model="@editbook" OnSubmit="@Submit">
<CustomBookValidation @ref="customValidation" />
<ValidationSummary />
<div class="form-field">
<label>ID:</label>
<div>
<label>@editbook!.ID</label>
</div>
</div>
<div class="form-field">
<label>Title:</label>
<div>
<InputText @bind-Value=editbook.Title></InputText>
</div>
</div>
<div class="form-field">
<label>Author:</label>
<div>
<InputText @bind-Value=editbook.Author></InputText>
</div>
</div>
<div class="form-field">
<label>Year Published:</label>
<div>
<InputNumber @bind-Value=editbook.YearPublished></InputNumber>
</div>
</div>
<div class="form-field">
<label>Genre:</label>
<div>
<InputSelect @bind-Value="editbook.Genre">
<option value="">Select genre ...</option>
@foreach (var genres in @editbook.Genres)
{
<option value="@genres.Value.ToString()">@genres.Value.ToString()</option>
}
</InputSelect>
</div>
</div>
<div class="form-field">
<label>Edition:</label>
<div>
<InputText @bind-Value=editbook.Edition></InputText>
</div>
</div>
<div class="form-field">
<label>ISBN:</label>
<div>
<InputText @bind-Value=editbook.ISBN></InputText>
</div>
</div>
<div class="form-field">
<label>Location:</label>
<div>
<InputText @bind-Value=editbook.Location></InputText>
</div>
</div>
<div class="form-field">
<label>Media Type:</label>
<div>
<InputSelect @bind-Value="editbook.MediaType">
<option value="">Select media type ...</option>
@foreach (var mediatypes in @editbook.MediaTypes)
{
<option value="@mediatypes.Value.ToString()">@mediatypes.Value.ToString()</option>
}
</InputSelect>
</div>
</div>
<br />
<button class="btn btn-primary" type="submit">
Update Changes
</button>
<br />
<br />
<button class="btn btn-primary"
@onclick="DeleteBook">
Delete
</button>
</EditForm>
<br />
}
@code {
[Parameter]
[SupplyParameterFromQuery]
public int ID { get; set; }
private CustomBookValidation? customValidation;
private BookViewModel? book;
private BookEditModel? editbook;
protected override async Task OnInitializedAsync()
{
book = await LibraryBookService.GetBook(ID);
editbook = new BookEditModel(book);
}
private string Message = String.Empty;
private async void Submit()
{
customValidation?.ClearErrors();
var errors = new Dictionary<string, List<string>>();
if (string.IsNullOrEmpty(editbook!.Title))
{
errors.Add(
nameof(editbook.Title),
new() { "Book 'Title' is required." }
);
}
if (string.IsNullOrEmpty(editbook!.Author))
{
errors.Add(
nameof(editbook.Author),
new() { "Book 'Author' is required." }
);
}
if (string.IsNullOrEmpty(editbook!.MediaType))
{
errors.Add(
nameof(editbook.MediaType),
new() { "Book 'MediaType' is required." }
);
}
if (string.IsNullOrEmpty(editbook!.Genre))
{
errors.Add(
nameof(editbook.Genre),
new() { "Book 'Genre' is required." }
);
}
if (editbook!.YearPublished < 1000 || editbook!.YearPublished > 3000)
{
errors.Add(
nameof(editbook.YearPublished),
new() { "Book 'YearPublished' range must be between 1000 and 3000." }
);
}
if (errors.Any())
{
customValidation?.DisplayErrors(errors);
}
else
{
this.UpdateBook();
}
}
// Update entered book properties.
private async void UpdateBook()
{
var result = await LibraryBookService.UpdateBook(ID, editbook! as BookViewModel);
if (result != null)
message = "Record has been successfully updated!";
else
message = "Unable to update record.";
await JS.InvokeVoidAsync("alert", message);
}
// Delete book on confirmation.
private async void DeleteBook()
{
try
{
var decision = await JS.InvokeAsync<bool>("confirm", "Are you sure you want this record removed?");
if (decision == true)
{
var result = await LibraryBookService.DeleteBook(ID!);
if (result == true)
{
await JS.InvokeVoidAsync("alert", "Record has been successfully removed!");
PageNavigation.NavigateTo($"listbooks");
}
}
}
catch (System.Threading.Tasks.TaskCanceledException)
{
}
}
}
The classes for the above references model objects BookEditModel and BookViewModel are defined in my previous post on HTTP PUT requests from a WebAssembly.
Aside from the addition of the Delete button and its associated event handling method, DeleteBook(), the above component is almost identical to that for the update Razor component.
Using DeleteAsync() to Execute HTTP DELETE REST Calls to a Web API
To execute HTTP DELETE REST calls to remote web API methods requires us to include the following namespace in our code:
System.Net.Http.Json
The parameters required to use the DeleteAsync() library method include the URI for the API method.
As I showed in the API web service in the previous section, the URI request pattern is of the form:
bookitems/{Id}
Where {id} is the resource identifier.
With the Book Service class that I implemented in the previous posts on HTTP GET, POST and PUT calls, I add the following method, DeleteBook() to the service class:
public async Task<bool> DeleteBook(int Id)
{
try
{
await _http.DeleteAsync(_apiUri + $"bookitems/{Id}");
return true;
}
catch
{
return false;
}
}
When the above method DeleteBook() is included in the BookService class, it will look as follows:
BookService.cs:
using BookLoanBlazorWASMApp.Models;
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();
}
/// <summary>
/// GetBook()
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<BookViewModel> GetBook(int id)
{
var book = await _http.GetFromJsonAsync<BookViewModel>(_apiUri + "bookitems/" + id);
return book!;
}
/// <summary>
/// SaveBook()
/// </summary>
/// <param name="vm"></param>
/// <returns></returns>
public async Task<int> SaveBook(BookViewModel vm)
{
try
{
var response = await _http.PostAsJsonAsync(_apiUri + "bookitems", vm);
var content = response.Content;
return 1;
}
catch
{
return 0;
}
}
/// <summary>
/// UpdateBook()
/// </summary>
/// <param name="Id"></param>
/// <param name="vm"></param>
/// <returns></returns>
public async Task<int> UpdateBook(int Id, BookViewModel vm)
{
try
{
var response = await _http.PutAsJsonAsync(_apiUri + $"bookitems/{Id}", vm);
var content = response.Content;
return 1;
}
catch
{
return 0;
}
}
/// <summary>
/// DeleteBook()
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
public async Task<bool> DeleteBook(int Id)
{
try
{
await _http.DeleteAsync(_apiUri + $"bookitems/{Id}");
return true;
}
catch
{
return false;
}
}
}
}
In the next section, I will show how the HTTP DELETE REST calls are tested.
Testing the HTTP DELETE REST Call from the Blazor WebAssembly
To test the call to the Web API from our service within the WebAssembly web client, we run the application.
In the landing page, we select the List Books menu item.
In the list of Books we nominate the record we wish to remove, then click on the Edit hyperlink for the record.

The edit form opens with the selected record displaying its details.
The rendered Delete button shows as the lest control in the form:

Before I perform the deletion action, I first select the browser Developer Tools option so that we can view the HTTP request and response.
I then hit the Delete button.
Once the deletion action been actioned, the following confirmation alert will popup:

What this tells us is to decide if we want to delete the current record.
To delete the record, we depress the Ok dialog button.
Once the deletion has been completed, the following alert will popup:

In the Developer Tools, select the Network tab. You will then see the status code of 200 as shown in the Header sub-tab:

To view the response, we click on the Response sub-tab, which shows the JSON object for the deleted record:

To verify the deletion of the record has been successful, we can re-run the Book listing and review the records. You will notice that the Book with the title Sample Book 1 has been removed as it no longer appears in the list of Books:

We have seen how to execute the deletion to data using HTTP DELETE calls to a web API service from within a .NET Core Blazor WebAssembly web application.
That is all for today’s post.
I hope you have found this post useful and informative.

Andrew Halil is a blogger, author and software developer with expertise of many areas in the information technology industry including full-stack web and native cloud based development, test driven development and Devops.