Building Scalable Applications with .NET 8, Blazor, and Microservices

In modern web development, scalability, flexibility, and maintainability are key challenges. A microservices architecture offers a way to break monolithic applications into independently deployable services, improving scalability and team productivity.

Blazor, part of .NET 8, is an advanced UI framework that enables full-stack C# development, allowing developers to build interactive web applications that consume microservices via REST APIs, gRPC, and event-driven messaging.

In this article, we’ll explore how Blazor and microservices work together, discuss API integration patterns, and walk through code examples to build a real-world scalable application.

Why Use Blazor with Microservices?

  • Separation of Concerns: Frontend (Blazor) is decoupled from backend services.
  • Scalability: Individual microservices can scale independently.
  • Resilience: Failure in one service doesn’t affect the entire application.
  • Technology Agnostic: Different services can use different stacks.
  • Developer Productivity: Teams can work on separate microservices without conflicts.

Blazor and Microservices Architecture Overview

.NET 8 Blazor microservices-based solutions typically consist of the following:

  1. Blazor Frontend — A client-side UI built with Blazor WebAssembly or Blazor Server.
  2. API Gateway — A centralized point for routing requests to microservices (e.g., OcelotYARP).
  3. Microservices — Independent backend services exposing REST APIs or gRPC endpoints.
  4. Database Per Service — Each microservice can have its own database (SQL Server, PostgreSQL, MongoDB, etc.).
  5. Event-Driven Messaging — Services communicate asynchronously using RabbitMQKafka, or Azure Service Bus.

Technology Stack

  • Frontend: Blazor WebAssembly (WASM) or Blazor Server
  • Backend: ASP.NET Core Web API Microservices
  • Database: SQL Server, PostgreSQL, MongoDB
  • API Gateway: Ocelot, YARP
  • Authentication: IdentityServer, Azure AD
  • Message Broker: RabbitMQ, Kafka

1️⃣Building a Microservice with .NET 8

We’ll start by creating an Orders Microservice in ASP.NET Core Web API.

Install the required packages

dotnet new webapi -n OrdersService
cd OrdersService
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Swashbuckle.AspNetCore

Define the Order Model

Models/Order.cs

public class Order
{
public int Id { get; set; }
public string Product { get; set; }
public int Quantity { get; set; }
}

Create the Orders API Controller

This microservice exposes an API endpoint: GET /api/orders/{id}

[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
private static readonly List<Order> Orders = new()
{
new Order { Id = 1, Product = "Laptop", Quantity = 1 },
new Order { Id = 2, Product = "Smartphone", Quantity = 2 }
};

[HttpGet("{id}")]
public IActionResult GetOrder(int id)
{
var order = Orders.FirstOrDefault(o => o.Id == id);
if (order == null) return NotFound();
return Ok(order);
}
}

2️⃣Consuming Microservices in Blazor

Inject HttpClient in Blazor

Program.cs

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("https://localhost:5001") });

Call the API in a Blazor Component

Clicking Get Order fetches and displays the order details.

@inject HttpClient Http

<h3>Order Details</h3>
<p>@OrderDetails</p>

<button @onclick="LoadOrder">Get Order</button>

@code {
private string OrderDetails = "Click to load order...";

private async Task LoadOrder()
{
var order = await Http.GetFromJsonAsync<Order>("api/orders/1");
OrderDetails = $"Product: {order.Product}, Quantity: {order.Quantity}";
}

public class Order
{
public string Product { get; set; }
public int Quantity { get; set; }
}
}

3️⃣Implementing an API Gateway (Ocelot)

An API Gateway routes requests from Blazor to the appropriate microservice.

Install Ocelot

dotnet add package Ocelot.AspNetCore

Define Ocelot Configuration

ocelot.json

{
"Routes": [
{
"DownstreamPathTemplate": "/api/orders/{id}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [{ "Host": "localhost", "Port": 5001 }],
"UpstreamPathTemplate": "/orders/{id}",
"UpstreamHttpMethod": [ "GET" ]
}
]
}

Configure Ocelot in Program.cs

Blazor only needs to call /orders/{id}, and Ocelot routes it to the right microservice.

builder.Services.AddOcelot();
app.UseOcelot().Wait();

4️⃣Event-Driven Microservices with RabbitMQ

Instead of synchronous API calls, we can use event-driven messaging.

Publish an Order Created Event

OrderService

public void PublishOrderCreatedEvent(int orderId)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.QueueDeclare(queue: "order_events", durable: false, exclusive: false, autoDelete: false);

string message = JsonSerializer.Serialize(new { OrderId = orderId });
var body = Encoding.UTF8.GetBytes(message);

channel.BasicPublish(exchange: "", routingKey: "order_events", body: body);
}

Subscribe in Blazor

