plugins/dotnet-blazor/skills/microservices-patterns/SKILL.md
.NET microservices patterns including service decomposition, communication, CQRS, saga, and resilience
npx skillsauth add markus41/claude microservices-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
E-Commerce Platform:
├── Catalog Service (products, categories, search)
├── Order Service (orders, order processing)
├── Payment Service (payment processing, refunds)
├── Inventory Service (stock management)
├── Notification Service (email, SMS, push)
├── Identity Service (authentication, users)
└── Gateway (API gateway, BFF)
Each service owns its data store. No shared databases.
// Catalog uses PostgreSQL
builder.AddNpgsqlDbContext<CatalogDbContext>("catalogdb");
// Order uses SQL Server
builder.AddSqlServerDbContext<OrderDbContext>("orderdb");
// Notification uses Cosmos DB
builder.AddCosmosDbContext<NotificationDbContext>("cosmosdb");
// Command side
public sealed record CreateOrderCommand(int CustomerId, List<OrderItemDto> Items);
public sealed class CreateOrderHandler(OrderDbContext db, IPublishEndpoint bus)
{
public async Task<int> HandleAsync(CreateOrderCommand command, CancellationToken ct)
{
var order = Order.Create(command.CustomerId, command.Items);
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
await bus.Publish(new OrderCreatedEvent(order.Id, order.CustomerId), ct);
return order.Id;
}
}
// Query side (separate read model, possibly different DB)
public sealed class OrderQueryService(IReadOnlyDbContext readDb)
{
public async Task<OrderDetailDto?> GetByIdAsync(int id, CancellationToken ct) =>
await readDb.Orders
.AsNoTracking()
.Where(o => o.Id == id)
.Select(o => o.ToDetailDto())
.FirstOrDefaultAsync(ct);
}
// Using MassTransit state machine
public sealed class OrderSaga : MassTransitStateMachine<OrderSagaState>
{
public OrderSaga()
{
InstanceState(x => x.CurrentState);
Event(() => OrderCreated, x => x.CorrelateById(m => m.Message.OrderId));
Event(() => PaymentProcessed, x => x.CorrelateById(m => m.Message.OrderId));
Event(() => InventoryReserved, x => x.CorrelateById(m => m.Message.OrderId));
Initially(
When(OrderCreated)
.Then(ctx => ctx.Saga.OrderId = ctx.Message.OrderId)
.Publish(ctx => new ProcessPaymentCommand(ctx.Saga.OrderId))
.TransitionTo(AwaitingPayment));
During(AwaitingPayment,
When(PaymentProcessed)
.Publish(ctx => new ReserveInventoryCommand(ctx.Saga.OrderId))
.TransitionTo(AwaitingInventory),
When(PaymentFailed)
.Publish(ctx => new CancelOrderCommand(ctx.Saga.OrderId))
.TransitionTo(Failed));
During(AwaitingInventory,
When(InventoryReserved)
.Publish(ctx => new FulfillOrderCommand(ctx.Saga.OrderId))
.TransitionTo(Completed));
}
}
// Microsoft.Extensions.Resilience + Polly v8
builder.Services.AddHttpClient<ICatalogClient>(client =>
client.BaseAddress = new("https+http://catalog-api"))
.AddStandardResilienceHandler(); // Retry + Circuit Breaker + Timeout
// Custom pipeline
builder.Services.AddResiliencePipeline("custom", pipeline =>
{
pipeline
.AddRetry(new() { MaxRetryAttempts = 3, BackoffType = DelayBackoffType.Exponential })
.AddCircuitBreaker(new() { FailureRatio = 0.5, MinimumThroughput = 10 })
.AddTimeout(TimeSpan.FromSeconds(5));
});
builder.Services.AddHealthChecks()
.AddNpgSql(connectionString, name: "database")
.AddRedis(redisConnection, name: "cache")
.AddRabbitMQ(rabbitConnection, name: "messaging")
.AddCheck<CustomHealthCheck>("custom");
app.MapHealthChecks("/health/ready", new() { Predicate = check => check.Tags.Contains("ready") });
app.MapHealthChecks("/health/live", new() { Predicate = _ => false }); // Just checks app is running
| Pattern | Use when | Trade-offs | |---------|----------|------------| | Direct client-to-service | Few services, internal apps | Simple but couples clients to services | | API Gateway (YARP/Ocelot) | Many services, external clients | Single entry point, adds latency | | BFF (Backend for Frontend) | Multiple client types (web, mobile) | Client-optimized APIs, more gateways |
// YARP reverse proxy (Microsoft's recommended API gateway)
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
app.MapReverseProxy();
Each service owns its data. Cross-service data needs are resolved via:
Order Service ──(event)──> Catalog Service
│ OrderDB │ CatalogDB
│ (orders, items) │ (products, stock)
│ │
└──(HTTP)──> Payment Service
│ PaymentDB
│ (payments, refunds)
// Integration events cross service boundaries
public abstract record IntegrationEvent
{
public Guid Id { get; } = Guid.NewGuid();
public DateTime CreatedAt { get; } = DateTime.UtcNow;
}
public sealed record OrderSubmittedIntegrationEvent(
int OrderId, int BuyerId, decimal Total) : IntegrationEvent;
// Publish via outbox pattern for reliability
public sealed class OutboxPublisher(AppDbContext db, IEventBus bus)
{
public async Task PublishPendingEventsAsync(CancellationToken ct)
{
var pending = await db.OutboxMessages
.Where(m => !m.Published)
.OrderBy(m => m.CreatedAt)
.Take(50)
.ToListAsync(ct);
foreach (var message in pending)
{
await bus.PublishAsync(message.Event, ct);
message.Published = true;
message.PublishedAt = DateTime.UtcNow;
}
await db.SaveChangesAsync(ct);
}
}
Each service can own a UI fragment:
@* Main Blazor app composes service-specific components *@
<CatalogProductList /> @* Owned by Catalog team *@
<OrderStatusWidget /> @* Owned by Order team *@
<CartSummary /> @* Owned by Cart team *@
Pattern options:
// JWT validation at API gateway
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://identity-service";
options.Audience = "catalog-api";
});
// Azure Key Vault for secrets
builder.Configuration.AddAzureKeyVault(
new Uri("https://myvault.vault.azure.net/"),
new DefaultAzureCredential());
tools
Build Teams-native agents with the Teams SDK (formerly Teams AI Library v2) — App class, activity routing, adaptive cards, streaming, AI-generated labels, feedback, message extensions, Teams-as-MCP-server, and the bring-your-own-AI pattern with Agent Framework.
tools
Run agents on Microsoft Foundry (formerly Azure AI Foundry) Agent Service — prompt agents vs hosted agents, threads/runs and the Responses API, built-in tools (Bing grounding, code interpreter, file search, MCP, OpenAPI, A2A), connected agents, Entra agent identity, SDKs, and observability/evaluations.
tools
Build and host custom engine agents with the Microsoft 365 Agents SDK — AgentApplication, the Activity protocol, channel reach via Azure Bot Service, hosting Agent Framework or Semantic Kernel engines, and the Agents Toolkit/Playground workflow. Successor to the Bot Framework SDK.
tools
Design, govern, and extend Microsoft Copilot Studio agents — topics, generative orchestration, knowledge, tools and MCP, agent flows, autonomous triggers, publishing channels, Copilot Credits pricing, and solution-based ALM on Power Platform.