在控制器和 ActionFilter 之外获取 ModelState
Get ModelState outside of controller and ActionFilter
有没有办法从 DI(在 Controller 或 ActionFilter 之外)访问 ModelStateDictionary
?我想我可以制作一个 ActionFilter,在某处存储对 ModelStateDictionary
的引用,这样我以后可以在其他地方访问它,但我想知道是否有 常规 访问方式它,就像 IHttpContextAccessor
对应 HttpContext
.
我们有一个 Web 应用程序,它是我们 api 的客户端。我想这样做的原因是因为我想从我们的 API 客户端(类型化的 http 客户端)使用的 DelegatingHandler
自动向 Web 应用程序的 ModelState
添加错误。处理程序将监视来自 API 的每个响应,并且对于适用的响应(正文中带有自定义错误代码的 400 个响应,如 "Name already taken"),向 ModelState
添加一条消息。
到目前为止,我已经尝试请求一个 ControllerContext
,但它似乎总是空的。
var controllerContext = _serviceProvider.GetService<ControllerContext>();
controllerContext?.ModelState.AddModelError("", result.ErrorMessage);
我也查看了所有使用 VS 调试器的注册服务,但我找不到任何有希望的东西。
旁注(相当大)关于 SRP 和关注点分离的评论:我不认为这违反了 SRP。 API 客户端是我们 API 的通用客户端实现,可以从任何地方使用(我们目前在 Xamarin 和 ASP.NET Core MVC Web 应用程序上使用它——本文中提到的那个)非常疑问)。但是,API 客户端在其构造函数中期望 HttpClient
,这意味着其行为可以由其消费者修改。
例如,Web 应用程序使用 DI 来提供 HttpClient
和 API 客户端的需求。 HttpClient
设置为使用两个委托处理程序,其中之一就是我在这个问题中描述的那个。
至于 ModelState
是否应该在控制器之外进行操作:好吧,这正是像 FluentValidation
(和 ASP.NET 默认验证)这样的库所做的。
至于 ModelState
是否应该在 DelegatingHandler
中被操纵:我认为这是一个更有效的讨论。然而,没有人真正提出任何关于为什么这不好的论据。
至于是否应该这样做 "automatically":我认为将代码放在一个地方比每次调用 api.
至于这些消息是否应该甚至放入ModelState
:好吧,如果我在这里进入那个 side 注释会变得太大。另外,没有人真正争论过这个,所以...
在我看来,这样做会破坏单一职责原则,因为 http 客户端不应该知道有关您的控制器的任何信息。
但是,如果您真的想这样做,可以使用 lambda 表达式将 ModelStateDictionary 的引用传递给您的委托,请参阅:Passing delegate function with extra parameters
如果您不想破坏 SRP,一种选择是使 http 客户端 return 控制器添加到模型状态的错误列表(或如果没有错误则为 null)
您无法获得 ControllerContext
itself but what you can get is the ActionContext
(which is a more specialized version of the controller context). You can get it by using the IActionContextAccessor
:
var actionContextAccessor = _serviceProvider.GetService<IActionContextAccessor>();
var actionContext = actionContextAccessor.ActionContext;
actionContext?.ModelState.AddModelError("", result.ErrorMessage);
您实际上不需要每次都解析操作上下文访问器,但可以保留它的实例并在需要时访问操作上下文。 ActionContext
将在您处理请求时处于操作范围内时设置。
另一种解决方案是分离关注点并将错误存储在其他地方,然后在操作过滤器期间从那里填充模型状态。这样,您的解决方案就不会局限于 MVC 方式,您还可以在其他地方访问这些错误。
有没有办法从 DI(在 Controller 或 ActionFilter 之外)访问 ModelStateDictionary
?我想我可以制作一个 ActionFilter,在某处存储对 ModelStateDictionary
的引用,这样我以后可以在其他地方访问它,但我想知道是否有 常规 访问方式它,就像 IHttpContextAccessor
对应 HttpContext
.
我们有一个 Web 应用程序,它是我们 api 的客户端。我想这样做的原因是因为我想从我们的 API 客户端(类型化的 http 客户端)使用的 DelegatingHandler
自动向 Web 应用程序的 ModelState
添加错误。处理程序将监视来自 API 的每个响应,并且对于适用的响应(正文中带有自定义错误代码的 400 个响应,如 "Name already taken"),向 ModelState
添加一条消息。
到目前为止,我已经尝试请求一个 ControllerContext
,但它似乎总是空的。
var controllerContext = _serviceProvider.GetService<ControllerContext>();
controllerContext?.ModelState.AddModelError("", result.ErrorMessage);
我也查看了所有使用 VS 调试器的注册服务,但我找不到任何有希望的东西。
旁注(相当大)关于 SRP 和关注点分离的评论:我不认为这违反了 SRP。 API 客户端是我们 API 的通用客户端实现,可以从任何地方使用(我们目前在 Xamarin 和 ASP.NET Core MVC Web 应用程序上使用它——本文中提到的那个)非常疑问)。但是,API 客户端在其构造函数中期望 HttpClient
,这意味着其行为可以由其消费者修改。
例如,Web 应用程序使用 DI 来提供 HttpClient
和 API 客户端的需求。 HttpClient
设置为使用两个委托处理程序,其中之一就是我在这个问题中描述的那个。
至于 ModelState
是否应该在控制器之外进行操作:好吧,这正是像 FluentValidation
(和 ASP.NET 默认验证)这样的库所做的。
至于 ModelState
是否应该在 DelegatingHandler
中被操纵:我认为这是一个更有效的讨论。然而,没有人真正提出任何关于为什么这不好的论据。
至于是否应该这样做 "automatically":我认为将代码放在一个地方比每次调用 api.
至于这些消息是否应该甚至放入ModelState
:好吧,如果我在这里进入那个 side 注释会变得太大。另外,没有人真正争论过这个,所以...
在我看来,这样做会破坏单一职责原则,因为 http 客户端不应该知道有关您的控制器的任何信息。
但是,如果您真的想这样做,可以使用 lambda 表达式将 ModelStateDictionary 的引用传递给您的委托,请参阅:Passing delegate function with extra parameters
如果您不想破坏 SRP,一种选择是使 http 客户端 return 控制器添加到模型状态的错误列表(或如果没有错误则为 null)
您无法获得 ControllerContext
itself but what you can get is the ActionContext
(which is a more specialized version of the controller context). You can get it by using the IActionContextAccessor
:
var actionContextAccessor = _serviceProvider.GetService<IActionContextAccessor>();
var actionContext = actionContextAccessor.ActionContext;
actionContext?.ModelState.AddModelError("", result.ErrorMessage);
您实际上不需要每次都解析操作上下文访问器,但可以保留它的实例并在需要时访问操作上下文。 ActionContext
将在您处理请求时处于操作范围内时设置。
另一种解决方案是分离关注点并将错误存储在其他地方,然后在操作过滤器期间从那里填充模型状态。这样,您的解决方案就不会局限于 MVC 方式,您还可以在其他地方访问这些错误。