The scope of this article is to showcase the possibilities of the Command pattern applied for web APIs, in order to abstract infrastructural aspects of the hosting platform while allowing the development team to focus on extending the API with new functionality without the need to carry platform specifics during the development of the API. In order to make sure the implementation is platform agnostic, both Azure Functions and .Net Minimal API are used to host the same API code, with minimal differences in terms of setup.
The complete source code is available in my git repository with examples for Azure functions and Minimal Api.
In one of my earlier articles I already discussed the importance and perspectives of applying the Command pattern as an abstraction model for business flows and how it allows extending the system with cross cutting concerts. This article focuses more on implementation details rather than the high level architectural perspective.
Objectives
Let’s define some clear and perhaps ambitious objectives for this proof of concept:
1. Be able to build extensible APIs without repetitive infrastructure components just by defining commands and command handlers.
2. The same solution should work in different hosting platforms without changing the business domain.
3. The API must expose an Open API definition for every endpoint (swagger) in order to make the API discoverabe.
4. Both azure and local environments should use the same infrastructure implementations.
5. Implementation for cross cutting concerns such as logging, exception handling authorization should be realized without mixing with the business domain.
The above objectives are key aspects to design a flexible and scalable solution which can be understood without deep understanding of the underlying infrastructure, where application infrastructure and business domain is highly decoupled allowing them to evolve at a different pace during the lifecycle of the project.
Now let’s take the steps needed to achieve the above goals, starting with the first one.
Command and command handlers
Commands, besides representing a domain model, also contain in their definition an authorization resource in the form of a string which is understood by the authorization service. Commands always have only one handler and one or more command validators. Special commands are queries which don’t require validation, as they don’t apply any state change (Http Get).
Below is an example of commands and command handlers:
Our goal is to build APIs of any dimension just defining the command and their command handlers and expose them as Http endpoints without further configuration or additional code.
Towards our goals, the next step is to implement the command dispatcher.
Command dispatcher
The command dispatcher is responsible to resolve and execute command validators and command handlers for a given command or query, in my case using the service locator pattern.
Below is a fragment of the command dispatcher’s implementation, complete code is in the CommandDispatcher class.
Above at line 13 the DispatchCommand method validates the command by using data annotation validator or ICommandValidators<> if any defined. In case the validation passes, the dispatcher resolves the command handler (line 18) for the given command and returns its execution result (line 20).
As the next step we have to make sure whenever a command handler or validator is implemented it is registered in the IOC container, so the dispatcher can resolve those.
Convention based registration of handlers
In order to automatically register all command handlers and validators, the following code fragment has to be executed in the application startup, both for Azure Functions and Minimal API, in order to register the handlers in the ServiceCollection.
For more details, check my article about convention based dependency resolution.
Above the lines 3-6 are the conventions that register command handlers, query handlers and command validators in the IOC container. You can find complete code in following links for Azure Functions and Minimal API.
Now that we have a command dispatcher, we have to make sure all the requests that are made to our API are mapped to a command/query and are calling the command dispatcher.
Mapping requests to commands
In order to map commands and queries to Http requests, we need to implement a conventions which maps Http verbs and request urls to commands and queries. In my case the are the following:
- Query names are mapped to endpoint names except the Command/Query suffixes.
- Queries are always mapping to http Get.
- Commands are mapped to HttpVerbs based on the prefix of their names, driven by the domain language used in the project. I use a dictionary for this mapping for simplicity:
Now that we have a conceptual definition of our request mapping let’s see the implementation.
In order to improve the performance of the request mapping the solution builds a collection of request map objects in a singleton service called CommandToApiMapper used to identify commands and queries based on the Url of the Http request and the Http verb, but it will also serve the generation of Open API json using Swagger in a later stage.
Here is the code snippet for creating the request map:
The GetHandlerRequestMap method is executed for all the command and query handlers present in the referenced assemblies, and creates a HandlerRequestMap object for each handler with the details needed for invoking the Command Dispatcher and generating the Open API document.
In order to make all our command/query handlers to respond to requests we have to invoke the command dispatcher from our function (Azure Function) or route map (Minimal Api)
Invoking the command dispatcher
We already have A command dispatcher and conventions to map requests to command, we only have to bridge the gap in between with a generic implementation called CommandDispatcherInvoker
With all the above in place we only need to define a function or a route (minimal ApI) to handle all the requests to our API:
Let’s see our first query handler in action

For many use cases this might be enough, but in order for the API to be discoverable an Open API definition should also be generated which then can be used to import in Azure API Management, Postman or generate client code.
Last but not least, we should have some cross cutting concerns implemented to showcase how the Command pattern combined with the Decorator pattern can decouple the application infrastructure and business domain. In the second part of this sequel I’ll address the remaining objectives.