Composition over controllers lets you add ViewModel Composition to an existing ASP.NET Core MVC application without introducing a separate composition gateway or replacing your existing controllers. When enabled, ServiceComposer injects an MVC filter that intercepts every controller invocation. If a route matches both a regular controller action and one or more composition handlers, ServiceComposer invokes the matching handlers after the controller executes and before the view is rendered — giving handlers the opportunity to enrich the view model produced by the controller. This technique is particularly useful when migrating a monolithic MVC application toward a services-based architecture incrementally, or when you want to use Razor as a templating engine while sourcing parts of the view model from independent services.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.
Enabling composition over controllers
CallEnableCompositionOverControllers() inside your AddViewModelComposition options callback:
How it works
Request arrives
An incoming HTTP request is matched by ASP.NET Core’s routing system to a controller action as normal.
Controller executes
The controller action runs and produces its view model, populating
ViewData, ViewBag, or a strongly typed model.Composition handlers run
If the resolved route also matches one or more ServiceComposer composition handlers, those handlers are invoked in parallel. Each handler can read from and write to the composed view model, adding properties sourced from downstream services.
Supported handler types
Composition over controllers supports both handler styles:ICompositionRequestsHandler
Standard composition handlers that implement the
ICompositionRequestsHandler interface, including full model binding support.Contract-less handlers
Contract-less composition request handlers, also with full model binding support. These handlers do not need to declare an explicit interface and are discovered through assembly scanning.
Route matching
ServiceComposer matches composition handlers to controller routes using the same route template system. Routes are matched case-insensitively by default. To opt out of case-insensitive matching, passuseCaseInsensitiveRouteMatching: false to EnableCompositionOverControllers:
Typical use cases
Enriching a product page from multiple services
Enriching a product page from multiple services
A
ProductController fetches core product data (name, description, price) from its own data store. A InventoryHandler and a ReviewsHandler registered with ServiceComposer add stock level and review summary to the same view model — all without modifying the controller.Incremental migration from a monolith
Incremental migration from a monolith
As functionality is extracted to separate services, composition handlers are added alongside the existing controller. The controller handles what has not yet been migrated; handlers cover what has been extracted. The Razor view does not change.
Leveraging Razor as a composition templating engine
Leveraging Razor as a composition templating engine
Teams that prefer Razor over returning raw JSON can keep their MVC views and routing intact while still sourcing parts of the view model from independent services through composition handlers.