5

次のCQRS パターンを使用してASP.NET MVCアプリケーションを作成しようとしています(これが CQRS の私の最初の味です)。コマンド側、結果がないことを理解しています。この回答で、@ Johannes Rudolphは、コマンド側で結果が必要な場合は、イベントを作成してサブスクライブし、問題を解決できると述べました。ここで、ログイン ページを作成するとします。

public class AuthController : Controller {

    private ICommandHandler<LoginCommand> _handler;

    public AuthController(ICommandHandler<LoginCommand> handler) {
        _handler = handler;
    }

    public ActionResult Login(LoginModel model) {
        if(ModelState.IsValid) {
            var cmd = new LoginCommand(model.Username, model.Password);
            _handler.Handle(cmd);
            // how to notify about login success or failed?
        }
        return View(model);
    }
}

ログイン コマンドの成功または失敗を通知するにはどうすればよいですか? LoginCommand上記の方法でイベントを作成してサブスクライブできることを知っています。しかし、私のサブスクリプションは別の方法であり、(たとえば:) 指定されたビューを返すことはできません。見る:

    public ActionResult Login(LoginModel model) {
        if(ModelState.IsValid) {
            var result = true;
            var cmd = new LoginCommand(model.Username, model.Password);
            cmd.CommandCompleted += e => { result = e; };
            _handler.Handle(cmd);
            // is this correct?
            if(result)
                // redirect to ReturnUrl
            else
                // something else
        }
        return View(model);
    }

これは本当ですか?それとももっと良い考えがありますか?それとも私が間違っていますか?

4

5 に答える 5

15

他の人が言ったように、認証プロセスは非同期コマンドや一般的な CQRS の良い例ではありません。実際には、同期要求/応答はおそらくこれに対するより良い解決策です。

非同期コマンドでこれ (または他の例) を行うには、コマンドを送信し、最終的にそのコマンドの結果を照会する必要があります。

コマンドを送信する部分は「簡単」です。コントローラーにハンドラーを挿入するのではなく、コマンドを .Send() できるようにするバスのように、そのコマンドをディスパッチできるものを挿入します。バスの実装は無関係であり、インメモリ ダイレクト ディスパッチャーからハンドラー、実際のサービス バスの実装までさまざまです。コマンドを追跡するには、コンストラクターで識別子 (Guid.NewGuid() など) を生成し、コマンドが正常にディスパッチされたことを示すサインとして返すことをお勧めします。

ここで、コマンドの実際のハンドラーから、CommandId を含む UserAuthenticated または AuthenticationFailed のいずれかのイベント、およびユーザー名、ユーザー ロールなどの関連する可能性のあるその他のデータを発行する必要があります。

asp.net アプリケーションでは、2 つのイベントのそれぞれに対してサブスクライバーが必要です。

ここでは、次の 2 つのオプションがあります。

  1. コマンドの結果を保存し、js コードがクエリを実行するのを待ちます
  2. SignalR などを使用して、クライアント コードにイベントを通知します。

ログイン情報を送信した後、クライアント コードはコマンド ID を取得します。選択したオプションに応じて、X 秒ごとに JavaScript からログイン ステータスをプールするか (オプション 1)、SignalR などのメカニズムによって通知されるのを待つか (オプション 2) を選択できます。

オプション 1 が優れている場合もあれば、オプション 2 が優れている場合もあります。十分に速く、ほとんどの場合最初の呼び出しで結果を返すプーリング間隔の値を見積もることができる場合は、オプション 1 が最適です。オプション 2 は通常、ほとんどの場合コマンドが成功したと見なされ ( order submit など)、コマンドが失敗するまれなケースのみに関心がある場合に最適です。

これは認証プロセスにとって複雑に聞こえるかもしれませんが、実際にはそうですが、一般に、成功するようにプロセスとコマンドを設計し、失敗するコマンドがほとんどない場合、これは実際には非常にうまく機能します。

その他のケースでは、2 つのオプションの組み合わせを使用する必要がある場合があります。オプション 2 を使用して、コマンドが実行されたという通知を取得してから、ビュー モデルに関連データを照会します。

コマンドを送信し、ハンドラーがメッセージを受信するのを非同期的に待機する AsyncController を含む 1 つの追加オプションがあります。これには非同期コントローラーを使用したことがないため、以下は単なる意見ですが、非同期コントローラーを使用する必要がある場合は、非同期コントローラーを使用して影響を最小限に抑えるリクエスト/レスポンス実装を使用する方がよいと思います。ウェブサーバー上。

私は、CQRS が悪用され、要求と応答を同期するように設計されたプロセス (CRUD 操作など) を強制するのを見たことがあることを警告する必要があります。その結果、イベントの実際のインフラストラクチャ処理と実際のビジネスの論理。

