クエリサービスを使用してデータを取得し、コマンドサービスを使用してコマンドを送信するASP.NET MVCアプリケーションがあります。私の質問は、コマンド部分についてです。
リクエストが受信されると、コマンドサービスはコマンドディスパッチャーを使用して、指定されたコマンドハンドラーにコマンドをルーティングします。このコマンドハンドラーは最初にコマンドを検証し、すべてが許容できる場合はコマンドを実行します。
具体例:AddCommentToArticleCommandHandlerは、ArticleId、CommentText、EmailAddressを持つAddCommentToArticleCommandを受け取ります。
最初; -記事が存在するかどうかを確認します-記事が閉じていないかどうかを確認します-コメントテキストが20〜500文字で入力されているかどうかを確認します-電子メールアドレスが入力されており、有効な形式かどうかを確認します.
この検証をどこに置くのか疑問に思っていますか?
1 /コマンドハンドラ自体。ただし、他のコマンドハンドラで再利用することはできません。
2 /ドメインエンティティ内。しかし、ドメインエンティティはリポジトリやサービスを認識していないため、必要な検証を実行できません(記事が存在するかどうかを確認できません)。ただし、一方で、エンティティにロジックが含まれていない場合は、DDDの原則に従わない単純なデータコンテナになります。
3 /コマンドハンドラーはバリデーターを使用するため、検証を他のコマンドハンドラーで再利用できます。
4 /その他のメカニズム?
この特定の例の一連の責任と、その中で役割を果たすオブジェクト(エンティティ、リポジトリなど)を探しています。
コマンドハンドラーからリポジトリまで、これをどのように実装するかについてのアイデアはありますか?
この場合、2つのタイプの検証を分離する必要があると思います。 ドメイン検証およびアプリケーション検証。
アプリケーションの検証は、コマンドのプロパティ 'text'が20〜200文字であることを検証するときに行うものです。したがって、これをGUIと、POST後にサーバーでも実行されるview-model-validatorで検証します。同じことが電子メールにも当てはまります(ところで、 `32.d +" Hello World .42 "@mindomän.local"などの電子メールはRFCによれば有効であることを理解してください)。
次に、別の検証があります。記事が存在することを確認してください-GUIから実際にコメントを添付するコマンドが送信された場合、記事が存在しない理由を自問する必要があります。 GUIは最終的に整合性がとれており、データストアから物理的に削除できるアーティクルという集約ルートがありますか?その場合、コマンドハンドラーは集約ルートのロードに失敗するため、コマンドをエラーキューに移動するだけです。
上記の場合、有害なメッセージを処理するインフラストラクチャがあります。たとえば、メッセージを1〜5回再試行してから、メッセージをポイションキューに移動します。そこで、メッセージのコレクションを手動で検査し、関連するメッセージを再ディスパッチできます。監視するのは良いことです。
さて、ここで議論しました:
アプリケーションの検証
集約ルート+ポイズンキューがありません
ドメインと同期していないコマンドについてはどうですか?おそらく、ドメインロジックに、記事への5つのコメントの後には400文字未満のコメントしか許可されないというルールがあるかもしれませんが、1人の男が5番目のコメントで遅すぎて6番目になりました-GUIはそれをキャッチしませんでした彼がコマンドを送信した時点でドメインと一致していませんでした。この場合、ドメインロジックの一部として「検証エラー」が発生し、対応するエラーイベントを返します。
イベントは、メッセージブローカーまたはカスタムディスパッチャーへのメッセージの形式にすることができます。アプリケーションがモノリシックである場合、Webサーバーは、前述の成功イベントと失敗イベントの両方を同期的にリッスンし、適切なビュー/部分を表示できます。
多くのタイプのコマンドの失敗を意味するカスタムイベントがよくあります。Webサーバーの観点からサブスクライブするのはこのイベントです。
現在取り組んでいるシステムでは、MassTransit + RabbitMQメッセージバス+ブローカーを介してコマンド/イベントでリクエスト/レスポンスを実行しており、InvalidStateTransitionError
という名前のこの特定のドメイン(ワークフローの一部をモデル化)にイベントがあります。状態グラフのエッジに沿って移動しようとするほとんどのコマンドは、このイベントを発生させる可能性があります。今回のケースでは、最終的に一貫性のあるパラダイムに基づいてGUIをモデル化しているため、ユーザーを「コマンドが受け入れられた」ページに送信し、その後、イベントサブスクリプションを通じてWebサーバーのビューを受動的に更新します。また、集約ルートでイベントソーシングも行っていることにも注意してください(sagasの場合も同様です)。
つまり、あなたが話している検証の多くは、実際にはアプリケーションタイプの検証であり、実際のドメインロジックではありません。ドメインは単純ですがDDDを実行している場合、単純なドメインモデルを使用しても問題はありません。ただし、ドメインのモデリングを続けると、ドメインが最初に判明したほど単純ではない場合があることに気づくでしょう。多くの場合、集約ルート/エンティティは、コマンドによって引き起こされたメソッド呼び出しを受け入れるだけで、検証を実行することなく、その状態の一部を変更する可能性があります。あなたがコントロールします。
Norwegian Developer Conference 2011 からのDDDに関する2つのプレゼンテーション、および Öredev201 でのGregのプレゼンテーションを視聴することをお勧めします。
乾杯、ヘンケ
編集:WaybackMachineリンク: http://devlicio.us/blogs/billy_mccafferty/archive/2009/02/17/a-response-to-validation-in-a-ddd-world.aspx
正解はありません。
検証がどこにあるべきかについて答えようとすると、2つの明確なプロジェクトシナリオが思い浮かびます。 1つ目は、ビュー層とドメイン層の間で情報を転送するためにDTO層が使用される場合です。たとえば、ドメインレイヤーにCustomerオブジェクトがあり、カスタマー情報をマップする別のレイヤーに関連付けられたCustomer DTOがある場合、カスタマー情報をユーザーに提示するためのビューを提供します。
2番目のシナリオは、ドメインレイヤー内のエンティティがビューと直接共有され、ユーザーにデータを提示するプロジェクトです。たとえば、個別のDTOレイヤーを維持し、ドメインオブジェクトをビューに与えるDTOにマッピングする代わりに、ビューに直接Customerオブジェクトを与えることができます。したがって、個別に管理されているDTOを介してCustomerの名前を表示する代わりに、ビューは単にCustomerオブジェクト自体に情報を要求します。