- 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)
- Fix: Update
Scrutor
to version 4.0.0 to support generic type constraints on decorators. (See also Scrutor issue #159)
- Fix: Register
DynamicQueryProcessor
andDynamicCommandProcessor
as transient instead of singleton so that scoped dependencies can be resolved.
- Support list of validators for given
TCommand
andTQuery
.
- Fix: Add dependency to
softaware.Cqs.Decorators.FluentValidation
version1.1.0
to use new constructor parameters.
- Add
SoftawareCqsTypesBuilder
class.
- Fix: Add dependency to
softaware.Cqs
version2.1.0
to have access to theSoftawareCqsTypesBuilder
class.
- Fix: Add dependency to
softaware.Cqs.DependencyInjection
version1.0.1
to have access to theSoftawareCqsTypesBuilder
class.
- Initial release: Builder extensions
- Initial release: Builder extensions
- Initial release: Builder extensions
- Initial release: Builder extensions
- Initial release: add support for
Microsoft.Extensions.DependencyInjection
DI framework.
- Extension methods for the Simple Injector
Container
class 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.FluentValidation
which supports command and query decorators for using FluentValidation.
- The
CancellationToken
will 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.PublicCommandHandlerDecorator
andsoftaware.Cqs.SimpleInjector.PublicQueryHandlerDecorator
are registered as last decorator in the chain when usingsoftaware.Cqs.SimpleInjector.DynamicCommandProcessor
andsoftaware.Cqs.SimpleInjector.DynamicQueryProcessor
. This is needed so that the dynamic processors can call the correct overload of theHandleAsync
method. Secondly this is needed when trying to call aninternal
decorator or aninternal
handler. If these two decorators are not registered, an exception will be thrown when trying to callExecuteAsync
on either theICommandProcessor
orIQueryProcessor
. See here for more details. - The package
softaware.Cqs.EntityFramework
is deprecated and no longer supported. It has been removed from this release. - The constructor parameter of
softaware.Cqs.Decorators.Validation.DataAnnotationsValidator
has been removed as it's not needed.
-
It is now possible to pass a
CancellationToken
when 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 thecancellationToken
to 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.PublicCommandHandlerDecorator
andsoftaware.Cqs.SimpleInjector.PublicQueryHandlerDecorator
are registered as last decorator in the chain when usingsoftaware.Cqs.SimpleInjector.DynamicCommandProcessor
andsoftaware.Cqs.SimpleInjector.DynamicQueryProcessor
. This is needed so that the dynamic processors can call the correct overload of theHandleAsync
method. Secondly this is needed when trying to call aninternal
decorator or aninternal
handler. If these two decorators are not registered, an exception will be thrown when trying to callExecuteAsync
on either theICommandProcessor
orIQueryProcessor
. See here for more details. - The package
softaware.Cqs.EntityFramework
is deprecated and no longer supported. It has been removed from this release.
-
It is now possible to pass a
CancellationToken
when 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