我最近一直在研究CQRS / MediatR。但是,我越深入,就越不喜欢它。也许我误会了一些东西。
因此,它声称可以将您的控制器简化为
public async Task<ActionResult> Edit(Edit.Query query)
{
var model = await _mediator.SendAsync(query);
return View(model);
}
完全符合瘦控制器指南。但是,它忽略了一些非常重要的细节-错误处理。
让我们看一下Login
新MVC项目中的默认操作
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation(1, "User logged in.");
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning(2, "User account locked out.");
return View("Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
进行转换会给我们带来许多现实问题。记住目标是将其减少到
public async Task<IActionResult> Login(Login.Command command, string returnUrl = null)
{
var model = await _mediator.SendAsync(command);
return View(model);
}
一种可能的解决方案是返回a CommandResult<T>
而不是a model
,然后CommandResult
在后操作过滤器中处理。正如这里所讨论的。
的一种实现CommandResult
可能是这样的
public interface ICommandResult
{
bool IsSuccess { get; }
bool IsFailure { get; }
object Result { get; set; }
}
但这并不能真正解决我们的问题Login
,因为有多个故障状态。我们可以将这些额外的失败状态添加到其中,ICommandResult
但这对于非常膨胀的类/接口来说是一个很好的开始。有人可能会说它不符合单一职责(SRP)。
另一个问题是returnUrl
。我们有这段return RedirectToLocal(returnUrl);
代码。我们需要以某种方式基于命令的成功状态来处理条件参数。虽然我认为可以做到(我不确定ModelBinder是否可以将FromBody和FromQuery(returnUrl
是FromQuery)参数映射到单个模型)。只能想知道会发生什么疯狂的情况。
随着返回错误消息,模型验证也变得更加复杂。以这个为例
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
我们将错误消息与模型一起附加。这种事情不能用做Exception
战略(如建议在这里),因为我们需要的型号。也许您可以从中获取模型,Request
但这将是一个非常复杂的过程。
因此,总的来说,我很难转换这种“简单”的动作。
我在寻找输入。我在这里完全错了吗?