VSA organizes backend code by feature, but what about the frontend? The Blazor CRM answers this with a service layer that mirrors the VSA structure on the client side. Each feature has a service class — TodoService, CurrencyService, TaxService — that wraps HTTP calls to the corresponding API endpoints. This part builds the TodoService using the Blazor CRM's production patterns, including a BaseService for shared concerns and a RestClient wrapper for typed HTTP calls.
The service layer solves three problems in Blazor VSA applications: it isolates HTTP concerns from UI components, it centralizes authentication token management, and it provides typed request/response contracts that match the backend DTOs. Without this layer, Blazor components would be littered with HttpClient calls, token headers, and JSON deserialization — exactly the kind of scattering that VSA eliminates on the backend.
The BaseService: Token Management and Error Handling
The BaseService provides shared infrastructure for all feature services. It manages JWT tokens (retrieving, refreshing, attaching to requests), handles 401 responses (redirecting to login), and provides a standardized ExecuteWithResponseAsync method that wraps every API call:
public class TodoService : BaseService
{
private readonly RestClient _client;
public TodoService(IHttpClientFactory clientFactory, NavigationManager nav,
ISnackbar snackbar, ICurrentUserService currentUserService,
TokenProvider tokenProvider)
: base(clientFactory, nav, snackbar, currentUserService, tokenProvider)
{
_client = new RestClient(nav.BaseUri);
}
public async Task<ApiResponse<List<GetTodoListResponse>>?> GetTodoListAsync()
{
var request = new RestRequest("api/todo", Method.Get);
return await ExecuteWithResponseAsync<List<GetTodoListResponse>>(_client, request);
}
}
The ExecuteWithResponseAsync method handles the entire request lifecycle: attaching the JWT token, executing the HTTP call, deserializing the JSON response into ApiResponse<T>, handling errors, and showing snackbar notifications. Feature services inherit all of this for free — they just define the endpoint and the response type.
Feature Services Mirror Handler Structure
The TodoService has one method per API endpoint, mirroring the CQRS handlers on the backend. Create, Read, Update, Delete — each is a typed async method that returns the corresponding response DTO. Child entities get their own service methods too — CreateTodoItemAsync, UpdateTodoItemAsync, DeleteTodoItemAsync. The service layer mirrors the backend's API structure exactly, which means a developer familiar with the backend handlers can predict the service methods without reading the service code. This consistency is a key benefit of VSA — the architecture is the same on both sides.
IHttpClientFactory for Resilient HTTP
The service layer uses IHttpClientFactory instead of manually creating HttpClient instances. This provides connection pooling, automatic handler recycling (avoiding socket exhaustion), and centralized configuration of timeouts and retry policies. The RestClient wrapper from RestSharp adds convenience methods for JSON serialization and header management. Together, they make HTTP calls as simple as method calls — the Blazor component doesn't know it's making network requests.
Error Handling and User Feedback
The BaseService handles errors consistently: 401 responses trigger a redirect to login, 400 validation errors are deserialized and displayed, and unexpected errors show a generic snackbar notification. Feature services don't need try-catch blocks — the base class handles it. This is the frontend equivalent of the backend's ApiResponse<T> pattern: errors are structured, predictable, and handled in one place.