Let’s say we’ve encapsulated an operation our application has to perform. I tend to write little classes which express the desired behaviour or which delegate to other classes if the need arises. An example of such an operation is the class illustrated here ‘UpdateCustomerCommand’.
class UpdateCustomerCommand : IRequestHandler<UpdateCustomerRequest, UpdateCustomerResponse> { private IDbContext _context; public UpdateCustomerCommand(IDbContext context) { _context = context; } public async Task Handle(UpdateCustomerRequest request) { var customer = _context.Customers.Single(x => x.Id == request.Id); customer.Name = request.Name; customer.Address = request.Address.ToModel(); await _context.SaveChangesAsync(); return new UpdateCustomerResponse(); } } |
In any application of reasonable size you end up with a lot of these classes. You want to keep these small and easy to read and keep any infrastructure out of the way. Let’s say we want to use transactionscope to manage the transaction, perhaps we’re connecting to a bunch of databases or reading from a message queue. You don’t want to modify all these command classes to add this behaviour. One solution is to introduce a base class which has this behaviour, but we all prefer composition over inheritance right? Let’s create a simple transactionalhandler.
class TransactionalCommandHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>; where TRequest : IRequest where TResponse : IResponse { private IRequestHandler<TRequest, TResponse> _innerHandler; public TransactionalCommandHandler(IRequestHandler<TRequest, TResponse> handler) { _innerHandler = handler; } public async Task Handle(TRequest request) { using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { var response = await _innerHandler.Handle(request); scope.Complete(); return response; } } } |
This class is short and sweet and allows us to write this code once and not repeat it again and again. We just need to find a way to create the transactionalhandler and then pass in an instance of our class which does actual work as the inner handler. Enter AutoFac (or pretty much any IoC framework).
You can wire this up in AutoFac with the following code (copied and adapted from their website).
var builder = new ContainerBuilder(); builder.RegisterGeneric(typeof(IRequestHandler<,>)) .Named("handler", typeof(IRequestHandler<,>)); builder.RegisterGenericDecorator( typeof(TransactionalCommandHandler<>), typeof(IRequestHandler<>), fromKey: "handler"); var container = builder.Build(); // You can then resolve closed generics and they'll be // wrapped with your decorator. var updateCustomerHander = container.Resolve<IRequestHandler<UpdateCustomerRequest, UpdateCustomerResponse>>(); |
This approach is great if you have one cross cutting concern handler (like the transactionalhandler) and want to apply it to every implementation. There is no built in approach though if you want to apply this behaviour only to some classes. If you need more control you need to write some infrastructure code.
I introduce an attribute “NotTransactional” and apply it to some classes that I don’t want to take part in this decorator process. I then change the registration process.
private void RegisterCommandHandlers(ContainerBuilder containerBuilder) { containerBuilder.RegisterGeneric(typeof(TransactionalCommandHandler<,>)); foreach (var handlerType in typeof(CommandModule).Assembly .GetTypes().Where(i => i.IsClosedTypeOf(typeof(IRequestHandler<,>)))) { containerBuilder.RegisterType(handlerType); var registerAsInterfaceType = handlerType.GetInterfaces().Single(t => t.GetGenericTypeDefinition() == typeof(IRequestHandler<,>)); containerBuilder.Register(c => { var handler = c.Resolve(handlerType); if (!handlerType.GetCustomAttributes(typeof(NotTransactionalAttribute), true).Any()) { handler = c.Resolve(typeof(TransactionalCommandHandler<,>) .MakeGenericType(registerAsInterfaceType.GetGenericArguments()), new TypedParameter(registerAsInterfaceType, handler)); } return handler; }).As(registerAsInterfaceType); } } |
- First I register the open generic type of the transactionalhandler.
- I then loop trough every concrete class that implements the request handler interface and register them in the container.
- The classes that will request the concrete handlers will always ask for an instance of the interface IRequestHandler with concrete request and response objects. The UpdateCustomerRequest for instance. So I register that type as well.
- The registration mentioned above is done with a lambda. Whenever someone asks for an command handler we resolve the concrete implementation and if it wants to participate in a transaction we also ask for the transactional handler and pass our concrete handler to its constructor.
The same approach can be used to further decorate your commands. Adding a claims check can become pretty trivial.
First create an attribute.
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] sealed class AuthorizeUserAttribute : Attribute { public string ClaimType { get; set; } public string ClaimValue { get; set; } } |
Then apply it to the necessary classes.
[AuthorizeUser(ClaimType = AppClaims.Administrator)] class ManageCustomerCommand : IRequestHandler<ManageCustomerRequest, ManageCustomerResponse> { //omitted for brevity } |
Create a handler which does the user authorization.
class AuthorizedUserCommandHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse> where TRequest : IRequest where TResponse : IResponse { private IRequestHandler<TRequest, TResponse> _innerHandler; private string _checkExistingClaim; private string _existingClaimValue; public AuthorizedUserCommandHandler(IRequestHandler<TRequest, TResponse> handler, string checkExistingClaim, string existingClaimValue) { _innerHandler = handler; _checkExistingClaim = checkExistingClaim; _existingClaimValue = existingClaimValue; } public async Task<TResponse> Handle(TRequest request) { CheckAccess(System.Threading.Thread.CurrentPrincipal as ClaimsPrincipal); return await _innerHandler.Handle(request); } private void CheckAccess(ClaimsPrincipal principal) { //omited for brevity } } |
And finally wire everything up.
private void RegisterCommandHandlers(ContainerBuilder containerBuilder) { containerBuilder.RegisterGeneric(typeof(TransactionalCommandHandler<,>)); containerBuilder.RegisterGeneric(typeof(AuthorizedUserCommandHandler<,>)); foreach (var handlerType in typeof(CommandModule).Assembly.GetTypes().Where(i => i.IsClosedTypeOf(typeof(IRequestHandler<,>)))) { containerBuilder.RegisterType(handlerType); var registerAsInterfaceType = handlerType.GetInterfaces().Single(t => t.GetGenericTypeDefinition() == typeof(IRequestHandler<,>)); containerBuilder.Register(c => { var handler = c.Resolve(handlerType); handler = ConfigureAuthorizationHandler(c, handlerType, registerAsInterfaceType, handler); handler = ConfigureTransactionalHandler(c, handlerType, registerAsInterfaceType, handler); return handler; }).As(registerAsInterfaceType); } } private static object ConfigureTransactionalHandler(IComponentContext c, Type handlerType, Type registerAsInterfaceType, object handler) { if (!handlerType.GetCustomAttributes(typeof(NotTransactionalAttribute), true).Any()) { handler = c.Resolve(typeof(TransactionalCommandHandler<,>).MakeGenericType(registerAsInterfaceType.GetGenericArguments()), new TypedParameter(registerAsInterfaceType, handler)); } return handler; } private static object ConfigureAuthorizationHandler(IComponentContext c, Type handlerType, Type registerAsInterfaceType, object handler) { var authorizeAttr = (AuthorizeUserAttribute)handlerType.GetCustomAttributes(typeof(AuthorizeUserAttribute), true).SingleOrDefault(); if (handlerType.GetCustomAttributes(typeof(AuthorizeUserAttribute), true).Any()) { var parameters = new List<Parameter>{ new TypedParameter(registerAsInterfaceType, handler), new PositionalParameter(1, authorizeAttr.ClaimType), new PositionalParameter(2, authorizeAttr.ClaimValue) }; handler = c.Resolve(typeof(AuthorizedUserCommandHandler<,>).MakeGenericType(registerAsInterfaceType.GetGenericArguments()), parameters); } return handler; } |
And we’re done!
Thanks for this great article … I wonder how did you write your IRequestHandler interface?
Hi
Over the years I’ve done several implementations. The last one written by a friend is available here: https://github.com/Smartasses/RequestHandlers . We’ve put together several repositories, writing a post about it has been on the todo list for a while.
thanks for the answer …