【问题标题】:Custom validation at controller level in web apiWeb api中控制器级别的自定义验证
【发布时间】:2021-04-26 01:20:51
【问题描述】:

我在网络标准 2.0 库中遇到了一个问题,我真的不知道如何解决它。

假设我有一个这样的控制器:

    [Route("{action}/{Id}")]
    [HttpPut]
    public void UpdateUser([FromBody] UserDTO user, long id )
    {
        _service.UpdateUser(user, id);
    }

简单,有效。 现在我想添加一些自定义验证。 我知道我可以在 DTO 上使用 System.ComponentModel.DataAnnotations,但是当有错误请求时的消息是......错误。

我尝试将 ValidationAttributeisValidFormatErrorMessage 一起使用,然后像这样将其添加到我的控制器中

    [MyValidation]
    [Route("{action}/{Id}")]
    [HttpPut]
    public void UpdateUser([FromBody] UserDTO user, long id )
    {
        _service.UpdateUser(user, id);
    }

但它从未到达 MyValidation 代码,它只是跳过它。

有没有办法我可以做到这一点,以便我可以进行所有我想要的验证并对照我的数据库检查它并做我需要的所有事情?

我该如何继续?

我找到的所有指南都与 .core 或 .mvc 有关,我无法使用因为我在网络标准库上 即使是指南也会很棒! 感谢任何想要帮助的人:D

我的解决方案!

所以,经过大量研究后,我发现......这是不可能的。 至少从我的理解/尝试来看

我做了一些解决方法,因为我使用的东西不能在网络标准库上使用,无论如何,网络标准似乎没有这种东西可以使用。

我使用了 IActionFilter。

我创建了一个类并继承了过滤器并放入了它需要的两个方法,OnActionExecuted 和 OnActionExecuting。

public class UserFilter : IActionFilter
    {
       public void OnActionExecuted(ActionExecutedContext context)
        {
           
        }

      public void OnActionExecuting(ActionExecutingContext context)
        {
        }
    }

要读取您可以使用的有效负载中的内容

    UserDTO model = new UserDTO();
    model = context.ActionArguments["user"] as UserDTO;

其中 user 是您的有效负载的“名称”。 要知道它是什么,您可以使用调试器并阅读 context.actionArguments 中的内容。 请记住在该名称之间使用“”。 您必须使用“as”关键字将其投射到您的模型中。 现在您可以访问您的有效负载,并且可以进行自己的自定义验证器!!!

在我的例子中,我创建了一个包含字符串错误的字符串列表,验证 id 并在列表至少包含一个元素时抛出错误。

示例:

     UserDTO model = new UserDTO();
     List<string> CustomError = new List<string>();
     model = context.ActionArguments["user"] as UserDTO;
     if (model.Age == 0) //dumb control, just for the sake of the example
        {
           CustomError.Add("age cannot be 0!")      
        }
     //other controls
     if (CustomError.Count > 0)
        {
            context.Result = new BadRequestObjectResult(CustomError);
        }

最后一个 if 很重要!如果你创建的列表至少有一个元素,它会抛出一个错误的请求(错误 400),你会得到一个包含所有错误的 json。

在你想要自定义验证使用的控制器之上

     [HttpPost]
     [TypeFilter(typeof(UserFilter))]
     public IValidation<> PostUser(UserDTO user)
       {
        //your controller logic
       }

希望它会帮助将来像我一样陷入困境的人,试图在网络标准中自定义验证数据,这似乎是不可能的

【问题讨论】:

  • 您知道您可以在数据注释上设置自己的ErrorMessage 吗?您还可以在控制器中将错误添加到 ModelState 以进行服务器端验证。
  • @Crowcoder 是的,但我必须找到一种方法在类中构建它
  • 有一个名为 FluentValidation 的库,您可以在其中为您的模型定义各种规则,它就像一个魅力。看看:fluentvalidation.net

标签: c# .net-standard


【解决方案1】:

您需要实现 ValidationAttribute 类,然后您可以编写自己的逻辑并用作模型上的数据注释。

示例实现

public class ValidJoinDate : ValidationAttribute
{      
    protected override ValidationResult 
            IsValid(object value, ValidationContext validationContext)
    {   
        DateTime _dateJoin = Convert.ToDateTime(value); 
        if (_dateJoin < DateTime.Now)
        {
            return ValidationResult.Success;
        }
        else
        {
            return new ValidationResult
                ("Join date can not be greater than current date.");
        }
    }        
}

并以这种方式在您的模型属性中使用:

public class Customer
{
    
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}"
        , ApplyFormatInEditMode = true)]
    [ValidJoinDate(ErrorMessage=
        "Join Date can not be greater than current date")] 
    public DateTime JoinDate { get; set; }

    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = 
        "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    [ValidLastDeliveryDate(ErrorMessage = 
        "Last Delivery Date can not be less than Join Date")]
    public DateTime LastDeliveryDate { get; set; }
   
}

希望这能解决你的问题?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-03
    • 2016-12-11
    • 2021-01-25
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    • 2016-05-06
    相关资源
    最近更新 更多