- 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>andICommandHandleranymore. 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
IQueryProcessorandICommandProcessor, you can simply useIRequestProcessor.ExecuteAsynchas been renamed toHandleAsync.
- There is no need to distinguish between
- The cancellation token is now a required parameter for the
HandleAsyncmethod.
Show detailed upgrade instructions
-
Update all
softaware.CQSpackages 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
HandleAsyncinterface implementation: AddCancellationToken- Replace
Task<(.+?)> HandleAsync\(([^,]+?) ([^,]+?)\) Task<$1> HandleAsync($2 $3, System.Threading.CancellationToken cancellationToken)
- Replace
-
Replace command handler
HandleAsync: addNoResultandCancellationToken- Replace
Task HandleAsync\(([^,]+?) ([^,]+?)\) Task<NoResult> HandleAsync($1 $2, System.Threading.CancellationToken cancellationToken)
- Replace
-
Remove
HandleAsyncoverloads delegating toCancellationTokenversion- 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
IQueryProcessorandICommandProcessorwithIRequestProcessor- Replace
IQueryProcessorwithIRequestProcessor - Replace
ICommandProcessorwithIRequestProcessor - Replace
queryProcessorwithrequestProcessor - Replace
commandProcessorwithrequestProcessor - Replace
requestProcessor.ExecuteAsync\(([^,]+?)\); requestProcessor.HandleAsync($1, cancellationToken);
- Remove duplicates where
IQueryProcessorandICommandProcessorwere injected
- Replace
-
Add
return NoResult.Valueto command handlers -
Optional: Add
CancellationTokento 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
CancellationTokenparameters -
Decorators: Refactor command handler decorators to 2 generic type parameters
-
Replace
AddQueryHandlerDecoratorandAddCommandHandlerDecoratorwithAddRequestHandlerDecorator -
Remove
PublicQueryHandlerDecoratorandPublicCommandHandlerDecoratorif you referenced them explicitely. -
Optional: Combine duplicate decorators implementing
IQueryHandler<TResult>andICommandHandlerinto a single class implementingIRequestHandler -
Optional: Use
ICommand<TResult>instead ofICommandif you used some workarounds for returning values from commands (like setting a property on the command)
- Fix: Update
Scrutorto version 4.0.0 to support generic type constraints on decorators. (See also Scrutor issue #159)
- Fix: Register
DynamicQueryProcessorandDynamicCommandProcessoras transient instead of singleton so that scoped dependencies can be resolved.
- Support list of validators for given
TCommandandTQuery.
- Fix: Add dependency to
softaware.Cqs.Decorators.FluentValidationversion1.1.0to use new constructor parameters.
- Add
SoftawareCqsTypesBuilderclass.
- Fix: Add dependency to
softaware.Cqsversion2.1.0to have access to theSoftawareCqsTypesBuilderclass.
- Fix: Add dependency to
softaware.Cqs.DependencyInjectionversion1.0.1to have access to theSoftawareCqsTypesBuilderclass.
- Initial release: Builder extensions
- Initial release: Builder extensions
- Initial release: Builder extensions
- Initial release: Builder extensions
- Initial release: add support for
Microsoft.Extensions.DependencyInjectionDI framework.
- Extension methods for the Simple Injector
Containerclass to support fluent CQS builder syntax.
- Update Dependency to FluentValidation to use Version 10 or higher.
-
Major update of Simple Injector to version 5.
-
If you are using the NuGet package
softaware.Cqs.Decorators.UsageAware, the typesUsageAwareCommandLogger<>andUsageAwareQueryLogger<,>must now be registered in the container, since these classes won't be resolved automatically in the new Simple Injector version any more by default. For more information, see https://simpleinjector.org/ructd.this.container.Register(typeof(UsageAwareCommandLogger<>)); this.container.Register(typeof(UsageAwareQueryLogger<,>));
- Added new NuGet package
softaware.Cqs.Decorators.FluentValidationwhich supports command and query decorators for using FluentValidation.
- The
CancellationTokenwill now correctly be passed to the inner handlers when using the Transaction-, Validation- or UsageAware decorators.
- XML documentation for all public types has been added.
- All packages now target
netstandard2.1. - It is now needed that the two decorators
softaware.Cqs.SimpleInjector.PublicCommandHandlerDecoratorandsoftaware.Cqs.SimpleInjector.PublicQueryHandlerDecoratorare registered as last decorator in the chain when usingsoftaware.Cqs.SimpleInjector.DynamicCommandProcessorandsoftaware.Cqs.SimpleInjector.DynamicQueryProcessor. This is needed so that the dynamic processors can call the correct overload of theHandleAsyncmethod. Secondly this is needed when trying to call aninternaldecorator or aninternalhandler. If these two decorators are not registered, an exception will be thrown when trying to callExecuteAsyncon either theICommandProcessororIQueryProcessor. See here for more details. - The package
softaware.Cqs.EntityFrameworkis deprecated and no longer supported. It has been removed from this release. - The constructor parameter of
softaware.Cqs.Decorators.Validation.DataAnnotationsValidatorhas been removed as it's not needed.
-
It is now possible to pass a
CancellationTokenwhen executing command handlers and query handlers. So it is now easily possible to cancel the execution of commands and queries. To use the cancellable version, implement theHandleAsync(command, token)default interface method and delegate to this implementation in theHandleAsync(command)method:internal class LongRunningCommandHandler : ICommandHandler<LongRunningCommand> { public Task HandleAsync(LongRunningCommand command) { return this.HandleAsync(command, default); } public async Task HandleAsync(LongRunningCommand command, CancellationToken cancellationToken) { await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken); } }
Note: For this to work, all existing Decorators must override the
HandleAsync(command, token)method and pass thecancellationTokento the inner handlers. -
Unit tests have been added.
- All packages now target
netstandard2.1. - It is now needed that the two decorators
softaware.Cqs.SimpleInjector.PublicCommandHandlerDecoratorandsoftaware.Cqs.SimpleInjector.PublicQueryHandlerDecoratorare registered as last decorator in the chain when usingsoftaware.Cqs.SimpleInjector.DynamicCommandProcessorandsoftaware.Cqs.SimpleInjector.DynamicQueryProcessor. This is needed so that the dynamic processors can call the correct overload of theHandleAsyncmethod. Secondly this is needed when trying to call aninternaldecorator or aninternalhandler. If these two decorators are not registered, an exception will be thrown when trying to callExecuteAsyncon either theICommandProcessororIQueryProcessor. See here for more details. - The package
softaware.Cqs.EntityFrameworkis deprecated and no longer supported. It has been removed from this release.
-
It is now possible to pass a
CancellationTokenwhen executing command handlers and query handlers. So it is now easily possible to cancel the execution of commands and queries. To use the cancellable version, implement theHandleAsync(command, token)default interface method and delegate to this implementation in theHandleAsync(command)method:internal class LongRunningCommandHandler : ICommandHandler<LongRunningCommand> { public Task HandleAsync(LongRunningCommand command) { return this.HandleAsync(command, default); } public async Task HandleAsync(LongRunningCommand command, CancellationToken cancellationToken) { await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken); } }
- SourceLink support
- Deprecation of
softaware.Cqs.EntityFramework. This package will be removed in the next major release.
- NuGet package metadata update
- Initial Release