2

私が現在構築しているシステムでは、コマンド パターンを使用して可能なすべての操作を実行します。私は CommandMessage と CommandHandler のアプローチを選択し、ロジックをデータから分離しました。これは今のところ問題なく動作しますが、検証という問題に遭遇しました。

コマンドが実行できるかどうかを実際に検証するにはどうすればよいですか?

現在、私はCanExecute(ICommandExecutionContext context)on every コマンドを持っており、実行できるかどうかを判断する責任があります。ICommandExecutionContext次に、各コマンドでAが型チェックされ、正しいコンテキスト型であるかどうかが確認され、その後、その情報によってコマンドがそのコンテキストで実行可能になるかどうかが確認されます。

ICommandService名前、コンテキスト、およびメッセージに基づいて、コマンドを検証および実行できるにすべてがラップされます。それ以外にも、コマンド実行に関するイベントを発行し、権限チェックを実行します。

この問題は、UI (ASP.NET MVC 3 アプリケーション) に起因します。各ビューに有効なコマンドのみを表示したいのですが、本当に気に入った解決策を見つけることができませんでした。現在、私のコントローラーは、次のような具体的なコンテキストが与えられた場合に、コマンドを実行できるかどうかをコマンド サービスに尋ねます。

var executionContext = new SystemCommandExecutionContext("SignInCommand", CurrentPrincial);
var canExecute = _commandService.CanExecute(executionContext);
/* Handle the result to enable or disable the action link */

具体的なドメイン オブジェクトで機能する他の種類のコマンドについては、同じコマンド サービス メソッドを使用しますが、次のようにドメイン オブジェクト ID を渡す別のコンテキストを使用します。

[HttpPost, Authorize, ValidateAntiForgeryToken /* etc. */]
public ActionResult Delete(Guid id)
{
    /* Note the additional object id in the context */
    var executionContext = new EntityCommandExecutionContext("DeletePersonCommand", CurrentPrincipal, id);
    var canExecute = _commandService.CanExecute(executionContext);

    if(canExecute)
    {
        var message = new DeletePersonCommandMessage(id);
        var isValid = _commandService.IsValid(executionContext, message);
        if(isValid)
        {
            var result = _commandService.Execute(executionContext, message);
            /* More logic here... Not very DRY :( */
        }            
    }
}

あまりDRYではありませんが、上記は今のところ大丈夫だと思います。しかし、私が達成したいのは、CanExecute の結果に基づいて、アクション リンクを無効にすることです。

どうやってやるの?

各ビューのすべてのコマンド リンクを「ハードコード」することにしたので、コマンド名などのコレクションを渡す必要はありません。そのパスは難しすぎます (誰かが賢いアイデアを持っている場合を除きます ;)

私の現在のスタックは、NHibernate、Castle Windsor、ASP.NET MVC 3、AutoMapper で構成されています。

4

1 に答える 1

1

細かい注意として、コマンドオブジェクトはシリアル化され、コマンドハンドラーによって処理される(おそらくリモートの)サービスに送信されるものであり、コマンドオブジェクト自体はそうではないため、これはGoFの意味でのコマンドパターンのインスタンスではありません実行方法を提供します。この場合のコマンド メッセージ オブジェクトの目的は必要なパラメーターを含むアクション。一部のソースでは、これをシリアライズ可能なメソッド呼び出しと呼んでいます。メッセージ オブジェクトには動作を含めず、データのみを含める必要があります。コマンド メッセージも例外ではありません。つまり、特定のコマンドを特定のコンテキストで実行できるかどうかを判断するプロセスは、別のサービスで処理する必要があります。この検証サービスの具体的な実装は、特定のコマンドを実行できるかどうかを判断する際に使用される基準によって異なります。コマンドのコンテキストとタイプに基づいて、コマンドを検証できる場合があります。

interface ICommandValidationService
{
  bool CanExecute(object context, Type commandType);
}

コンテキスト オブジェクトは、実行される実際のコマンドから独立している必要があります。代わりに、ユーザー、ユーザー権限など、よりグローバルなコンテキスト値を含める必要があります。実行するコマンドの機能は、このコンテキストを使用して決定されます。

コマンドの実行ステータスに基づくアクション リンクの無効化または非表示は、次のようなビュー モデルを使用して実装できます。

class ActionLinkViewModel
{
        public string Name { get; set; }
        public string Url { get; set; }
        public bool Enabled { get; set; }
}

によってコントローラで有効な値が割り当てられる場所ICommandValidationService。さらに、MvcSiteMapProviderを拡張して、特定のサイト マップ ノードを表示するかどうかを指定できます。

于 2011-12-29T23:55:16.213 に答える