# shiny-mediator > Generate Shiny Mediator handlers, contracts, middleware, and scaffold projects for .NET applications - Author: Allan Ritchie - Repository: shinyorg/skills - Version: 20260204235601 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/shinyorg/skills - Web: https://mule.run/skillshub/@@shinyorg/skills~shiny-mediator:20260204235601 --- --- name: shiny-mediator description: Generate Shiny Mediator handlers, contracts, middleware, and scaffold projects for .NET applications auto_invoke: true triggers: - mediator - handler - request handler - command handler - event handler - stream handler - middleware - IRequest - ICommand - IEvent - CQRS - Shiny.Mediator --- # Shiny Mediator Skill You are an expert in Shiny Mediator, a mediator pattern library for .NET applications. ## When to Use This Skill Invoke this skill when the user wants to: - Create request handlers, command handlers, event handlers, or stream handlers - Generate contracts (IRequest, ICommand, IEvent, IStreamRequest) - Add middleware (caching, resilience, validation, offline) - Scaffold ASP.NET, MAUI, or Blazor projects with Shiny Mediator - Configure Shiny Mediator in their application - Migrate from MediatR to Shiny Mediator ## Library Overview **Documentation**: https://shinylib.net/mediator Shiny Mediator is AOT & trimming friendly, using source generators for automatic DI registration. ### Core Patterns | Pattern | Contract | Handler | Usage | |---------|----------|---------|-------| | Request | `IRequest` | `IRequestHandler` | Queries returning data | | Command | `ICommand` | `ICommandHandler` | Void state changes | | Event | `IEvent` | `IEventHandler` | Pub/sub notifications | | Stream | `IStreamRequest` | `IStreamRequestHandler` | IAsyncEnumerable | ### Handler Registration Always use registration attributes: ```csharp [MediatorSingleton] // Stateless handlers [MediatorScoped] // Handlers needing per-request services (DbContext) ``` **Critical: Partial Class Requirement** When using **any middleware attribute** (`[Cache]`, `[OfflineAvailable]`, `[Resilient]`, `[MainThread]`, `[TimerRefresh]`), the handler class **must be declared as `partial`**: ```csharp [MediatorSingleton] public partial class MyHandler : IRequestHandler // partial required! { [Cache(AbsoluteExpirationSeconds = 60)] public Task Handle(...) { } } ``` This enables the source generator to create the `IHandlerAttributeMarker` implementation. Without `partial`, you'll get error `SHINY001`. ### Basic Setup **ASP.NET:** ```csharp builder.Services.AddShinyMediator(x => x .AddMediatorRegistry() ); app.MapGeneratedMediatorEndpoints(); ``` **MAUI:** ```csharp builder.AddShinyMediator(x => x .AddMediatorRegistry() .UseMaui() .AddMauiPersistentCache() .PreventEventExceptions() ); ``` **Blazor:** ```csharp builder.Services.AddShinyMediator(x => x .AddMediatorRegistry() .UseBlazor() .PreventEventExceptions() ); ``` ## Code Generation Instructions When generating Shiny Mediator code: ### 1. Contracts Always use records for immutability: ```csharp public record GetUserRequest(int UserId) : IRequest; public record CreateUserCommand(string Name, string Email) : ICommand; public record UserCreatedEvent(int UserId, string Name) : IEvent; ``` ### 2. Handlers Include all three parameters in Handle method: ```csharp [MediatorScoped] public class GetUserRequestHandler : IRequestHandler { public Task Handle( GetUserRequest request, IMediatorContext context, CancellationToken cancellationToken) { // Implementation } } ``` ### 3. Middleware Attributes Apply to handler methods as needed: - `[Cache(AbsoluteExpirationSeconds = N)]` - Cacheable queries - `[OfflineAvailable]` - Offline storage for mobile - `[Resilient("policyName")]` - Retry/timeout policies - `[MainThread]` - MAUI main thread execution - `[TimerRefresh(milliseconds)]` - Auto-refresh streams - `[Validate]` - Data annotation validation **When using ANY of these attributes, the handler class MUST be `partial`:** ```csharp [MediatorSingleton] public partial class CachedHandler : IRequestHandler { [Cache(AbsoluteExpirationSeconds = 60)] [OfflineAvailable] public Task Handle(...) { } } ``` ### 4. File Organization Place files in appropriate folders: - Contracts: `Contracts/{Name}Request.cs`, `Contracts/{Name}Command.cs` - Handlers: `Handlers/{Name}Handler.cs` - Middleware: `Middleware/{Name}Middleware.cs` ## Usage Examples **Request:** ```csharp var response = await mediator.Request(new GetUserRequest(1)); var user = response.Result; ``` **Command:** ```csharp await mediator.Send(new CreateUserCommand("John", "john@example.com")); ``` **Event:** ```csharp await mediator.Publish(new UserCreatedEvent(1, "John")); ``` **Chaining via Context:** ```csharp public async Task Handle(GetUserRequest request, IMediatorContext context, CancellationToken ct) { // Use context to chain operations (shares scope) await context.Publish(new UserAccessedEvent(request.UserId)); return new UserDto(...); } ``` ## Best Practices 1. **Use records for contracts** - Immutable, value equality 2. **One handler per file** - Focused and testable 3. **Appropriate lifetime** - Singleton for stateless, Scoped for DbContext 4. **Use `partial` with middleware attributes** - Required for `[Cache]`, `[OfflineAvailable]`, `[Resilient]`, etc. 5. **Chain via context** - Use `context.Request()` not injecting IMediator 6. **Implement IContractKey** - For custom cache/offline keys 7. **Always pass CancellationToken** - Respect cancellation ## Reference Files For detailed templates and examples, see: - `reference/templates.md` - Code generation templates - `reference/scaffolding.md` - Project structure templates - `reference/middleware.md` - Middleware configuration - `reference/api-reference.md` - Full API and NuGet packages ## Common Packages ```bash dotnet add package Shiny.Mediator # Core dotnet add package Shiny.Mediator.Maui # MAUI dotnet add package Shiny.Mediator.Blazor # Blazor dotnet add package Shiny.Mediator.AspNet # ASP.NET dotnet add package Shiny.Mediator.Resilience # Polly dotnet add package Shiny.Mediator.Caching.MicrosoftMemoryCache # Caching dotnet add package Shiny.Mediator.AppSupport # Offline ```