By default, ServiceComposer uses a C#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.
dynamic object instance as the shared view model. Handlers call request.GetComposedResponseModel() and assign properties directly to it, without compile-time type checking. This is convenient for getting started, but as your composition layer grows you may want a strongly typed view model that provides IDE autocompletion, refactoring support, and static analysis. ViewModel factories let you replace the dynamic object with any POCO class you choose.
The default dynamic view model
Without a factory,GetComposedResponseModel() returns a dynamic backed by an ExpandoObject. Any property you assign to it is serialized into the JSON response:
Defining a strongly typed view model
View models are plain POCO classes. The only requirement is that they are serializable:Endpoint-scoped view model factories
AnIEndpointScopedViewModelFactory creates the view model for a specific route. Decorate the factory class with the same [Http*] routing attribute used by your handlers:
IEndpointScopedViewModelFactory implementations automatically and registers them in DI at startup — no manual registration is required. Each route that needs a strongly typed view model needs its own factory.
The factory receives the
HttpContext and the ICompositionContext, so it can pre-populate properties from route values, as shown above with ProductId. Handlers then only need to fill in the properties they own.Using the typed view model in handlers
Once a factory is in place, switch handlers to the generic overloadGetComposedResponseModel<T>():
- Sales Handler
- Marketing Handler
Global view model factories
A global factory (IViewModelFactory) is used for every route that does not have a matching endpoint-scoped factory. It is useful when all routes share a common base view model, or when a single factory can determine the correct type from the request:
IViewModelFactory per application is supported — attempting to register a second one throws a NotSupportedException.
Manual factory registration
Assembly scanning handles registration automatically, but you can also register factories explicitly throughViewModelCompositionOptions when you need more control (for example, when disabling the scanner or configuring from tests):
RegisterEndpointScopedViewModelFactory<T>() accepts any T that implements IEndpointScopedViewModelFactory. RegisterGlobalViewModelFactory<T>() accepts any T that implements IViewModelFactory — but not IEndpointScopedViewModelFactory; endpoint-scoped factories must always be registered through their own method.
Interface contracts
Resolution order
ServiceComposer resolves the view model factory for each request using the following priority:Endpoint-scoped factory
If an
IEndpointScopedViewModelFactory is registered whose route attribute matches the current request, it is used to create the view model.Global factory
If no endpoint-scoped factory matches and an
IViewModelFactory is registered, it is used as the fallback for all unmatched routes.