Source Generation
We have an assortment of source generation features to help reduce boilerplate, make it safe for AOT/trimming scenarios, and ultimately improve performance.
- Handler & Middleware Registration
These two attributes [MediatorSingletonAttribute] and [MediatorScopedAttribute] can be applied to your handler and middleware implementations to have source generators create the necessary registration code for you.
They actually do the leg work for #2 below as well, so if you use these attributes you do not need to also use the executer source generators. This saves you having to manually register each handler.
[MediatorSingleton]public class MyHandler : IRequestHandler<MyRequest, MyResponse>{
}
// in your startupservices.AddShinyMediator(x => x.AddMediatorRegistry()); // this method is generated in your assemblyTODO: configuration options
- Executers (Request & Stream Request)
This is actually to get around a bit of a generics issue within .NET. Our v4 and earlier implementations used reflection to get around the fact that you cannot create a generic type at runtime without knowing the type parameters at compile time. This is solved in v5+ with source generation.
This issue is much easier solved (and performant) when you know the types at compile time. So we provide source generators to create executers for your requests and stream requests.
All source generated registrations will register your implementations as singleton against ALL interfaces they implement.
- JSON Converter
With v5 - we created our own JSON serialization source generator because you cannot currently chain source generators (mediator > system.text.json). This source generator will create high performance JSON converters for your request and response types while also helping our HTTP client be fully AOT compliant.
You can use this for ANY of your types. If you manually create your contracts and you use a storage mechanic like Offline mode, we recommend you decorate your types with [SourceGenerateJsonConverter] to get the benefits of source generated serialization.
[SourceGenerateJsonConverter]public class MyRequest{ public string Name { get; set; }}
[SourceGenerateJsonConverter]public class MyResponse{ public string Message { get; set; }}
4. Contract Keys
Contract key source generation is more of a convenience feature. Creating request keys on your contracts can be tedious. You also had to check for things like nulls, etc.
_BEFORE_
```csharppublic class MyRequest : IRequest<Something>, IContractKey{ public string Name { get; set;} public DateTimeOffset? Date { get; set; }
public string GetKey() { var key = String.Empty; if (String.IsNulthis.Name) $"{Name}_{Date?.ToString("yyyyMMddHHmmss")}";
}}AFTER
[ContractKey("MyRequest_{Name}_{Date:yyyyMMddHHmmss}")]public class MyRequest : IRequest<Something>{ public string Name { get; set;} public DateTimeOffset? Date { get; set; }}- HTTP Contracts
There are tons of libraries out there to do this already. Refitter is a great option. However, if you want to keep everything within Shiny Mediator because it allows our users to bring all of the middleware goodness to their HTTP calls.
<ItemGroup> <MediatorHttp Include="" />
<MediatorHttp Include="" /></ItemGroup>- Attribute Usage
This may sound weird, but attributes on methods required a level of deep reflection to get at. With our war on reflection for the benefit of AOT and trimming, we created source generators to help with this.
public class MyHandler : IRequestHandler<MyRequest, MyResponse>{ [MyCustomAttribute] public Task<MyResponse> Handle(MyRequest request, CancellationToken ct) { ... }}
### Implementing Your Own Handler Attributes
Best of all, our source generator can work with your own mediator attributes. Simply inherit `Shiny.Mediator.MediatorMiddlewareAttribute` and we'll pick it off the handlers for you.
TODO
7. ASP.NET Endpoint Creation
TODO