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.

ICompositionContext is the central coordination object for a single composition request. It exposes the ability to raise events — which fan out to all interested subscribers and handlers — and a stable RequestId that identifies the in-flight composition. It is available to every handler, subscriber, and filter through the request.GetCompositionContext() extension method. An experimental API (GetArguments) is also available on ICompositionContext. It allows handlers and subscribers to inspect the model-binding arguments that were bound to them by the framework, enabling richer runtime introspection without relying on reflection.

Namespace

ServiceComposer.AspNetCore

Interface definition

#nullable enable
public interface ICompositionContext
{
    string RequestId { get; }

    Task RaiseEvent<TEvent>(TEvent @event);

    [Experimental("SC0001")]
    IList<ModelBindingArgument>? GetArguments(ICompositionRequestsHandler owner);

    [Experimental("SC0001")]
    IList<ModelBindingArgument>? GetArguments(ICompositionEventsSubscriber owner);

    [Experimental("SC0001")]
    IList<ModelBindingArgument>? GetArguments<T>(ICompositionEventsHandler<T> owner);
}

Obtaining the context

Call the GetCompositionContext() extension method on the current HttpRequest:
var context = request.GetCompositionContext();
This method is defined on HttpRequestExtensions in the ServiceComposer.AspNetCore namespace.

Properties

RequestId

RequestId
string
A unique identifier assigned to the current composition request. The same value is emitted in the composed-request-id response header, making it easy to correlate log entries across multiple handlers that run in parallel.

Methods

RaiseEvent<TEvent>

Raises an event and delivers it to every ICompositionEventsHandler<TEvent> and every ICompositionEventsSubscriber that has subscribed to TEvent on the current route.
event
TEvent
required
The event instance to raise. The runtime type must match the type argument used in ICompositionEventsHandler<TEvent> and publisher.Subscribe<TEvent>.
Returns Task — completes when all event handlers have finished processing.

GetArguments (ICompositionRequestsHandler) — Experimental SC0001

This method is decorated with [Experimental("SC0001")]. You must suppress diagnostic SC0001 to call it without a compiler warning. See the model-binding documentation for details.
Returns the list of model-binding arguments that were bound to the specified ICompositionRequestsHandler for the current request.
owner
ICompositionRequestsHandler
required
The handler instance whose bound arguments to retrieve. Pass this when called from inside the handler.
Returns IList<ModelBindingArgument>? — the list of bound arguments, or null if no arguments were bound.

GetArguments (ICompositionEventsSubscriber) — Experimental SC0001

Returns the model-binding arguments bound to the specified ICompositionEventsSubscriber.
owner
ICompositionEventsSubscriber
required
The subscriber instance whose bound arguments to retrieve.
Returns IList<ModelBindingArgument>?

GetArguments<T> (ICompositionEventsHandler) — Experimental SC0001

Returns the model-binding arguments bound to the specified ICompositionEventsHandler<T>.
owner
ICompositionEventsHandler<T>
required
The event handler instance whose bound arguments to retrieve.
Returns IList<ModelBindingArgument>?

ModelBindingArgument

ModelBindingArgument carries metadata about a single bound argument.
public class ModelBindingArgument
{
    public ModelBindingArgument(string name, object? value, BindingSource bindingSource) { }

    public string Name { get; }
    public object? Value { get; }
    public BindingSource BindingSource { get; }
}
Name
string
The name of the bound argument, matching the parameter or attribute name declared on the handler.
Value
object?
The bound value. May be null if the source did not provide a value.
BindingSource
BindingSource
The ASP.NET Core BindingSource that provided the value (e.g. BindingSource.Route, BindingSource.Query, BindingSource.Body).

ModelBindingArgumentExtensions

A set of extension methods on IList<ModelBindingArgument>? that simplify typed argument retrieval:
public static class ModelBindingArgumentExtensions
{
    // Returns the single argument's value cast to TArgument
    public static TArgument? Argument<TArgument>(
        this IList<ModelBindingArgument>? arguments);

    // Returns the argument matching the given name
    public static TArgument? Argument<TArgument>(
        this IList<ModelBindingArgument>? arguments, string name);

    // Returns the argument matching the given BindingSource
    public static TArgument? Argument<TArgument>(
        this IList<ModelBindingArgument>? arguments, BindingSource bindingSource);

    // Returns the argument matching both name and BindingSource
    public static TArgument? Argument<TArgument>(
        this IList<ModelBindingArgument>? arguments, string name, BindingSource bindingSource);
}
All overloads return default(TArgument) when no matching argument exists.

Usage example

The example below shows a handler that raises an event and then uses the experimental GetArguments API to access a route-bound product ID.
using System.Threading.Tasks;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using ServiceComposer.AspNetCore;

public class ProductHandler : ICompositionRequestsHandler
{
    [HttpGet("/product/{id}")]
    [BindFromRoute<string>("id")]
    [SuppressMessage("Usage", "SC0001")]
    public async Task Handle(HttpRequest request)
    {
        var context = request.GetCompositionContext();

        // Access the unique request identifier
        var requestId = context.RequestId;

        // Retrieve route-bound arguments (experimental)
        var args = context.GetArguments(this);
        var productId = args.Argument<string>("id");

        var vm = request.GetComposedResponseModel();
        vm.ProductId = productId;
        vm.RequestId = requestId;

        // Raise an event for other handlers/subscribers to react to
        await context.RaiseEvent(new ProductRequested(productId));
    }
}

public record ProductRequested(string ProductId);
A subscriber on the same route reacts to ProductRequested:
public class InventorySubscriber : ICompositionEventsSubscriber
{
    [HttpGet("/product/{id}")]
    public void Subscribe(ICompositionEventsPublisher publisher)
    {
        publisher.Subscribe<ProductRequested>((@event, request) =>
        {
            var vm = request.GetComposedResponseModel();
            vm.StockLevel = 42; // fetch from inventory service
            return Task.CompletedTask;
        });
    }
}

Build docs developers (and LLMs) love