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.

ViewModelCompositionOptions is the central configuration object for the ServiceComposer pipeline. An instance is created internally by AddViewModelComposition and passed to the optional Action<ViewModelCompositionOptions> callback before the DI container is finalized. Through its properties and methods you can control which assemblies are scanned, how responses are serialized, whether write endpoints are active, and how individual composition handlers are registered and configured in the DI container.

Properties

AssemblyScanner

public AssemblyScanner AssemblyScanner { get; }
Exposes the AssemblyScanner instance used to discover composition handlers at startup. Use this to disable automatic scanning or add inclusion/exclusion filters. See the Assembly Scanner reference for full details.
builder.Services.AddViewModelComposition(options =>
{
    // Exclude third-party assemblies from scanning
    options.AssemblyScanner.AddAssemblyFilter(path =>
        path.Contains("ThirdParty")
            ? AssemblyScanner.FilterResults.Exclude
            : AssemblyScanner.FilterResults.Include);
});

Services

public IServiceCollection Services { get; }
The application IServiceCollection. Use this inside AddTypesRegistrationHandler or AddServicesConfigurationHandler callbacks to register additional services alongside discovered types.

Configuration

public IConfiguration Configuration { get; }
The IConfiguration root passed to AddViewModelComposition. Accessing this property throws ArgumentException when no IConfiguration was supplied to AddViewModelComposition. Pass the configuration instance explicitly to avoid this:
builder.Services.AddViewModelComposition(
    options => { /* use options.Configuration safely here */ },
    builder.Configuration);

ResponseSerialization

public ResponseSerializationOptions ResponseSerialization { get; }
Controls JSON serialization behavior for composed responses — response casing, output formatter delegation, and custom JsonSerializerOptions. See the Response Serialization Options reference for full details.

Methods

EnableCompositionOverControllers

public void EnableCompositionOverControllers(bool useCaseInsensitiveRouteMatching = true)
Activates the composition-over-controllers feature. When enabled, composition handlers whose route templates match an existing MVC controller action are not mapped as standalone endpoints; instead, they are invoked as action filters on the controller’s pipeline, allowing them to augment the controller’s ViewModel without replacing the controller.
useCaseInsensitiveRouteMatching
bool
When true (default), route template comparisons between handlers and controller actions ignore letter case. Set to false to enforce case-sensitive matching.
builder.Services.AddViewModelComposition(options =>
{
    options.EnableCompositionOverControllers();
});

DisableWriteSupport

public void DisableWriteSupport()
Prevents MapCompositionHandlers from registering POST, PUT, PATCH, and DELETE endpoints. Use this in read-only gateway scenarios to reduce the exposed surface area.
builder.Services.AddViewModelComposition(options =>
{
    options.DisableWriteSupport();
});

RegisterCompositionHandler<T>

public void RegisterCompositionHandler<T>()
Manually registers a single composition handler type, bypassing assembly scanning. T must implement ICompositionRequestsHandler, ICompositionEventsSubscriber, ICompositionEventsHandler<TEvent>, or IEndpointScopedViewModelFactory.
builder.Services.AddViewModelComposition(options =>
{
    options.AssemblyScanner.Disable();
    options.RegisterCompositionHandler<ProductDetailsHandler>();
    options.RegisterCompositionHandler<InventoryHandler>();
});

RegisterGlobalViewModelFactory<T>

public void RegisterGlobalViewModelFactory<T>() where T : IViewModelFactory
Registers a global IViewModelFactory that creates the ViewModel object for every composed request. Only one global factory can be registered; registering a second throws NotSupportedException.
builder.Services.AddViewModelComposition(options =>
{
    options.RegisterGlobalViewModelFactory<ExpandoViewModelFactory>();
});

RegisterEndpointScopedViewModelFactory<T>

public void RegisterEndpointScopedViewModelFactory<T>()
    where T : IEndpointScopedViewModelFactory
Registers a ViewModel factory that is scoped to a specific endpoint, identified by the route template on T’s CreateViewModel method. Multiple endpoint-scoped factories can coexist, each handling a different route.
builder.Services.AddViewModelComposition(options =>
{
    options.RegisterEndpointScopedViewModelFactory<ProductPageViewModelFactory>();
});

AddServicesConfigurationHandler

public void AddServicesConfigurationHandler(
    Type serviceType,
    Action<Type, IServiceCollection> configurationHandler)
Overrides how a specific handler type is registered in the DI container. When the scanner (or a manual RegisterCompositionHandler call) encounters serviceType, it invokes configurationHandler instead of the default services.AddTransient(type). Use this to register a handler as a singleton, keyed service, or with a factory delegate.
serviceType
Type
required
The composition handler type whose registration should be customized. Throws NotSupportedException if a handler is already registered for this type.
configurationHandler
Action<Type, IServiceCollection>
required
Delegate receiving the concrete type and the service collection. Perform the custom registration inside this delegate.
builder.Services.AddViewModelComposition(options =>
{
    options.AddServicesConfigurationHandler(
        typeof(CachedProductHandler),
        (type, services) => services.AddSingleton(type));
});

AddTypesRegistrationHandler

public void AddTypesRegistrationHandler(
    Func<Type, bool> typesFilter,
    Action<IEnumerable<Type>> registrationHandler)
Registers a custom type-scanning hook. After the assembly scanner finishes collecting all types, each registered handler is called with the subset of types for which typesFilter returns true. Use this to auto-register types that are not first-class ServiceComposer concepts (e.g., custom validators or enrichers).
typesFilter
Func<Type, bool>
required
Predicate that receives a candidate type and returns true if the registrationHandler should receive it.
registrationHandler
Action<IEnumerable<Type>>
required
Callback that receives all matching types and is responsible for registering them in Services.
builder.Services.AddViewModelComposition(options =>
{
    options.AddTypesRegistrationHandler(
        typesFilter: t => typeof(IMyEnricher).IsAssignableFrom(t) && !t.IsAbstract,
        registrationHandler: types =>
        {
            foreach (var type in types)
                options.Services.AddTransient(typeof(IMyEnricher), type);
        });
});

Build docs developers (and LLMs) love