Now Blazor reacts to order events asynchronously

public class OrderListenerService : BackgroundService
{
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.QueueDeclare(queue: "order_events", durable: false, exclusive: false, autoDelete: false);

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
Console.WriteLine($"Received: {message}");
};

channel.BasicConsume(queue: "order_events", autoAck: true, consumer: consumer);
return Task.CompletedTask;
}
}

Extending .NET 8 Blazor and Microservices with gRPC and Kubernetes

Extending microservices with gRPC enables high-performance communication, while Kubernetes automates deployment and orchestration. By integrating these technologies, you can build a scalable, efficient, and resilient microservices architecture. In this article, we’ll explore how to enhance .NET 8 microservices with gRPC for fast communication and Kubernetes for seamless deployment.

5️⃣Using gRPC for Faster Microservice Communication

While REST APIs are common, gRPC (gRPC Remote Procedure Calls) offers higher performance, lower latency, and strong type safety, making it ideal for microservices.

Why Use gRPC?

  • Efficient Binary Serialization (Protocol Buffers) — Faster than JSON
  • Strongly Typed Contracts — Enforced via .proto files
  • Streaming Support – Ideal for real-time applications
  • Multiplexing – Multiple requests over a single connection

Step 1: Create a gRPC Microservice

dotnet new grpc -n OrdersGrpcService
cd OrdersGrpcService

Step 2: Define the gRPC Service

Protos/orders.proto

syntax = "proto3";

service OrderService {
rpc GetOrder (OrderRequest) returns (OrderResponse);
}

message OrderRequest {
int32 id = 1;
}

message OrderResponse {
int32 id = 1;
string product = 2;
int32 quantity = 3;
}

Step 3: Implement gRPC Service

Services/OrderService.cs

public class OrderService : OrderServiceBase
{
private readonly List<Order> _orders = new()
{
new() { Id = 1, Product = "Laptop", Quantity = 1 },
new() { Id = 2, Product = "Smartphone", Quantity = 2 }
};

public override Task<OrderResponse> GetOrder(OrderRequest request, ServerCallContext context)
{
var order = _orders.FirstOrDefault(o => o.Id == request.Id);
return Task.FromResult(order == null
? new OrderResponse()
: new OrderResponse { Id = order.Id, Product = order.Product, Quantity = order.Quantity });
}
}

Step 4: Configure gRPC in Program.cs

Now the microservice exposes gRPC endpoints

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<OrderService>();
app.Run();

6️⃣Consuming gRPC in Blazor

gRPC is a high-performance, open-source RPC framework that enables efficient, cross-platform communication between microservices using protocol buffers and HTTP/2.

Step 1: Install gRPC Client Packages

dotnet add package Grpc.Net.Client
dotnet add package Grpc.Tools

Step 2: Add gRPC Client

Program.cs

builder.Services.AddSingleton(services =>
{
var channel = GrpcChannel.ForAddress("https://localhost:5001");
return new OrderService.OrderServiceClient(channel);
});

Step 3: Call gRPC in Blazor

Blazor now fetches orders using gRPC, which is faster and more efficient than REST

@inject OrderService.OrderServiceClient OrderClient

<h3>Order Details</h3>
<p>@OrderDetails</p>

<button @onclick="LoadOrder">Get Order</button>

@code {
private string OrderDetails = "Click to load order...";

private async Task LoadOrder()
{
var request = new OrderRequest { Id = 1 };
var response = await OrderClient.GetOrderAsync(request);
OrderDetails = $"Product: {response.Product}, Quantity: {response.Quantity}";
}
}

7️⃣Deploying Microservices with Kubernetes

Kubernetes (K8s) automates deployment, scaling, and management of microservices.

Step 1: Create a Dockerfile for Orders API

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY ./bin/Release/net8.0/publish/ .
ENTRYPOINT ["dotnet", "OrdersService.dll"]

Step 2: Create a Kubernetes Deployment

orders-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-service
spec:
replicas: 2
selector:
matchLabels:
app: orders-service
template:
metadata:
labels:
app: orders-service
spec:
containers:
- name: orders-service
image: myregistry/orders-service:latest
ports:
- containerPort: 80

Step 3: Apply to Kubernetes

Now the Orders Microservice is deployed on Kubernetes

kubectl apply -f orders-deployment.yaml

Combining .NET 8, Blazor, and microservices enables highly scalable, resilient applications. By integrating API Gateways, asynchronous messaging, and Blazor UI, we create a modern, decoupled architecture for future-proof applications.

Using .NET 8, Blazor, Microservices, gRPC, and Kubernetes, we’ve built a scalable, fast, and cloud-native application. Blazor provides a powerful UIgRPC ensures high-performance communication, and Kubernetes handles deployment and scaling.