Automatic CQRS handler registration in ASP.NET Core with reflection
Image from Unsplash

Automatic CQRS handler registration in ASP.NET Core with reflection

Registering all query and command handlers in your CQRS implementation in ASP.NET Core

Command Query Responsibility Segregation (CQRS) pattern is one of my favorite way of handling the Web API requests for a simple reason that is clearly separates reading and writing. Quite often at some stage of the project you will hit the performance bottlenecks which are most probably cause by the way you are reading ow writing your data.

CQRS splits reading and writing so that you can independently use different persistence framework for reading and writing. For example you might want to stick to Entity Framework for reading, but you want to write large amount of data with stored procedures and BulkCopy can play major role. On the other hand you might want to write asynchronously as in most cases you do not need to retrieve any data after writing data.

There are more benefits of using CQRS pattern in handling requests from Web API but there are as well some down sides of using this pattern which at some point make your code longer and a bit harder to understand. The more lines you have, there are more places to miss something and potentially cause a bug.

One of these things that I found quite annoying is registering command and query handlers in ASP.NET Core dependency injection. To demonstrate what I am pointing at I will start with a dummy CQRS implementation. Let start with interfaces for our commands, queries and their respective handlers

    public interface ICommand
    {
    }
	
	public interface IQuery<TResult>
    {
    }
	
	public interface ICommandHandler<TCommand> TCommand:ICommand
    {
		Task HandleAsync(TModel model);
    }
	
	public interface IQueryHandler<TQuery,TResult> where TQuery:IQuery<TResult>
    {
        Task<TResult> HandleAsync(TQuery query);
    }
    

You can see that our command and query handlers are using generic type so that we can implement different classes for different types of queries and commands.

Let's write few dummy implementations for commands and queries and eventually register them with ASP.NET core dependency injection IOC container. We'll start with commands and command handlers first.

Commands and command handlers

We already have our interfaces for commands so let's have some simple implementation of a command that for example create a product. Well have to define our command first

    public class CreateProductCommand:ICommand
    {
        public Guid Id { get; }
        public String Name { get;  }
        public String Description { get; set; }

        [JsonConstructor]
        public CreateProductCommand(Guid id, String name, String description)
        {
            this.Id = id;
            this.Name = name;
            this.Description = description;
        }
    }
    

Since ICommand interface does not have any method or property definition, we are not forced to implement anything. ICommand interface is used as a marker only, so that we can filterĀ generic types declared for ICommandHandler interface. Command handler for this command would look like following

    public class CreateProductHandler : ICommandHandler<CreateProductCommand>
    {
        public async Task HandleAsync(CreateProductCommand command)
        {
			//TODO: Implement command handling logic
            throw new NotImplementedException();
        }
    }
    

Another command we'll might need is delete product command

    public class DeleteProductCommand:ICommand
    {
        public Guid Id { get; }

        [JsonConstructor]
        public DeleteProductCommand(Guid id)
        {
            this.Id = id;
        }
    }
	
	public class DeleteProductHandler : ICommandHandler<DeleteProductCommand>
    {
        public Task HandleAsync(DeleteProductCommand model)
        {
            throw new NotImplementedException();
        }
    }

    

Our sample dummy commands and handlers are done. Let's declare some queries and query handlers for retrieving the data.

Queries and query handlers

Unlike command, queries do not have to be immutable, so we're not going to restraint setters in our queries. Queries are closer to DTOs than commands as they allow modification of the properties, but should not be confused with DTOs. We will use DTOs (Data Transfer Objects) for returning result of the queries.

We'll first have our DTO defined so that we can have our output types of our queries. I picked product DTO to represent data from the query to be in the same subject as our command shown previously

    public class ProductView
    {
        public Guid Id { get; set; }
        public String Name { get; set; }
        public String Description { get; set; }
    }
    

Now let's have our query which will take id and name property into consideration

    public class ProductBrowseQuery:IQuery<IEnumerable<ProductView>>
    {
        public Guid Id { get; set; }
        public String Name { get; set; }
        public int PageIndex { get; set; }
        public int PageSize { get; set; }
    }
    

