この素晴らしい記事https://cuttingedge.it/blogs/steven/pivot/entry.php?id=9の影響を強く受けて、アプリケーションに CQRS アプローチを実装しました。コマンドとハンドラーのコードは、記事と同じように設定されており、その部分はうまく機能しています。コマンドの検証を処理するデコレータ クラスを実装しようとすると、私の問題が発生します。シンプルなコマンド処理インターフェースは次のようになります。
public interface ICommand
{
}
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
それから私が持っている検証デコレータのために:
public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand> where TCommand : CommandBase
{
private readonly ICommandHandler<TCommand> _decoratedCommandHandler;
private readonly ICommandValidator<TCommand> _commandValidator;
public ValidationCommandHandlerDecorator(ICommandHandler<TCommand> decoratedCommandHandler, ICommandValidator<TCommand> commandValidator)
{
_decoratedCommandHandler = decoratedCommandHandler;
_commandValidator = commandValidator;
}
public void Handle(TCommand command)
{
if (_commandValidator != null)
{
var validationResult = _commandValidator.Validate(command);
if (validationResult != null)
{
command.Success = false;
command.Errors = validationResult;
return;
}
}
_decoratedCommandHandler.Handle(command);
command.Success = true;
}
}
バリデーターを定義するためにインターフェースを使用します。
public interface ICommandValidator<TCommand>
{
IEnumerable<string> Validate(TCommand command);
}
AndCommandBase
は、コマンドの成功または失敗と、失敗した場合に発生したエラーを格納できる単純な基本クラスです。例外をスローする代わりに、この方法を使用することをお勧めします。すべてのコマンドは、この基本クラスを継承します。
public abstract class CommandBase : ICommand
{
public bool Success { get; set; }
public IEnumerable<string> Errors { get; set; }
}
そして、これはすべて、構造マップ レジストリ内の IoC コンテナーに接続されています。
public class CommandRegistry : Registry
{
public CommandRegistry()
{
Scan(s =>
{
s.AssemblyContainingType<CommandBase>();
s.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<>));
s.ConnectImplementationsToTypesClosing(typeof(ICommandValidator<>));
s.WithDefaultConventions();
For(typeof(ICommandHandler<>)).DecorateAllWith(typeof(ValidationCommandHandlerDecorator<>));
});
}
}
ここで、ICommandHandler ごとにそのデコレーターを登録するので、バリデーターを必要とせず、バリデーターを定義しないコマンドがある場合ICommandValidator<TCommand> _commandValidator
、クラスのプライベート フィールドはValidationCommandHandlerDecorator<TCommand>
もちろん存在せず、常に次の構造マップ エラーをスローします。
「デフォルトのインスタンスが登録されておらず、タイプ 'ICommandValidator' に対して自動的に決定できません ICommandValidator に指定された構成がありません」
クラス内のコンテナに依存したり、コマンドを処理ValidationCommandHandlerDecorator
するためのインターフェイスを作成したりする必要なく、存在しない場合に何らかのタイプのデフォルトバリデータを使用するように、構造マップで get の構築方法を定義する方法はありますか?IValidateableCommandHandler<TCommand>
バリデーター?
ありがとうございました。