Reduce code boilerplate with Blazor Toolkit. Save ~17 lines per API call
9/16/2025 by Yuriy Frankiv (aka InstanceMaster)
When building real-world Blazor applications, a lot of the complexity doesn't come from UI rendering itself, it comes from state management, service calls, error handling, and validation. Developers often find themselves writing repetitive boilerplate code: toggling loading states, catching exceptions, rolling back model changes, showing validation errors, or paging through API results. The Blazor Toolkit is designed to reduce that friction. By providing a set of reusable components, services, and patterns, it lets you focus more on your business logic and less on wiring code.
Unlike Angular, which forces you to use the right structure from the beginning, Blazor doesn't require you to follow any specific structure. You are free to choose where and how to store your Razor pages, keep the code section inline or move it into a separate file. If your project is simple you can end up with a single Razor file containing all your logic including API calls or database access (in server render mode). If you keep reading this article you will see, I'm not encouraging you to have a single Razor page with everything in it... quite the contrary.
Why Blazor Toolkit?
I have completed several projects using Blazor. While the code base grew I had to structure it in some way to keep control over it. I introduced services and API abstractions. I wrapped all the basic code such as page loading, showing progress, and handling exceptions into utility classes or base classes. My goal was to keep everything clean and simple, and to make as much code as possible unit testable.
For instance, I introduced an ITimeProvider
interface to abstract the current time before it was added in .NET 8.
Every time I started a new project though, I had to copy all the base classes into the new project. It was a fast but repetitive process. I even open-sourced my own project template, DevCoreApp. But with each new version of .NET, it became harder to maintain. So I thought: if all these utility tools I wrote to support my own structure helped me write clean code faster, maybe it would be better to wrap them into a NuGet library so I don't have to manually copy them every time. This is how Blazor Toolkit was born.
How can it help you?
Imagine you have to build an ERP (Enterprise Resource Planning) system. Such systems can be heavy with lots of forms, grids, charts, and reports. They can grow to several dozen pages. All APIs will implement one or more CRUD functions. All your pages will serve CRUD and have to:
- indicate loading progress
- handle and show errors
- handle "empty" results
- handle data presentation
- handle form submit (and errors if it goes wrong)
If you do not enforce any structure into your .NET projects you will end up with a big pile of code mostly doing CRUD with duplicated parts. And this is where Blazor Toolkit can help by:
- enforcing rules for creating model classes to unify API types, making it simpler to introduce complex data structures like paged lists and search results
- offering easy-to-use methods for handling HTTP requests and responses, reducing boilerplate code and potential errors
- enforcing middleware service classes and making it easy to implement them with special attributes, which abstracts complex processes from the UI layer. This promotes a clean separation of concerns, making your application more modular and maintainable
- standardizing service return types, which makes service calls much cleaner, reduces the amount of needed code in Razor pages, and keeps code easier to maintain
Example: Todo List
Let's explore the benefits with a simple example: a Todo List page. I know... everybody uses it as an example. There are probably more todo list applications in the world than people who use them.
Without Blazor Toolkit
private async Task UpdateItemStatusAsync(TodoItem item, ChangeEventArgs e)
{
showError = false;
errorMessage = "";
isSubmitting = true;
isReading = false;
StateHasChanged();
try
{
item.IsCompleted = (bool)e.Value;
var result = await Http.PutAsJsonAsync($"api/todo/{item.Id}", item);
if (!result.IsSuccessStatusCode)
{
BlazorToolkit.Services.ServiceActionError error = null;
try
{
error = await result.Content.ReadFromJsonAsync<BlazorToolkit.Services.ServiceActionError>();
}
catch
{
throw new HttpRequestException($"Request failed, code {result.StatusCode}", null, result.StatusCode);
}
if (error != null)
{
throw new HttpRequestException(error.Message, null, result.StatusCode);
}
throw new HttpRequestException($"Request failed, code {result.StatusCode}", null, result.StatusCode);
}
todos = await result.Content.ReadFromJsonAsync<ModelList<TodoItem>>();
}
catch (Exception ex)
{
item.IsCompleted = !item.IsCompleted; //rollback
showError = true;
errorMessage = $"An error occurred while updating the item.: {ex.Message}";
}
isSubmitting = false;
}
You manually track loading states, catch exceptions, roll back changes, and display error messages. Every CRUD operation repeats the same structure.
With Blazor Toolkit
private async Task UpdateItemStatusAsync(TodoItem item, ChangeEventArgs e)
{
item.IsCompleted = (bool)e.Value;
await this.ServiceSubmitAsync(
async () => await Service.UpdateAsync(item),
(t) => todos = t,
null,
(e) =>
{
item.IsCompleted = !item.IsCompleted; // rollback
return false; // show main error banner
});
}
What changed?
ServiceSubmitAsync
takes care of state management (IsSubmitting
,IsReading
,InProgress
) so you don't have to toggle flags manually. See ServiceCallExtensions for more details.Error handling is centralized. If the service fails, you can choose to roll back state or display a banner message.
The page is cleaner and focused only on business logic.
All service calls return a standardized
ServiceResult<T>
type, making it easy to handle success and failure uniformly.The service layer abstracts away the HTTP details, so your Razor page doesn't need to know about
HttpClient
or status codes.
Another key part of the Blazor Toolkit is how it encourages a clear separation between UI and API calls by introducing service classes. Instead of sprinkling HttpClient
calls across Razor pages, you define an interface and implement it once. This makes your codebase more modular and easier to test.
Service Interface
public interface ITodoService
{
...
Task<ServiceActionResult<ModelList<TodoItem>?>> UpdateAsync(TodoItem updatedTodo);
...
}
Service Implementation
[BlazorService]
public class TodoService : ITodoService
{
IApiContext<TodoItem> Api { get; set; }
public TodoService(IApiContext<TodoItem> api)
{
Api = api;
}
...
public async Task<ServiceActionResult<ModelList<TodoItem>?>> UpdateAsync(TodoItem updatedTodo)
{
return await ServiceUtils.HandleWebApiCallAsync(
async (l) => await Api.Put(updatedTodo, updatedTodo.Id).ExecuteListAsync()
);
}
...
}
What’s happening here?
IApiContext<T>
abstracts API access, letting you build queries fluently (Top, Page, Search) before executing.ServiceUtils.HandleWebApiCallAsync
wraps API calls in a consistent error-handling pipeline. See ServiceUtils for more details.[BlazorService]
attribute makes the class discoverable for dependency injection without boilerplate configuration.All CRUD methods are implemented once and can be injected anywhere in your Blazor app.
This approach means your Razor components never have to worry about HttpClient or error handling details. They only work with a strongly typed service.
Error Handling: From Manual Alerts to Reusable Banners
Without the toolkit you might add an error banner manually:
@if (showError)
{
<div class="alert alert-danger">@errorMessage</div>
}
With the toolkit you simply drop in:
<ErrorMessageBanner IsError="IsError" Message="@ErrorMessage"></ErrorMessageBanner>
This component ties directly into the service execution pipeline. Any service call failure is automatically reflected in the banner.
Toolkit vs No Toolkit: Quick Comparison
Aspect | No Toolkit (manual) | With Blazor Toolkit |
---|---|---|
State management | Manual flags (isReading , isSubmitting ) |
Automatic via ServiceReadAsync / ServiceSubmitAsync |
Error handling | Custom try/catch and alert banners per page |
Centralized with <ErrorMessageBanner> |
CRUD operations | Repeated boilerplate for every service call | Clean and reusable service calls |
API abstractions | Raw HttpClient calls |
Service interfaces (ITodoService ) |
Pagination | Custom helper methods (e.g., page ranges) | <ModelDataPager> component |
Code focus | Mixed logic, UI, and error handling in each Razor page | Focused on business logic with less boilerplate |
Conclusion
Blazor is flexible and lets you build applications in many different ways. That freedom is powerful, but without some structure you can quickly end up with duplicated code and messy pages. The Blazor Toolkit doesn’t take away your freedom, it simply gives you consistent patterns, reusable components, and clean abstractions.
The result is less boilerplate, better error handling, and code that’s easier to maintain.
If you’re building applications that talk to APIs, handle CRUD, and need to scale beyond just a couple of pages, the Blazor Toolkit can save you time and frustration while keeping your Blazor projects clean and maintainable.
👉 You can see the full example used in this article on GitHub: Blazor Toolkit Example
👉 You can install the package directly from NuGet: DevInstance.BlazorToolkit
Thanks for reading to the end. You can follow me on X: @InstanceMaster or LinkedIn Yuriy Frankiv.