【发布时间】:2020-10-10 00:45:49
【问题描述】:
我正在使用 Mediatr 在 dotnet core 3.0 中实现 CQRS 模式。我对如何协调不同的多个查询和命令有一些疑问。根据我在网上阅读的内容,这里有一些人们描述的最佳做法。
- 查询处理程序不应依赖于命令处理程序
- 命令处理程序不应依赖于查询处理程序
- 不要使用装饰器,而是使用
IPipelineBehaviour - 每个命令都应一对一映射到
HTTP Request(例如:创建用户会将命令发送到CreateUserCommandHandler,这将负责所有工作) - 对于命令处理程序,返回 void 。使用 Mediatr 框架,我会返回
Task<Unit>
这是我的问题,现在,我正在为 AspNet.Identity 实现 IUserStore<TUser>,假设我们正在查看这个示例
public async Task<IdentityResult> DeleteAsync(User user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (user == null) return IdentityResult.Failed(new ArgumentNullError(nameof(user)));
bool userExists = await _mediator.Send(new UserExistsQuery {UserId = user.Id}, cancellationToken);
if (!userExists) return IdentityResult.Failed(new EntityDoesNotExistError(user));
await _mediator.Send(new DeleteUserCommand {User = user}, cancellationToken);
return IdentityResult.Success;
}
在这种方法中,我基本上是使用实现用户存储来协调不同的查询和命令以删除用户。在这种情况下,我可以看到执行以下操作以使其尽可能薄并更严格地遵循“每个 http 请求一个命令”
- 摆脱
UserExistsQuery和UserExistsQueryQueryHandler,将该查询移至DeleteUserCommandHandler并使用存储库进行查询(UserExistsQueryHandler现在已经这样做了)而不是依赖于查询处理程序 - 不是返回
Task<Unit>,而是返回类似IdentityResult的东西
我犹豫是否要执行 #2 的原因是,我感觉我正在根据使用命令的上下文返回一些东西。我返回一个 IdentityResult 只是因为我需要它来处理这个实例。
此外,我首先将其拆分成这样的原因是为了可重用性。我希望能够进行一些可以在其他地方重复使用的查询和命令。如果我返回一个IdentityResult,那么这种方式就达不到目的,因为除了UserStore<TUser>,我在任何地方都不需要它
我一直在阅读有关 IPipelineBehaviour 的信息,但它似乎更像是所有查询/命令处理程序的通用解决方案(即:如果您的程序集中存在适当的类型,则可以为每个命令/查询运行该管道)。但是IPipelineBehaviour 可以用来实现自定义管道吗?在我的示例中,我会将所有这些逻辑移至仅针对DeleteUserCommand 运行的管道?
我已经搜索过有关此主题的文章,但实际上找不到任何有用的东西 - 或者我正在搜索错误的术语。我的术语可能是错误的,但我可以创建仅依赖于IMediatr 的协调服务来完成删除用户。任何反馈和/或阅读材料将不胜感激。
【问题讨论】: