Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Blazor Microservice Communication Patterns

Tech May 18 2

When building modern web applications with Blazor, efficient communication between client and server components is essential. This guide explores how to implement robust microservice communication patterns using HttpClient and related extensions.

Setting Up the Project Structure

Begin by creating a new Blazor WebAssembly project with hosting enabled. This will establish the foundation for our communication demonstration. The project will consist of three main components: a server project, a shared library, and a client application.

Server-Side Implementation

Our server project exposes a REST API through a WeatherForecastController. This controller provides weather data that our client will consume.

using WeatherApp.Shared;
using Microsoft.AspNetCore.Mvc;
namespace WeatherApp.Server.Controllers;
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] WeatherSummaries = new[]
    {
        "Clear", "Cloudy", "Rainy", "Snowy", "Stormy", "Windy"
    };
    
    private readonly ILogger<weatherforecastcontroller> _logger;
    
    public WeatherForecastController(ILogger<weatherforecastcontroller> logger)
    {
        _logger = logger;
    }
    
    [HttpGet]
    public IEnumerable<weatherdata> GetWeatherData()
    {
        return Enumerable.Range(1, 7)
            .Select(index => new WeatherData
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-10, 35),
                Summary = WeatherSummaries[Random.Shared.Next(WeatherSummaries.Length)]
            })
            .ToArray();
    }
}</weatherdata></weatherforecastcontroller></weatherforecastcontroller>

This controller exposes a GET endpoint at /api/WeatherForecast that returns an array of weather data objects. The [Route("api/[controller]")] attribute automatically maps the controller name to the route, and the [HttpGet] attribute specifies the HTTP method.

Shared Model Layer

Creating shared models between client and server eliminates the need for duplicate type definitions and ensures consistent data structures.

namespace WeatherApp.Shared;
public class WeatherData
{
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public string? Summary { get; set; }
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

By placing this model in a shared project, both client and server can reference the same type, preventing serialization mismatches and reducing maintenance overhead.

Cliant-Side Implementation

The client component fetches and displays weather data using HttpClient.

@page "/weather"
@using WeatherApp.Shared
@inject HttpClient Http

<h3>Weekly Weather Forecast</h3>
@if (weatherData == null)
{
    <p>Loading weather information...</p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temperature (C)</th>
                <th>Temperature (F)</th>
                <th>Condition</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var day in weatherData)
            {
                <tr>
                    <td>@day.Date.ToShortDateString()</td>
                    <td>@day.TemperatureC</td>
                    <td>@day.TemperatureF</td>
                    <td>@day.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherData[]? weatherData;
    
    protected override async Task OnInitializedAsync()
    {
        weatherData = await Http.GetFromJsonAsync<weatherdata>("api/WeatherForecast");
    }
}</weatherdata>

The component injects HttpClient and uses the GetFromJsonAsync extension method to fetch data. The @if block handles the loading state before data is available.

HttpClient Best Practices

HttpClient should never be instantiated directly in Blazor components. Instead, register it as a scoped service in Program.cs:

builder.Services.AddScoped(sp => new HttpClient
{
    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});

Advanced HTTP Operations

Beyond GET requests, HttpClient provides methods for POST, PUT, and DELETE operations. The HttpClientJsonExtensions class offers convenient methods for JSON serialization.

// POST request with JSON payload
public async Task SubmitOrder(OrderRequest order)
{
    await Http.PostAsJsonAsync("api/orders", order);
}

// PUT request with JSON payload
public async Task UpdateProduct(Product product)
{
    await Http.PutAsJsonAsync($"api/products/{product.Id}", product);
}

Custom Serialization Configuration

Control JSON serialization behavior using JsonSerializerOptions:

private readonly JsonSerializerOptions _jsonOptions = new()
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true,
    Converters = { new JsonStringEnumConverter() }
};

// Usage with HttpClient
var result = await Http.GetFromJsonAsync<weatherdata>(
    "api/WeatherForecast", _jsonOptions);</weatherdata>

Real-World Application: Pizza Ordering System

Let's implement a complete ordering system with menu and order services.

Menu Service Implementation

using PizzaApp.Shared;
using System.Net.Http.Json;
using System.Threading.Tasks;

namespace PizzaApp.Client.Services
{
    public class MenuService : IMenuService
    {
        private readonly HttpClient _httpClient;
        
        public MenuService(HttpClient httpClient)
        {
            _httpClient = httpClient;
        }
        
        public async Task<menu> GetAvailableMenu()
        {
            var pizzas = await _httpClient.GetFromJsonAsync<pizza>("api/menu");
            return new Menu { Items = pizzas!.ToList() };
        }
    }
}</pizza></menu>

Order Service Implementation

using PizzaApp.Shared;
using System.Net.Http.Json;
using System.Threading.Tasks;

namespace PizzaApp.Client.Services
{
    public class OrderService : IOrderService
    {
        private readonly HttpClient _httpClient;
        
        public OrderService(HttpClient httpClient)
        {
            _httpClient = httpClient;
        }
        
        public async Task SubmitOrder(OrderRequest order)
        {
            await _httpClient.PostAsJsonAsync("api/orders", order);
        }
    }
}

Database Integration

For data persistence, we'll use Entity Framework Core to manage our data models:

public class PizzaDbContext : DbContext
{
    public PizzaDbContext(DbContextOptions<pizzadbcontext> options) 
        : base(options) { }
    
    public DbSet<pizza> Pizzas { get; set; } = default!;
    public DbSet<order> Orders { get; set; } = default!;
    public DbSet<customer> Customers { get; set; } = default!;
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<order>()
            .HasMany(o => o.Pizzas)
            .WithMany(p => p.Orders)
            .UsingEntity(j => j.ToTable("OrderPizzas"));
    }
}</order></customer></order></pizza></pizzadbcontext>

Dependency Injection Configuration

Register services in Program.cs for dependency injection:

builder.Services.AddScoped(sp => new HttpClient
{
    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});

builder.Services.AddTransient<imenuservice menuservice="">();
builder.Services.AddTransient<iorderservice orderservice="">();</iorderservice></imenuservice>

Handling Loading States

Implement loading indicators for better user experience:

@if (menu == null)
{
    <div class="text-center">
        <div class="spinner-border text-primary" role="status">
            <span class="visually-hidden">Loading menu...</span>
        </div>
    </div>
}
else
{
    <pizzalist items="@menu.Items"></pizzalist>
}

Conclusion

Blazor's HttpClient integration provides a robust mechanism for microservice communication. By leveraging shared models, proper dependency injection, and JSON serialization extensions, you can build scalable and maintainable applications with seamless client-server interaction.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.