VSATutorialSeptember 2026 · 8 min read

VSA Todo App — Part 12: Front-End Service Layer & Typed HTTP Client Patterns

TL;DR

Part 12 builds the front-end service layer that bridges Blazor components to VSA API endpoints. Using the Blazor CRM's TodoService as a model, we implement a BaseService with token management and error handling, a RestClient wrapper for typed HTTP calls, and per-feature service classes that mirror the VSA handler structure on the client side.

Part 12 of 20 in the VSA Todo App Tutorial Series|← Previous: Part 11|Next: Part 13 →

Help Us Grow

Love this tutorial? Explore our ready-to-use enterprise starter kits built with VSA in .NET 10.

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.

Key Takeaways

  • The service layer isolates HTTP concerns from Blazor components — components call typed methods, not raw HTTP
  • BaseService centralizes token management, error handling, and user feedback for all feature services
  • Feature service methods mirror the backend's API structure — one method per endpoint, matching response DTOs
  • IHttpClientFactory prevents socket exhaustion and enables centralized timeout/retry configuration
  • Structured error handling in the base class eliminates try-catch clutter in feature services and components

Frequently Asked Questions

Q: Why a separate service layer in Blazor VSA apps?

It isolates HTTP concerns from UI components. Without it, every component would manage its own HttpClient, token headers, and JSON parsing. The service layer provides typed methods that match the backend DTOs, making the frontend as organized as the VSA backend.

Q: Should front-end services mirror the VSA handler structure?

Yes. Each backend feature gets a corresponding front-end service class. The service methods map 1:1 to API endpoints. This consistency means developers familiar with the backend can predict the frontend service API without reading the service code.

Q: How to handle API errors in the VSA front-end service layer?

Centralize error handling in a BaseService. Handle 401 (redirect to login), 400 (display validation errors), and unexpected errors (generic notification). Feature services inherit this behavior and don't need their own error handling. The backend's ApiResponse<T> pattern makes error responses predictable.

Q: How to share DTOs between the client and server in VSA?

In a single-project monolith, the request/response DTOs defined in the feature's Cqrs/ folder are directly usable by Blazor components — they're in the same assembly. Just reference the feature namespace. This is another reason single-project VSA is so efficient.

Part 12 of 20 in the VSA Todo App Tutorial Series|← Previous: Part 11|Next: Part 13 →

Ready to study real VSA code?

Every Indotalent product is a complete .NET 10 application built with Vertical Slice Architecture. Complete source code — $21 each.

Explore Products

Looking for a ready-to-use traditional monolithic multilayered clean architecture?

Monolithic Clean Architecture — 1,300+ devs, 500+ forks. Clean Arch + CQRS + Repository Pattern. Free & open source for commercial use.

Star on GitHub