-
Notifications
You must be signed in to change notification settings - Fork 9
Configuration
The main objective of this library was to provide a simple mediator implementation that should be easy to use and configure. Using any dependency injection framework shouldn't be a problem because you don't even need decorators to add transversal behavior.
Because your business code probably only needs to know the mediator interfaces or helper abstract classes (IMediator, ICommand, ICommandHandler<TCommand>, and so on), you only need to reference the package SimpleSoft.Mediator.Abstractions for those projects. To use the mediator, then you must add a reference to SimpleSoft.Mediator in the project where you configure the dependency injection container and everything should work.
Using the provided implementations, the services can be configured into the container in the following way:
| Service | Implementation | Lifetime |
|---|---|---|
IMediator |
Mediator |
Singleton |
IMediatorFactory |
DelegateMediatorFactory |
Singleton |
DelegateMediatorFactory.Service |
DelegateMediatorFactory.Service |
Singleton |
DelegateMediatorFactory.ServiceCollection |
DelegateMediatorFactory.ServiceCollection |
Singleton |
Every time the mediator needs a given handler or collection of handlers, it gets it from the IMediatorFactory and doesn't cache the instances. If you are using the delegate factory, they will be resolved using the handler interfaces (eg. IEventHandler<SomeEvent>, IQueryHandler<SomeQuery>). This decision was made so you can use lifetime that bests suits your needs. Typically it should range from Scoped or Transient. Examples:
-
ConfigurationsQueryHandler - assuming your configurations can be cached in memory, this could be a
Singleton; -
CreateUserCommandHandler - assuming you want to create the user in a database, to make it easier to manage the connection, this may be
ScopedorTransient;
Just like the handlers, the middleware collection is also resolved every time they are needed from the IMediatorFactory.If you are using the delegate factory, they will be resolved using the middleware interfaces (ICommandMiddleware, IQueryMiddleware or IEventMiddleware). Here are some examples:
-
LoggingMiddleware - assuming it only does is logging commands, events and queries, this could be a
Singleton; -
TransactionCommandMiddleware - assuming you want a transaction per request, this is probably a
Scopedinstance;
Here are some example configurations using known dependency containers.
Assuming the usage of DelegateMediatorFactory, here is a configuration example. A custom IMediatorFactory could also be used that would directly resolve from the service provider, instead of using the delegates.
private static IServiceCollection ConfigureMediator(this IServiceCollection services)
{
services
.AddSingleton<DelegateMediatorFactory.Service>(s => s.GetService)
.AddSingleton<DelegateMediatorFactory.ServiceCollection>(s => s.GetServices)
.AddSingleton<IMediatorFactory, DelegateMediatorFactory>()
.AddSingleton<IMediator, Mediator>();
// register middleware by their base interfaces
services
.AddSingleton<LoggingMiddleware>()
.AddSingleton<ICommandMiddleware>(s => s.GetRequiredService<LoggingMiddleware>())
.AddSingleton<IEventMiddleware>(s => s.GetRequiredService<LoggingMiddleware>())
.AddSingleton<IQueryMiddleware>(s => s.GetRequiredService<LoggingMiddleware>())
.AddScoped<ICommandMiddleware, TransactionCommandMiddleware>();
// register handlers by their base interface
services
.AddSingleton<IQueryHandler<ConfigurationsQuery, Configurations>, ConfigurationsQueryHandler>()
.AddScoped<ICommandHandler<CreateUserCommand>, CreateUserCommandHandler>();
return services;
}Remarks: to make it easier to register handlers and middleware, I recommend the usage of the library Scrutor, which allows for assembly scan and even supports decorators.
Because this is the new Microsoft facade for dependency injection libraries that are used by ASP.NET Core applications, the NuGet SimpleSoft.Mediator.Microsoft.Extensions.DependencyInjection is available to make it easier to configure the mediator into the IServiceCollection instance. It offers some extension methods and a specialized MicrosoftMediatorFactory that can be used. Example configuration, equivalent to the previous example:
private static IServiceCollection ConfigureMediator(this IServiceCollection services)
{
services.AddMediator(options => {
// here you can change the factory functions or lifetimes to use
});
// register middleware by their base interfaces
services
.AddMediatorMiddleware<LoggingMiddleware>(ServiceLifetime.Singleton)
.AddMediatorMiddlewareForCommands<TransactionCommandMiddleware>(); // defaults to scoped
// register handlers by their base interface
services
.AddMediatorHandlerForQuery<ConfigurationsQuery, Configurations, ConfigurationsQueryHandler>(ServiceLifetime.Singleton)
.AddMediatorHandlerForCommand<CreateUserCommand, CreateUserCommandHandler>(); // defaults to scoped
return services;
}