Skip to content

Quick Start

Quick Start

  1. Install

  2. First, let’s create our request & event handlers

    using Shiny.Mediator;
    public record TestRequest(string AnyArgs, int YouWant) : IRequest;
    public record TestEvent(MyObject AnyArgs) : IEvent;
    // and for request/response requests - we'll come back to this
    public record TestResponseRequest : IRequest<TestResponse> {}
    public record TestResponse {}
  3. Next - let’s wire up a RequestHandler. You can have ONLY 1 request handler per request type. This is where you would do the main business logic or data requests.

    Let’s create our RequestHandler

    using Shiny.Mediator;
    // NOTE: Request handlers are registered as singletons
    public class TestRequestHandler : IRequestHandler<TestRequest>
    {
    // you can do all dependency injection here
    public async Task Handle(TestRequest request, CancellationToken ct)
    {
    // do something async here
    }
    }
    public class TestResponseRequestHandler : IRequestHandler<TestResponseRequest, TestResponse>
    {
    public async Task<TestResponse> Handle(TestResponseRequest request, CancellationToken ct)
    {
    var response = await GetResponseThing(ct);
    return response;
    }
    }
    public class TestEventHandler : IEventHandler<TestEvent>
    {
    // Dependency injection works here
    public async Task Handle(TestEvent @event, CancellationToken ct)
    {
    // Do something async here
    }
    }
  4. Now, let’s register all of our stuff with our .NET MAUI MauiProgram.cs

    public static class MauiProgram
    {
    public static MauiApp CreateMauiApp()
    {
    var builder = MauiApp
    .CreateBuilder()
    .UseMauiApp<App>();
    builder.Services.AddShinyMediator();
    // AddSingletonAsImplementedInterfaces/AddScopedAsImplementedInterfaces are extension methods we've added to IServiceCollection
    // that allow you to register all interfaces that a class implements
    builder.Services.AddSingletonAsImplementedInterfaces<TestEventHandler>();
    builder.Services.AddSingletonAsImplementedInterfaces<TestRequestHandler>();
    builder.Services.AddSingltonAsImplementedInterfaces<TestResponseRequestHandler>();
    // OR
    // if you're using our attribute for source generation - simply add [RegisterHandler], [RegisterMiddleware] to your types
    // NOTE: that for each assembly you have source generation enabled, you will need to call AddDiscoveredMediatorHandlersFrom{AssemblyName}
    builder.Services.AddDiscoveredMediatorHandlersFromMaui_App();
    }
    }
  5. And finally, let’s use the mediator and call our new models - any model model/viewmodel/etc participating in dependency injection can now inject the mediator

    public class MyViewModel(Shiny.Mediator.IMediator mediator)
    {
    public async Task Execute()
    {
    await mediator.Send(new TestRequest()); // this will execute TestRequestHandler
    var response = await mediator.Request(new TestResponseRequest()); // this will execute TestResponseRequestHandler and return a value
    // this will publish to any service registered that implement IEventHandler<TestEvent>
    // there are additional args here to allow you to execute values in sequentially or wait for all events to complete
    await mediator.Publish(new TestEvent());
    }
    }

What about my ViewModels?

For .NET MAUI, your viewmodels have the ability to participate in the event publishing chain without being part of dependency injection

With this setup, you don’t need to worry about deallocating any events, unsubscribing from some service, or hooking to anything.

Lastly, if your page/viewmodel is navigated away from (popped), it will no longer participate in the event broadcast

  1. Install

  2. Now…let’s go back to our MauiProgram.cs and alter the AddShinyMediator

    builder.Services.AddShinyMediator(cfg => cfg.UseMaui());
  3. Now your viewmodel (or page) can simply implement the IEventHandler interface to participate

    public class MyViewModel : BaseViewModel,
    Shiny.Mediator.IEventHandler<TestEvent1>,
    Shiny.Mediator.IEventHandler<TestEvent2>
    {
    public async Task Handle(TestEvent @event, CancellationToken ct)
    {
    }
    public async Task Handle(TestEvent2 @event, CancellationToken ct)
    {
    }
    }

Source Generated Registration

When you install Shiny.Mediator, we include a source generator that will create a set of attributes that you can mark your request handlers, event handlers, and middleware with. This will generate the registration code for you.

Those attributes are

  • RegisterHandlerAttribute - This is used on implementations of any of your handlers
  • RegisterMiddlewareAttribute - This is used on implementations of any of your middleware

From there, any of those marked classes will be added to a source generated extension that you can use for you IServiceCollection registration

Example: MauiProgram.cs (ie. Project/Assembly with Shiny.Mediator installed named: Maui.App)

builder.Services.AddDiscoveredMediatorHandlersFromMaui_App();

The convention we use is AddDiscoveredMediatorHandlersFrom{AssemblyName} - This prevents naming collisions during the registration process.

All source generated registrations will register your implementations as singleton against ALL interfaces they implement.