Question

I'm building an N-Tier MVC 4 Application that implements the Repository and UnitOfWork patterns as well as Domain Driven Design using an abstracted CommandProcessor layer that validates and executes my CommandModels.

I'm beginning to learn Workflow Foundation now and have added a workflow project that handles user registration. At the end of the workflow if everything went through, the workflow will execute the ApproveMembership CodeActivity:

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();
        }
    }
}

There is also a similar RemoveMembership activity that deletes the user after a certain time if he never validates.

My question is, does it make sense to handle this right inside my workflow? Or is the better approach to use Dependency Injection in the workflow to get a CommandBus that will handle processing 2 new, almost identical command models that I will have to create, along with Validation and Submission handlers for them? This is how it's done in my MVC AccountController.

    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);
                }
            }
        }
    }

Obviously it's a lot more code but is it good design?

I feel like I answered me own question writing this and I'm thinking the answer is YES. But would still like to hear a professional opinion.

Was it helpful?

Solution

My question is, does it make sense to handle this right inside my workflow?

I would encapsulate the code that you have inside the CodeActivity into an application service and have the workflow reference that application service:

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);
    }
}

The motivation for this is that WWF is an infrastructural component in your architecture and it serves well to decouple infrastructure from domain logic. WWF could be replaced by something like NServiceBus in which you'd reference the same application service. Some would say this is a case of YAGNI but I think that separating infrastructure for domain code is very beneficial both in terms of code quality and the ability to reason about the domain.

I would also recommend that you push the unit of work code into the infrastructure as much as possible, so that application services don't have to call Commit explicitly.

Or is the better approach to use Dependency Injection in the workflow to get a CommandBus that will handle processing 2 new, almost identical command models that I will have to create, along with Validation and Submission handlers for them?

This seems more in line with my suggestion, however based on your code sample, I'd recommend going a step further and extracting most more of the logic inside the CodeActivity into an application service, or structure the application in such a way that you can dispatch a command without needed access to a repository.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top