是否可以通过DI(在Controller或ActionFilter之外)访问ModelStateDictionary
?我想我可以制作一个ActionFilter来存储对ModelStateDictionary
的引用,以便以后可以在其他地方访问它,但是我想知道是否有常规的访问方式,例如IHttpContextAccessor
有HttpContext
。
我们有一个网络应用程序,它是api的客户端。之所以这样做,是因为我想从API客户端(类型为http客户端)使用的ModelState
向Web应用程序的DelegatingHandler
自动添加错误。处理程序将监视来自API的每个响应,并为适用的响应(主体中包含400个带有自定义错误代码的响应,例如“名称已被接受”)向ModelState
添加一条消息。
到目前为止,我已经尝试过请求ControllerContext
,但它似乎始终为空。
var controllerContext = _serviceProvider.GetService<ControllerContext>();
controllerContext?.ModelState.AddModelError("", result.ErrorMessage);
我还使用VS调试器查看了所有已注册的服务,但是找不到任何有希望的东西。
附带说明(很大):我认为这不违反SRP。 API客户端是我们API的通用客户端实现,可以在任何地方使用(我们目前在Xamarin和ASP.NET Core MVC Web应用程序上使用它-本问题中提到的一个)。但是,API客户端期望在其构造函数中使用HttpClient
,这意味着其行为可以被其使用者修改。
例如,Web应用程序使用DI提供API客户端所需的HttpClient
。 HttpClient
设置为使用两个委托处理程序,其中一个是我在此问题中描述的处理程序。
关于ModelState
是否应在控制器之外进行操作:好吧,这正是FluentValidation
之类的库(和ASP.NET默认验证)所做的。
关于是否应该在ModelState
中操纵DelegatingHandler
:我认为这是一个更有效的讨论。但是,没有人真的没有提出任何关于为什么这样做不好的论据。
无论是否要执行此操作,都应该“自动”完成:我认为将代码放在一个地方比在每次对api的每次调用中都要记住每次执行操作要好得多。
关于是否应将这些消息甚至放到ModelState
中:好吧,如果我在这里提到,该面注释将变得太大。而且,没有人真的对此争论过,所以...
答案 0 :(得分:2)
您无法获得ControllerContext
本身,但可以得到的是ActionContext
(这是控制器上下文的更专业版本)。您可以使用IActionContextAccessor
:
var actionContextAccessor = _serviceProvider.GetService<IActionContextAccessor>();
var actionContext = actionContextAccessor.ActionContext;
actionContext?.ModelState.AddModelError("", result.ErrorMessage);
实际上,您不需要每次都解析操作上下文访问器,但是可以保留它的一个实例,并在需要时访问操作上下文。 ActionContext
将在您处理请求时处于动作范围内时设置。
另一种解决方案是将关注点分离并将错误存储在其他位置,然后在操作过滤器中从那里填充模型状态。这样,您的解决方案将不仅限于MVC,而且还可以在其他位置访问这些错误。
答案 1 :(得分:0)
在我看来,这样做会打破单一责任原则,因为http客户端对控制器一无所知。
但是,如果您确实要这样做,则可以使用lambda表达式将ModelStateDictionary的引用传递给您的委托,请参见:Passing delegate function with extra parameters
如果不想破坏SRP,一种选择是使http客户端返回错误列表,该错误列表将由控制器添加到模型状态(如果没有错误,则为null)>