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.

ICompositionEventsHandler<TEvent> lets any component in the composition pipeline react to events raised by other handlers. Whenever a handler calls ICompositionContext.RaiseEvent<TEvent>, every registered ICompositionEventsHandler<TEvent> is invoked — regardless of which route triggered the composition. This makes the generic handler appropriate for cross-cutting, route-agnostic reactions such as logging, telemetry enrichment, or shared ViewModel transformations. When you need a handler that reacts only to events raised on a specific route, use ICompositionEventsSubscriber instead. Implementations are discovered automatically by the assembly scanner and registered as transient services.

Namespace

ServiceComposer.AspNetCore

Interface definition

public interface ICompositionEventsHandler<in TEvent>
{
    Task Handle(TEvent @event, HttpRequest request);
}
CompositionEventHandler<TEvent> is the delegate type used when subscribing to events through ICompositionEventsPublisher (see ICompositionEventsSubscriber):
public delegate Task CompositionEventHandler<in TEvent>(TEvent @event, HttpRequest httpRequest);

Methods

Handle

Called by the ServiceComposer pipeline every time an event of type TEvent is raised via ICompositionContext.RaiseEvent, on any composition route.
event
TEvent
required
The raised event instance. The type parameter TEvent must exactly match the type passed to RaiseEvent<TEvent>.
request
HttpRequest
required
The current HttpRequest. Use this to access route values, query string, the shared ViewModel (GetComposedResponseModel()), or the composition context (GetCompositionContext()).
Returns Task — a task that completes when the handler has finished processing the event.

Route scope

ICompositionEventsHandler<TEvent> has no route affinity. It is invoked for every composition request on which the matching event is raised. If you need a handler that is scoped to a particular route, subscribe inline using ICompositionEventsSubscriber.
Because ICompositionEventsHandler<TEvent> is route-agnostic, avoid writing route-specific logic inside it. Use request.HttpContext.GetEndpoint() or route-value inspection if you need to branch on the matched route.

Usage example

The following event and handler illustrate a simple case where pricing information is broadcast as an event and an inventory handler reacts to it:
// The event record shared between publisher and handler
public record AnEvent(string SomeValue);
A handler publishes the event:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using ServiceComposer.AspNetCore;

public class EventPublishingHandler : ICompositionRequestsHandler
{
    [HttpGet("/route-based-handler/{some-id}")]
    public async Task Handle(HttpRequest request)
    {
        var context = request.GetCompositionContext();
        await context.RaiseEvent(new AnEvent(SomeValue: "This is the value"));
    }
}
A generic event handler reacts to AnEvent on every route:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using ServiceComposer.AspNetCore;

public class GenericEventHandler : ICompositionEventsHandler<AnEvent>
{
    public Task Handle(AnEvent @event, HttpRequest request)
    {
        var vm = request.GetComposedResponseModel();
        vm.EventValue = @event.SomeValue;
        return Task.CompletedTask;
    }
}

DI registration

The assembly scanner registers every ICompositionEventsHandler<TEvent> implementation as a transient service. Enable scanning with AddViewModelComposition:
builder.Services.AddViewModelComposition();
Explicit registration is also available:
builder.Services.AddViewModelComposition(options =>
{
    options.RegisterCompositionHandler<GenericEventHandler>();
});
Each ICompositionEventsHandler<TEvent> implementation is transient. A new instance is created for every composition request, which means state cannot be shared across requests via instance fields.

Build docs developers (and LLMs) love