Skip to content

Latest commit

 

History

History
95 lines (74 loc) · 4.26 KB

events.md

File metadata and controls

95 lines (74 loc) · 4.26 KB

Events

When handling composition requests, there are scenarios in which request handlers need to offload some of the composition concerns to other handlers.

Note

Composing lists of composed elements or master-details type of outputs is one scenario where events are needed. For an introduction to composing lists and the related challenges, read the Into the darkness of ViewModels Lists Composition blog post.

Events are regular .NET types, classes, or records, like in the following example:

public record AnEvent(string SomeValue);

snippet source | anchor

Events are synchronous, and in memory, they don't need to be serializable.

Publishing events

Publishing an event is done through the composition context, as demonstrated by the following snippet:

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"));
    }
}

snippet source | anchor

Subscribing to events

ServiceComposer offers two APIs to subscribe to events.

Generic event handlers

Subscribing to events can be done by creating a class that implements the ICompositionEventsHandler<TEvent> interface:

public class GenericEventHandler : ICompositionEventsHandler<AnEvent>
{
    public Task Handle(AnEvent @event, HttpRequest request)
    {
        // handle the event
        return Task.CompletedTask;
    }
}

snippet source | anchor

ICompositionEventsHandler<TEvent> instances are discovered at assembly scanning time and registered in the DI container as transient components. Hence, event handlers support dependency injection.

Route-based subscribers

A more granular way to subscribe to events is by creating a class that implements the ICompositionEventsSubscriber:

public class RouteBasedEventHandler : ICompositionEventsSubscriber
{
    [HttpGet("/route-based-handler/{some-id}")]
    public void Subscribe(ICompositionEventsPublisher publisher)
    {
        publisher.Subscribe<AnEvent>((@event, request) =>
        {
            // handle the event
            return Task.CompletedTask;
        });
    }
}

snippet source | anchor

Note

The class must also be decorated with one or more route attributes. Otherwise, it'll never be invoked.

At runtime, when an HTTP request that matches the route pattern is handled, all matching subscribers will be invoked, giving them the opportunity to subscribe. The registered event handler will be invoked when a publisher publishes the subscribed event.

When using which

Generic event handlers, classes implementing ICompositionEventsHandler<TEvent>, are invoked every time an event they subscribe to is published, regardless of the currently handled route. If the same event is used in multiple scenarios, e.g., when doing an HTTP GET and a POST, and different behaviors are required, it's better to implement a route-based event handler that can easily, through the route attribute, differentiate to which type of request it reacts to.