And now let's have a handler for this query which will handle it

    public class BrowseProductHandler : IQueryHandler<ProductBrowseQuery, IEnumerable<ProductView>>
    {
        public async Task<IEnumerable<ProductView>> HandleAsync(ProductBrowseQuery query)
        {
			//TODO: Hanlde query and return result
			throw new NotImplementedException();
        }
    }
    

We also might want to have a query for getting single product from the database, so let's write classes for that one as well and it's handler

    public class ProductGetQuery:IQuery<ProductView>
    {
        public Guid Id { get; set; }
    }

    public class GetProductHandler : IQueryHandler<ProductGetQuery, ProductView>
    {
        public async Task<ProductView> HandleAsync(ProductGetQuery query)
        {
			//TODO: Handle query and return result
			throw new NotImplementedException();
        }
    }
    

Depenedency injection

We have our commands and handler, but in order to use them in our controllers, we'll have to use dependency injection to register the, so that they can be injected in ASP.NET Core controller constructors. Here is our ConfigureServices method in Startup.cs class

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<ICommandHandler<CreateProductCommand>, CreateProductHandler>();
            services.AddScoped<ICommandHandler<DeleteProductCommand>, DeleteProductHandler>();
            services.AddScoped<IQueryHandler<ProductBrowseQuery, IEnumerable<ProductView>>, BrowseProductHandler>();
            services.AddScoped<IQueryHandler<ProductGetQuery, ProductView>, GetProductHandler>();
		}
    

We have single line per command/query and their handlers and for now, just for a simple scenario we already have four lines. This block will only grow for a real life scenario projects, so it would be nice if we could do this with less lines, because with approach like this, it is easy to miss a dependency to be injected and therefore increase debugging time. Same time, once we add a new query/command we need to register it in IOC container. Same situation when we are using multiple AutoMapper profiles, it is easy to miss one and spend time to debug. Would not it be nice if application would do it for us automatically?

This is the reason we are here, we want to have all our command and query handlers registered without adding much of additional code. Since we have same common interface for handlers, we can use reflection to discover all of them and then register them. Let's first see how to discover the handlers in our assembly using reflection

        public void ConfigureServices(IServiceCollection services)
        {
			var commandHandlers = typeof(Startup).Assembly.GetTypes()
                .Where(t => t.GetInterfaces().Any(i a=> i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICommandHandler<>))
            );

            foreach (var handler in commandHandlers)
            {
                services.AddScoped(handler.GetInterfaces().First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICommandHandler<>)), handler);
            }
		}
    

This will retrieve all command handler implementations from the assembly where they are declared. I am referencing Startup class as for this simple example I have everything inĀ one single project, but this would ideally be in application services layer extension methods class.

For queries we would have pretty much the same code, but we'll target different interface for class implementation discovery

        public void ConfigureServices(IServiceCollection services)
        {
			var queryHandlers = typeof(Startup).Assembly.GetTypes()
                .Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IQueryHandler<,>))
            );

            foreach (var handler in queryHandlers)
            {
                services.AddScoped(handler.GetInterfaces().First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IQueryHandler<,>)), handler);
            }
		}
    

Now you can obviously see that two code snippets above are pretty much the same, so let's refactor them. since both of these methods will be to register services, we can make them a single static extension method for easier usage

        private static void AddCommandQueryHandlers(this IServiceCollection services, Type handlerInterface)
        {
            var handlers = typeof(ServiceExtensions).Assembly.GetTypes()
                .Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == handlerInterface)
            );

            foreach (var handler in handlers)
            {
                services.AddScoped(handler.GetInterfaces().First(i => i.IsGenericType && i.GetGenericTypeDefinition() == handlerInterface), handler);
            }
        }
    

All we have to do now is to call this extension method from our ConfigureServices with a different interface type

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCommandQueryHandlers(typeof(ICommandHandler<>));
            services.AddCommandQueryHandlers(typeof(IQueryHandler<,>));
		}
    

Instead if four lines to declare our command and query handlers, we are down to two lines. This might not seem like a big deal on this sample project, but in real life project, you might and up with dozen of commands and queries and the whole beauty of this approach it that you will still have these two lines of code which will inject all command and query handlers for you.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article