【问题标题】:Validating model sent to Web API controller验证模型发送到 Web API 控制器
【发布时间】:2015-06-30 08:15:16
【问题描述】:

在对 Web API 服务的调用中,我需要将以下类属性发送到其控制器方法:

public class FindBookingRequestModel 
{
    public string ReservationNumber { get; set; }
    public string CreditCardNumber { get; set; }
    public string EmailAddress { get; set; }
    public string Origin { get; set; }
    public string Destination { get; set; }
    public DateTime? StartDate { get; set; }
}

每个用例,我需要验证发送到 Web api 控制器的模型并确保填充以下类属性的三个场景,否则我需要抛出 BadRequest 异常。

  1. 用例:

    {
        "ReservationNumber": "WERTSDFFSDF",
        "CreditCardNumber" : "3333"
    }   
    
  2. 用例

    {
        "ReservationNumber" : "WERTSDFFSDF",
        "EmailAddress" : "somene@gmail",
        "Origin" : "FRA",
        "Destination" : "MUN"
    }
    
  3. 用例

    {
        "StartDate" : "2015-12-15",
        "EmailAddress" : "somene@gmail",
        "Origin" : "FRA",
        "Destination" : "MUN"
    }
    

所以如果我们将此模型发送到控制器应该是错误的:

{
    "ReservationNumber": "WERTSDFFSDF",
    "Origin" : "FRA",
} 

或者这个:

{
    "EmailAddress" : "somene@gmail",
     "StartDate" : "2015-12-15",
}

确保按照上述用例传递字段的最有效方法是什么?

【问题讨论】:

  • 您可以编写自定义属性并在 ASP.Net WebApi 中进行模型验证 - asp.net/web-api/overview/formats-and-model-binding/…
  • 谢谢,但我需要验证类实例——特定调用是否适合用例。
  • 我的第一个想法是拥有具有所需属性的单独对象,但没有基于提供的参数重载 Web API 方法这样的事情。用例应该至少有这些参数,而不是更多,对吗?
  • 您的用例能否在客户端分开,例如通过有不同的输入形式?然后,您可以为每个用例处理不同的控制器方法,这将使服务器端的验证更加清晰。
  • @rdoubleui 事情是在这里只获得一个类 - 我们不允许制作三个不同的视图模型以适应用例,我们也不想在控制器上制作三个单独的方法而不是一个跨度>

标签: c# validation asp.net-web-api


【解决方案1】:

您可以实现IValidatableObject 来执行跨属性验证,可能也值得考虑单个属性值验证。

我建议在可能的情况下对属性值使用正则表达式(它们只会在属性值不为 null 时运行,因为您没有所有有效类型的任何必填字段,请避免使用 [Required] 属性)和然后使用Validate 方法进行跨属性验证:

public class FindBookingRequestModel : IValidatableObject
{
    [RegularExpression("[A-Z]+")]
    public string ReservationNumber { get; set; }

    [RegularExpression("...")] // Find a regex online
    public string CreditCardNumber { get; set; }

    [RegularExpression("...")] // Find a regex online
    public string EmailAddress { get; set; }

    [RegularExpression("[A-Z]{3}")]
    public string Origin { get; set; }

    [RegularExpression("[A-Z]{3}")]
    public string Destination { get; set; }

    public DateTime? StartDate { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrWhiteSpace(this.ReservationNumber) 
            && !string.IsNullOrWhiteSpace(this.Origin))
        {
            yield return new ValidationResult(
                "You cannot search using Reservation Number and Origin", 
                new[] { "ReservationNumber", "Origin" });
        }

        if (!string.IsNullOrWhiteSpace(this.EmailAddress) 
            && this.StartDate != null)
        {
            yield return new ValidationResult(
                "You cannot search using Email Address and Start Date", 
                new[] { "EmailAddress", "StartDate" });
        }

        yield break;
    }
}

如果无效组合太多,您可以这样做:

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrWhiteSpace(this.ReservationNumber) 
            && !string.IsNullOrWhiteSpace(this.CreditCardNumber)
            && this.EmailAddress == null
            && this.Origin == null
            && this.Destination == null
            && this.StartDate == null)
        {
            // OK - Only reservation number and credit card number specified
            yield break;
        }

        /// ...

        yield return new ValidationResult(
            "Invalid combination of search terms");
    }

【讨论】:

  • 这种方法是不是来自错误的一面?无效参数的组合“无穷无尽”。人们应该找到一种优雅的方式来过滤积极因素。
  • 如果 3 个有效结果都不匹配,您可以翻转它并返回单个验证结果 - 我正在展示如何以 WebApi 中使用的验证支持的方式验证跨属性 -我不建议为 OP 编写所有验证规则。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-18
  • 2015-04-25
  • 2017-06-23
  • 2021-10-12
  • 1970-01-01
  • 2015-09-06
  • 2013-09-06
相关资源
最近更新 更多