工作流中的域驱动设计支持MVC应用程序设计决策



我正在构建一个N层MVC 4应用程序,该应用程序使用一个抽象的CommandProcessor层来实现Repository和UnitOfWork模式以及域驱动设计,该层验证并执行我的CommandModels。

我现在开始学习Workflow Foundation,并添加了一个处理用户注册的工作流项目。在工作流结束时,如果一切顺利,工作流将执行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();
}
}
}

还有一个类似的RemoveMembership活动,如果用户从未验证,它会在一定时间后删除用户。

我的问题是,在我的工作流程中处理这个问题有意义吗?还是在工作流中使用依赖注入来获得CommandBus的更好方法,该CommandBus将处理我必须创建的两个新的、几乎相同的命令模型,以及它们的验证和提交处理程序?在我的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);
}
}
}
}

显然,这是更多的代码,但这是一个好的设计吗?

我觉得我在写这篇文章时回答了自己的问题,我认为答案是肯定的。但还是想听听专业人士的意见。

我的问题是,在我的工作流?

我会将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的东西所取代,在NServiceBus中您可以引用相同的应用程序服务。有人会说这是YAGNI的一个例子,但我认为分离域代码的基础设施在代码质量和推理域的能力方面都是非常有益的。

我还建议您尽可能多地将工作单元代码推送到基础结构中,这样应用程序服务就不必显式调用Commit

或者在工作流中使用依赖注入是更好的方法要获得一个CommandBus,它将处理2个新的,几乎我必须创建的相同命令模型,以及他们的验证和提交处理程序?

这似乎更符合我的建议,但根据您的代码示例,我建议更进一步,将CodeActivity中的大部分逻辑提取到应用程序服务中,或者以这样一种方式构建应用程序,即您可以在不需要访问存储库的情况下调度命令。

最新更新