最後に、CQRS と SOA に関する Udi Dahan の著書、特に CQRS の誤用について警告している著書を強くお勧めします。

これが CQRS の素晴らしい世界に足を踏み入れるのに役立つことを願っています :)

(これは予想よりもはるかに長くなりました)

于 2012-09-16T01:40:50.777 に答える
9

CQRSは素晴らしい概念です。しかし、それは非常に中空です。多くのことがその殻の下に入る可能性があります。だからあなたがそこに置くものに注意してください。賢明に考え、より単純なことに戻ることを恐れないでください。

処理コマンドは、問題に応じて同期または非同期にすることができます。基本的なアーキテクチャとして、コマンドをバスに送信することはお勧めしません。ほとんどの場合、コマンドを同期して処理する方がはるかに簡単です。通常、有効なコマンドを送信します。(例:StartDateは終了日より大きくてはなりません)。次に、コマンドハンドラーに到達します。ここで、アプリケーション層のコンテキストでコマンドの有効性を確認できます。(例:存在するはずの集約ルート「House」は存在しますか?)最後に、ドメインはこのコマンドを処理し、ドメインコンテキストでその有効性をチェックします(たとえば、AR「House」は複雑な処理を実行している可能性があります。コマンドはの一部...)

このコマンド検証フローに何が必要ですか。まあそれはあなた次第です。一部の検証でユーザーへの警告が失敗したことを知りたいと思うかもしれません。または、このケースはどのクライアントでも処理されるべきではないため、例外をスローします。

非同期を使用する場合、それはUIがコマンドの実行における問題を認識しないことを意味します。動作する可能性がありますが、ほとんどの場合、クライアントはフォームに入力し、そのアクションが失敗したかどうかを今すぐ知ることができます。

私に関する限り、これらのパターン(またはあなたがそれらと呼ぶことにしたもの)を探求すればするほど、非同期は例外として扱われるべきだと思います。コマンド処理とイベントプロジェクションには、完全同期を使用するのが最適です。非同期トレイトが必要な部分を非同期にします。完全同期を開始できますが、このアプローチが適合しない場合は、すべてがバスに入れて非同期にする準備ができています。

私が思い出すように、私の2つのペニーは価値があります、私はそれで遊ぶために自分自身の道を進んでいます、

[編集]

通常、私のコマンドを実行すると、次のようになります。

public class CommandValidation 
{

    public List<ValidationMessage> Messages { get; private set; }
}

CQRSは、私が行うメソッドからvoidを返すように指示します。すべてのアグリゲートには、コマンドの実行中に入力されるコマンド検証属性があります。実行の最後に、それをクライアントに返すことができます。

[/編集]

于 2012-09-17T06:50:55.747 に答える
6

CQRSを使用してユーザー管理と認証をモデル化するのはなぜですか?これは解決された問題であり、ここで車輪の再発明を行う必要はありません。

また、認証は、複数の境界コンテキストを含む問題であり、CQRSには非常に適していません。CQRSは、アプリケーション全体ではなく、制限されたコンテキスト内で実装されることを目的としています。動作するログインメカニズムを使用して、インフラストラクチャではなくドメインにモデリング作業を集中させます。

ロブ・アッシュトンの言葉で:あなたの解決策があなたの問題よりも複雑であるならば、あなたはおそらく何か間違ったことをしているでしょう。

于 2012-09-15T16:09:59.830 に答える
5

他の場所で述べたように、CQRSは単純な認証とユーザー管理には適していない可能性があります。しかし、それを使用することを選択した場合、問題の核心は、コマンドを非同期にしようとしていることである可能性があります。一般的に、成功または失敗を返す同期コマンドから始める方が良いと思います。(注:これには、AJAXやTPLコードなど、特定のプロバイダーの「非同期」コードが含まれる場合がありますが、概念的には、呼び出し元はコマンドの実行による成功または失敗の結果を待っており、期待しています。)

本当に「少しの間」以上、たとえば数秒以上かかるコマンドを見つけた場合、実際に持っているのは、コマンドで開始される長時間実行プロセスであることに気付くかもしれません。この場合、コマンドは引き続き同期されますが、プロセス全体を完了したときに成功を返すのではなく、プロセスを開始したという成功を返します。

于 2012-09-15T19:37:54.270 に答える
3

イベント駆動型パターンは、ASP.MVCではうまく機能しません。IO完了ポートを活用するために、I / O集中型の作業を大量に行う場合は、非同期コントローラーを使用できます。

于 2012-09-15T16:07:11.020 に答える