As a continuation of the "plug-and-play architecture" series we need to prepare a small Mediator pattern-based CQRS architecture.
First we need to wrap any result that a command or a query can return
namespace PlugAndPlayExample.Services.Infrastructure
{
public class Response
{
public Response()
{
Exceptions = new List<Exception>();
}
public List<Exception> Exceptions { get; set; }
}
public class Response<T> : Response
{
public T Result { get; set; }
public static implicit operator Response<T>(T result)
{
return new Response<T> { Result = result };
}
}
}
Second, we need to create the command and query handler interfaces
namespace PlugAndPlayExample.Services.Infrastructure
{
public interface ICommand
{
}
public interface ICommandHandler<TCommand, TResult>
where TCommand: ICommand
where TResult : Response
{
TResult Handle(TCommand command);
}
public interface IQuery
{
}
public interface IQueryHandler<TQuery, TResult>
where TQuery : IQuery
where TResult : Response
{
TResult Handle(TQuery query);
}
}
We need a mediator that will dispatch these requests to their appropriate handlers
namespace PlugAndPlayExample.Services.Infrastructure
{
public class Mediator
{
private readonly IServiceProvider serviceProvider;
public Mediator(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public TResult Dispatch<TCommand, TResult>(TCommand command)
where TCommand : ICommand
where TResult : Response
{
var commandHandler = serviceProvider.GetService(typeof(ICommandHandler<TCommand, TResult>)) as ICommandHandler<TCommand, TResult>;
return commandHandler.Handle(command);
}
public TResult Get<TQuery, TResult>(TQuery query)
where TQuery : IQuery
where TResult : Response
{
var queryHandler = serviceProvider.GetService(typeof(IQueryHandler<TQuery, TResult>)) as IQueryHandler<TQuery, TResult>;
return queryHandler.Handle(query);
}
}
}
And register everything in the startup
namespace PlugAndPlayExample.Configuration
{
public static class RegisterServicesExtension
{
public static IServiceCollection RegisterServices(this IServiceCollection services)
{
services.AddSingleton<Mediator>();
var queryHandlerType = typeof(IQueryHandler<,>);
var commandHandlerType = typeof(ICommandHandler<,>);
RegisterOfType(services, queryHandlerType);
RegisterOfType(services, commandHandlerType);
return services;
}
private static void RegisterOfType(IServiceCollection services, Type type)
{
var exportedTypes = typeof(Mediator).Assembly.GetExportedTypes();
var result = exportedTypes.Where(x => x
.GetInterfaces()
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == type)
&& x.IsClass
&& !x.IsAbstract)
.ToList();
result.ForEach(handler =>
{
var handlerType = handler;
var serviceType = handler
.GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == type);
services.AddTransient(serviceType, handlerType);
});
}
}
}
namespace PlugAndPlayExample
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.RegisterServices();
}
// Configure code ...
}
}
With there few infrastructure preparations we are ready to start implementing the plug-and-play architecture.
Until next time...
Happy coding,
DotNetGuru
Congratulations @dotnetguru! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s):
Your next target is to reach 50 upvotes.
You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word
STOP
To support your work, I also upvoted your post!
Check out the last post from @hivebuzz:
Support the HiveBuzz project. Vote for our proposal!