【问题标题】:Conditional validation based on request route with asp.net core 2.2 and FluentValidation基于请求路由的条件验证与 asp.net core 2.2 和 FluentValidation
【发布时间】:2019-07-22 21:11:05
【问题描述】:
所以基本上我用 FluentValidation 为我的类编写了一个验证器,还用一个过滤器在我的 webAPI 项目中为我完成了验证任务,到目前为止还可以,但假设我的 User 类具有名字、姓氏、电子邮件、密码属性
我有两条路线(一条用于注册,另一条用于登录)
并且您可能已经注意到,这些路由所需的属性不同。
因此,我是否真的需要为我拥有的每一个操作编写单独的验证?因为这会导致大量代码重复并且很难更改。有没有办法根据即将到来的请求添加所需的条件单一验证类?
有什么建议???
【问题讨论】:
标签:
asp.net-core-mvc
fluentvalidation
asp.net-core-2.2
【解决方案1】:
更好的做法是使用工厂模式进行验证,并使用操作过滤器来缩短错误请求。您可以使用类似的方式验证任何操作参数(标头、请求正文等)。
public class TestValidationAttribute : Attribute, IActionFilter
{
private string _requestModelName;
public TestValidationAttribute(string requestModelName)
{
_requestModelName = requestModelName;
}
public void OnActionExecuting(ActionExecutingContext context)
{
// using Microsoft.Extensions.DependencyInjection;
var services = context.HttpContext.RequestServices;
var accessor = services.GetService<IHttpContextAccessor>();
var factory = services.GetService<ITestValidatorFactory>();
var tokens = accessor.HttpContext.GetRouteData().DataTokens;
if (!tokens.TryGetValue("RouteName", out var routeNameObj))
{
throw new Exception($"Action doesn't have a named route.");
}
var routeName = routeNameObj.ToString();
var validator = factory.Create(routeName);
if (!context.ActionArguments.TryGetValue(_requestModelName, out var model))
{
throw new Exception($"Action doesn't have argument named {_requestModelName}.");
}
TestModel test;
try
{
test = (TestModel) model;
}
catch (InvalidCastException)
{
throw new Exception($"Action argument can't be casted to {nameof(TestModel)}.");
}
var validation = validator.Validate(test);
if (!validation.Successful)
{
context.Result = new BadRequestObjectResult(validation.ResponseModel);
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
public class TestController : Controller
{
[HttpPost]
[Route("Test/{id}", Name = "TestGet")]
[TestValidation("model")]
public IActionResult Test(TestModel model)
{
return Ok();
}
}
public class ValidationResult
{
public bool Successful { get; }
public ResponseModel ResponseModel { get; }
}
public class TestModel
{
}
public interface ITestValidator
{
ValidationResult Validate(TestModel model);
}
public interface ITestValidatorFactory
{
ITestValidator Create(string routeName);
}