Breaking Changes
- There is now an interface
ICommand<TResult>
for commands that return values. While this should be used sparingly, there are some cases where it can be useful. ICommand
(which should be the default for implementing commands) derives from this newICommand<NoResult>
interface.- There is now a common base interface for
IQuery<TResult>
andICommand<TResult>
(and thusICommand
):IRequest<TResult
. This has the following advantages:- There is no need to distinguish between
IQueryHandler<TResult>
andICommandHandler
anymore. Simply useIRequestHandler<TResult>
. - For cross-cutting concerns, you can write decorators that target
IRequestHandler<TResult>
. Before you had to write one forIQueryHandler<TResult>
and one forICommandHandler
. - Instead of
IQueryProcessor
andICommandProcessor
, you can simply useIRequestProcessor
.ExecuteAsync
has been renamed toHandleAsync
.
- There is no need to distinguish between
- The cancellation token is now a required parameter for the
HandleAsync
method.
Show detailed upgrade instructions
-
Update all
softaware.CQS
packages to version 4.0.0 or higher -
Replace
IQueryHandler<TQuery, TResult>
withIRequestHandler<TQuery, TResult>
:- Replace in files (Use regular expression)
IQueryHandler<(.*?), (.*?)> IRequestHandler<$1, $2>
- Replace in files (Use regular expression)
-
Replace
ICommandHandler<TCommand>
withIRequestHandler<TCommand, NoResult>
- Replace
ICommandHandler<(.*?)> IRequestHandler<$1, NoResult>
- Replace
-
Replace query handler
HandleAsync
interface implementation: AddCancellationToken
- Replace
Task<(.+?)> HandleAsync\(([^,]+?) ([^,]+?)\) Task<$1> HandleAsync($2 $3, System.Threading.CancellationToken cancellationToken)
- Replace
-
Replace command handler
HandleAsync
: addNoResult
andCancellationToken
- Replace
Task HandleAsync\(([^,]+?) ([^,]+?)\) Task<NoResult> HandleAsync($1 $2, System.Threading.CancellationToken cancellationToken)
- Replace
-
Remove
HandleAsync
overloads delegating toCancellationToken
version- Replace with empty string (You might need to adjust the expressions based on your formatting):
Task<(.+?)> HandleAsync\(([^,]+?) ([^,]+?)\) =>
- Replace with empty string
public this.HandleAsync(query, default);
- Replace with empty string (You might need to adjust the expressions based on your formatting):
-
Replace
IQueryProcessor
andICommandProcessor
withIRequestProcessor
- Replace
IQueryProcessor
withIRequestProcessor
- Replace
ICommandProcessor
withIRequestProcessor
- Replace
queryProcessor
withrequestProcessor
- Replace
commandProcessor
withrequestProcessor
- Replace
requestProcessor.ExecuteAsync\(([^,]+?)\); requestProcessor.HandleAsync($1, cancellationToken);
- Remove duplicates where
IQueryProcessor
andICommandProcessor
were injected
- Replace
-
Add
return NoResult.Value
to command handlers -
Optional: Add
CancellationToken
to Controller actions-
Replace with file pattern: *Controller.cs
-
With parameters:
public async (.+)\((.+)\) public async $1($2, System.Threading.CancellationToken cancellationToken)
- Without parameters:
public async (.+)\(\) public async $1(System.Threading.CancellationToken cancellationToken)
-
-
Add missing
CancellationToken
parameters -
Decorators: Refactor command handler decorators to 2 generic type parameters
-
Replace
AddQueryHandlerDecorator
andAddCommandHandlerDecorator
withAddRequestHandlerDecorator
-
Remove
PublicQueryHandlerDecorator
andPublicCommandHandlerDecorator
if you referenced them explicitely. -
Optional: Combine duplicate decorators implementing
IQueryHandler<TResult>
andICommandHandler
into a single class implementingIRequestHandler
-
Optional: Use
ICommand<TResult>
instead ofICommand
if you used some workarounds for returning values from commands (like setting a property on the command)