2

有没有办法ModelStateDictionary从 DI 访问(在控制器或 ActionFilter 之外)?我想我可以制作一个 ActionFilter 来存储对ModelStateDictionary某处的引用,以便稍后在其他地方访问它,但我想知道是否有一种传统的方式来访问它,例如IHttpContextAccessorfor HttpContext

我们有一个 Web 应用程序,它是我们 api 的客户端。我想这样做的原因是因为我想ModelStateDelegatingHandler我们的 API 客户端(一个类型化的 http 客户端)使用的网络应用程序中自动添加错误。处理程序将监视来自 API 的每个响应,并且对于适用的响应(正文中带有自定义错误代码的 400 个响应,例如“名称已采用”),将消息添加到ModelState.

到目前为止,我已经尝试过要求 a ControllerContext,但它似乎总是为空。

var controllerContext = _serviceProvider.GetService<ControllerContext>();
controllerContext?.ModelState.AddModelError("", result.ErrorMessage);

我还使用 VS 调试器查看了所有注册的服务,但我找不到任何有希望的东西。


关于关于 SRP 和关注点分离的评论的旁注(相当大的一个):我不认为这违反了 SRP。API 客户端是我们 API 的通用客户端实现,可以在任何地方使用(我们目前在 Xamarin 和 ASP.NET Core MVC Web 应用程序上使用它 - 在这个问题中提到的那个)。但是,API 客户端HttpClient在其构造函数中需要 a,这意味着它的行为可以被它的消费者修改。

例如,Web App 使用 DI 来提供HttpClientAPI 客户端的需求。这HttpClient是设置为使用两个委托处理程序,其中一个是我在这个问题中描述的那个。

至于是否ModelState应该在控制器之外进行操作:嗯,这正是库之类的FluentValidation(和 ASP.NET 默认验证)所做的。

至于是否ModelState应该在 a 中操作DelegatingHandler:我认为这是一个更有效的讨论。然而,没有人真正提出过为什么这是不好的论据。

至于这是否应该“自动”完成:我认为将代码放在一个地方比必须记住在每次调用 api 的每个动作中每次都这样做更好。

至于是否应该将这些消息放入ModelState: 好吧,如果我在这里进入,这个旁注会变得太大。而且,没有人真正争论过这一点,所以......

4

2 回答 2

3

你不能得到它ControllerContext本身,但你能得到的是ActionContext(它是控制器上下文的一个更专业的版本)。您可以使用以下方法获取它IActionContextAccessor

var actionContextAccessor = _serviceProvider.GetService<IActionContextAccessor>();
var actionContext = actionContextAccessor.ActionContext;
actionContext?.ModelState.AddModelError("", result.ErrorMessage);

您实际上不需要每次都解析操作上下文访问器,但可以保留它的一个实例,并在需要时访问操作上下文。当ActionContext您在处理请求时处于操作范围内时,将设置 。

另一种解决方案是分离关注点并将错误存储在其他地方,然后在操作过滤器期间从那里填充模型状态。这样,您的解决方案将不限于 MVC 方式,您还可以在其他地方访问这些错误。

于 2019-01-02T14:56:41.400 回答
0

在我看来,这样做会打破单一责任原则,因为 http 客户端不应该知道任何关于你的控制器的信息。
但是,如果您真的想这样做,您可以使用 lambda 表达式将 ModelStateDictionary 的引用传递给您的委托,请参阅:使用额外参数传递委托函数


如果您不想破坏 SRP,一种选择是让 http 客户端返回要由控制器添加到模型状态的错误列表(如果没有错误,则返回 null)

于 2019-01-02T14:45:38.823 回答