在 Action 之外访问 ControlerBase(在 CQRS 处理程序中)
Access ControlerBase outside Action (in CQRS handler)
我正在将我的逻辑从 Controller 转移到 CQRS 处理程序,我不确定如何处理调用 ControllerBase 的代码,例如:
[HttpPut("users/{id}")]
public IActionResult Put(UserForm userForm)
{
var user = Users.Get(email);
if (user == null)
return NotFound();
...
}
因此,当我将此逻辑移到操作之外时,显然我无法再访问 NotFound
。我看到了很多解决方法:
- 改为抛出自定义 NotFoundException,然后在 ExceptionMiddleware 中捕获它,然后 return NotFoundResult 在那里。
- 将 ControllerBase 注入 CQRS Commands/Queries。不喜欢此选项,因为 Commands/Queries 会与 ASP.NET 核心基础设施过度耦合。
我很快 Google 搜索不成功所以可能是我遗漏了什么。处理这种情况的推荐方法是什么?
这个 logic/validation 不属于 Command/Query 处理程序,因为它处理不同的事情(用户输入 -> BadRequest,资源状态(NotFound,Ok,Created(201)))场景(WebAPI、MVC、桌面、移动应用程序等)和响应高度依赖于基础设施(在 REST 中你会 return 状态代码、MVC 重定向、桌面消息等)
使用例外是不可接受的,因为这些是常见场景而不是例外场景(至少输入验证和 "not found")。在处理程序中使用 IActionResult
也与基础架构紧密耦合。
在更大的项目中,我使用 "result" 类,类似于 ASP.NET Core Identity 中的 IdentityResult
。
namespace MyProject.Common
{
public class QueryResult
{
private static readonly QueryResult success = new QueryResult { Succeeded = true };
private readonly List<QueryError> errors = new List<QueryError>();
public static QueryResult Success { get { return success; } }
public bool Succeeded { get; protected set; }
public IEnumerable<QueryError> Errors { get { return errors; } }
public static QueryResult Failed(params QueryError[] errors)
{
var result = new QueryResult { Succeeded = false };
if (errors != null)
{
result.errors.AddRange(errors);
}
return result;
}
}
public class QueryResult<T> : QueryResult where T : class
{
public T Result { get; protected set; }
public static QueryResult<T> Suceeded(T result)
{
var queryResult = new QueryResult<T>
{
Succeeded = true,
Result = result
};
return queryResult;
}
}
}
和 return 这些来自命令 (QueryResult
) 或查询 (QueryResult<T>
)。
然后您可以编写 return 正确 IActionResult
的扩展方法。
public static class QueryResultExtensions
{
public IActionResult ToActionResult(this QueryResult result)
{
if(result.Success)
{
return new OkResult();
}
if(result.Errors != null)
{
// ToModelStateDictionary needs to be implemented by you ;)
var errors = result.Errors.ToModelStateDictionary();
return BadRequestResult(errors);
}
return BadRequestResult();
}
public IActionResult ToActionResult<T>(this QueryResult<T> result)
{
if(result.Success)
{
if(result.Result == null)
{
return new NotFoundResult();
}
return new OkObjectResult(result.Result);
}
if(result.Errors != null)
{
// ToModelStateDictionary needs to be implemented by you ;)
var errors = result.Errors.ToModelStateDictionary();
return BadRequestResult(errors);
}
return BadRequestResult();
}
}
然后在你的控制器中调用它
[HttpPut("users/{id}")]
public IActionResult Put(CreateUserCommand command)
{
var result = commandHandler.Handle(command);
return result.ToActionResult();
}
您失去了更细粒度地控制 return 代码的能力。您可以为 commands/queries 或以不同方式处理它的不同扩展方法创建不同的结果类型 .ToCreateActionResult()
、.ToQueryActionResult()
等
我正在将我的逻辑从 Controller 转移到 CQRS 处理程序,我不确定如何处理调用 ControllerBase 的代码,例如:
[HttpPut("users/{id}")]
public IActionResult Put(UserForm userForm)
{
var user = Users.Get(email);
if (user == null)
return NotFound();
...
}
因此,当我将此逻辑移到操作之外时,显然我无法再访问 NotFound
。我看到了很多解决方法:
- 改为抛出自定义 NotFoundException,然后在 ExceptionMiddleware 中捕获它,然后 return NotFoundResult 在那里。
- 将 ControllerBase 注入 CQRS Commands/Queries。不喜欢此选项,因为 Commands/Queries 会与 ASP.NET 核心基础设施过度耦合。
我很快 Google 搜索不成功所以可能是我遗漏了什么。处理这种情况的推荐方法是什么?
这个 logic/validation 不属于 Command/Query 处理程序,因为它处理不同的事情(用户输入 -> BadRequest,资源状态(NotFound,Ok,Created(201)))场景(WebAPI、MVC、桌面、移动应用程序等)和响应高度依赖于基础设施(在 REST 中你会 return 状态代码、MVC 重定向、桌面消息等)
使用例外是不可接受的,因为这些是常见场景而不是例外场景(至少输入验证和 "not found")。在处理程序中使用 IActionResult
也与基础架构紧密耦合。
在更大的项目中,我使用 "result" 类,类似于 ASP.NET Core Identity 中的 IdentityResult
。
namespace MyProject.Common
{
public class QueryResult
{
private static readonly QueryResult success = new QueryResult { Succeeded = true };
private readonly List<QueryError> errors = new List<QueryError>();
public static QueryResult Success { get { return success; } }
public bool Succeeded { get; protected set; }
public IEnumerable<QueryError> Errors { get { return errors; } }
public static QueryResult Failed(params QueryError[] errors)
{
var result = new QueryResult { Succeeded = false };
if (errors != null)
{
result.errors.AddRange(errors);
}
return result;
}
}
public class QueryResult<T> : QueryResult where T : class
{
public T Result { get; protected set; }
public static QueryResult<T> Suceeded(T result)
{
var queryResult = new QueryResult<T>
{
Succeeded = true,
Result = result
};
return queryResult;
}
}
}
和 return 这些来自命令 (QueryResult
) 或查询 (QueryResult<T>
)。
然后您可以编写 return 正确 IActionResult
的扩展方法。
public static class QueryResultExtensions
{
public IActionResult ToActionResult(this QueryResult result)
{
if(result.Success)
{
return new OkResult();
}
if(result.Errors != null)
{
// ToModelStateDictionary needs to be implemented by you ;)
var errors = result.Errors.ToModelStateDictionary();
return BadRequestResult(errors);
}
return BadRequestResult();
}
public IActionResult ToActionResult<T>(this QueryResult<T> result)
{
if(result.Success)
{
if(result.Result == null)
{
return new NotFoundResult();
}
return new OkObjectResult(result.Result);
}
if(result.Errors != null)
{
// ToModelStateDictionary needs to be implemented by you ;)
var errors = result.Errors.ToModelStateDictionary();
return BadRequestResult(errors);
}
return BadRequestResult();
}
}
然后在你的控制器中调用它
[HttpPut("users/{id}")]
public IActionResult Put(CreateUserCommand command)
{
var result = commandHandler.Handle(command);
return result.ToActionResult();
}
您失去了更细粒度地控制 return 代码的能力。您可以为 commands/queries 或以不同方式处理它的不同扩展方法创建不同的结果类型 .ToCreateActionResult()
、.ToQueryActionResult()
等