Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ServiceComposer/ServiceComposer.AspNetCore/llms.txt

Use this file to discover all available pages before exploring further.

In systems built from autonomous services, each service owns its own slice of data — and that’s a feature, not a bug. But the moment a UI or API client needs to display a product page, a dashboard, or any view that draws from several services at once, that clean ownership starts to feel like an obstacle. ServiceComposer is an ASP.NET Core library that resolves this tension through a pattern called ViewModel Composition: each service contributes its own fragment of the response through an independent handler, and the gateway assembles them into one coherent reply.

The Problem: Data Ownership vs. Display Needs

Consider a typical e-commerce product page. The Sales service owns the price and availability. The Marketing service owns the product name and description. Neither service should know what the other holds — that separation is what lets them be deployed, scaled, and evolved independently. Yet the client needs all of that data in a single response. This is not a niche problem. Every sufficiently decomposed system faces it, and the way you solve it determines whether your services remain truly autonomous or gradually collapse into a distributed monolith.

Why Naive Approaches Fall Short

The temptation is to reach for the most convenient solution. But the common shortcuts each carry hidden costs:

Client-Side Merging

The UI calls each service separately and stitches results together. This couples the client to service internals, leaks service boundaries, and causes a flood of round-trips — especially painful on mobile or low-bandwidth connections.

Shared Database

Services read from a common schema. This destroys the data ownership that makes services autonomous. A schema change in one service can silently break another, and deployment independence disappears.

Dedicated Aggregation Service

A new service is built purely to call others and combine their data. This service must be updated every time any contributing service changes its API, creating a tight coupling in a different place — and a single point of failure.
Each approach either couples services to one another or shifts the coupling somewhere it is harder to see and manage. The result is what the industry calls a distributed monolith: the operational complexity of microservices with none of the autonomy benefits.

ViewModel Composition: Assembly at the Gateway Layer

ViewModel Composition moves the aggregation concern to the API gateway, where it belongs. The key insight is that each service is the best author of its own slice of the response. Instead of one service (or the client) knowing about all the others, each service ships a small composition handler — a class that lives in its own assembly, targets a specific route, and writes only the properties that service owns. The gateway discovers all registered handlers for an incoming request, runs them in parallel, and serializes the merged result. No handler knows about the others. No handler owns the route exclusively. This preserves all of the properties that make services valuable:
  • Data ownership — each service writes only its own fields
  • Independent deployability — adding a new service means adding a new handler; no existing handler changes
  • Single client request — the caller sees one endpoint and one response

ServiceComposer: The ASP.NET Core Implementation

ServiceComposer is the production-ready ASP.NET Core implementation of the ViewModel Composition pattern. It integrates with the standard ASP.NET Core endpoint routing pipeline, requires minimal configuration, and automatically discovers composition handlers by scanning loaded assemblies at startup. A handler is nothing more than a class that implements ICompositionRequestsHandler and carries an [Http*] routing attribute:
public interface ICompositionRequestsHandler
{
    Task Handle(HttpRequest request);
}
The Handle method receives the full HttpRequest, so handlers have access to route values, query strings, headers, and the DI container — everything needed to fetch data from a downstream service or database and project it onto the shared view model via request.GetComposedResponseModel().

Supported Platforms

Starting with version 5.0, ServiceComposer targets .NET 10 only. Both existing ASP.NET Core web applications and new gateway projects are supported. ServiceComposer can also be hosted in a .NET console application.
ServiceComposer leverages ASP.NET Core Endpoints support to plug into the request handling pipeline, which means it also automatically inherits support for authentication and authorization metadata, endpoint filters, and MVC output formatters.
Only the last two major releases of ServiceComposer are supported, and only the latest minor of every supported major. Bug fixes are backported only to the most recent minor of every affected supported major version.

Philosophy: Getting Service Boundaries Right

Service boundaries are the most critical design decision in a service-oriented system. When boundaries are wrong, the usual reaction is to compensate with rich events or shared caches (like Elasticsearch) to satisfy UI needs — but this causes data ownership to erode across the entire system. Every change starts to impact everything else. ViewModel Composition techniques are designed to prevent this. They bring the separation of concerns established at the back end forward to the front end, without forcing any service to know what another owns.
Service boundary identification is challenging; it requires extensive business domain knowledge and confidence in high-level design techniques. Technical challenges, such as the lack of technical solutions to problems foreseen while defining service boundaries, might drive the solution design in the wrong direction.
For a deeper exploration of the philosophy and the full pattern catalogue, see the ViewModel Composition series and the technical introduction on YouTube.

Ready to Build?

Quickstart: Your First Composition in 5 Minutes

Install ServiceComposer, write your first two composition handlers, wire them into an ASP.NET Core gateway, and see a merged JSON response — step by step.

Build docs developers (and LLMs) love