1

CommandModelsを検証して実行する抽象化されたCommandProcessorレイヤーを使用して、リポジトリとUnitOfWorkパターン、およびドメイン駆動設計を実装するN層MVC4アプリケーションを構築しています。

私は今WorkflowFoundationを学び始めており、ユーザー登録を処理するワークフロープロジェクトを追加しました。ワークフローの最後にすべてが完了した場合、ワークフローはApproveMembershipCodeActivityを実行します。

public sealed class ApproveMembership : CodeActivity
{
    [RequiredArgument]
    public InArgument<string> UserEmail { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        IDatabaseFactory databaseFactory = new DatabaseFactory();
        IUnitOfWork unitOfWork = new UnitOfWork(databaseFactory);
        IUserRepository userRepository = new UserRepository(databaseFactory);

        string userEmail = UserEmail.Get(context);

        User user = userRepository.Get(u => u.Email == userEmail);

        if (user != null)
        {
            user.Activated = true;
            userRepository.Update(user);
            unitOfWork.Commit();
        }
    }
}

同様のRemoveMembershipアクティビティもあり、ユーザーが検証しない場合、一定時間後にユーザーを削除します。

私の質問は、これをワークフロー内で処理することは理にかなっていますか?または、ワークフローで依存性注入を使用して、作成する必要のある2つの新しいほぼ同一のコマンドモデルと、それらの検証および送信ハンドラーの処理を処理するCommandBusを取得するためのより良いアプローチですか?これは私のMVCAccountControllerで行われる方法です。

    public class DeleteUserCommand : ICommand
    {
        public int UserId { get; set; }
    }
    public class ApproveUserCommand : ICommand
    {
        public int UserId { get; set; }
    }

    public sealed class RemoveMembership : CodeActivity
    {
        public InArgument<string> UserEmail { get; set; }

        private readonly ICommandBus commandBus;
        private readonly IUserRepository userRepository;

        public RemoveMembership(ICommandBus commandBus, IUserRepository userRepository)
        {
            this.commandBus = commandBus;
            this.userRepository = userRepository;
        }

        protected override void Execute(CodeActivityContext context)
        {
            string userEmail = UserEmail.Get(context);
            User user = userRepository.Get(u => u.Email == userEmail);

            if (user != null)
            {
                var command = new DeleteUserCommand
                {
                    UserId = user.UserId
                };

                IEnumerable<ValidationResult> errors = commandBus.Validate(command);
                if (!errors.Any())
                {
                    commandBus.Submit(command);
                }
            }
        }
    }

明らかにそれはもっと多くのコードですが、それは良いデザインですか?

これを書いて自分の質問に答えたような気がして、答えはイエスだと思います。しかし、それでも専門家の意見を聞きたいです。

4

1 に答える 1

2

私の質問は、これをワークフロー内で処理することは理にかなっていますか?

CodeActivity内にあるコードをアプリケーションサービスにカプセル化し、そのアプリケーションサービスをワークフローで参照します。

class UserApplicationService
{
    public void ApproveMembership(string userEmail) 
    { 
        var user = userRepository.Get(u => u.Email == userEmail);
        if (user != null)
        {
            user.Activated = true;
            userRepository.Update(user);
        }
    }
}


public sealed class ApproveMembership : CodeActivity
{
    [RequiredArgument]
    public InArgument<string> UserEmail { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        var userEmail = UserEmail.Get(context);
        this.userService.ApproveMembership(userEmail);
    }
}

この動機は、WWFがアーキテクチャのインフラストラクチャコンポーネントであり、インフラストラクチャをドメインロジックから切り離すのに役立つことです。WWFは、同じアプリケーションサービスを参照するNServiceBusのようなものに置き換えることができます。これはYAGNIの場合だと言う人もいますが、ドメインコードのインフラストラクチャを分離することは、コードの品質とドメインについて推論する能力の両方の点で非常に有益だと思います。

Commitまた、アプリケーションサービスが明示的に呼び出す必要がないように、作業単位コードを可能な限りインフラストラクチャにプッシュすることをお勧めします。

または、ワークフローで依存性注入を使用して、作成する必要のある2つの新しいほぼ同一のコマンドモデルと、それらの検証および送信ハンドラーの処理を処理するCommandBusを取得するためのより良いアプローチですか?

これは私の提案に沿っているように見えますが、コードサンプルに基づいて、さらに一歩進んでCodeActivity内のロジックのほとんどをアプリケーションサービスに抽出するか、できるようにアプリケーションを構造化することをお勧めします。リポジトリへのアクセスを必要とせずにコマンドをディスパッチします。

于 2012-12-18T20:15:25.730 に答える