如何将条件必需属性放入类属性以与WEB API一起使用?

27
我只想使用适用于WEB API的条件必填属性。
示例。
public sealed class EmployeeModel
{
      [Required]
      public int CategoryId{ get; set; }
      public string Email{ get; set; } // If CategoryId == 1 then it is required
}

我正在使用通过 (ActionFilterAttribute) 的模型状态验证。

2个回答

54

您可以实现自己的 ValidationAttribute。例如像这样:

public class RequireWhenCategoryAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var employee = (EmployeeModel) validationContext.ObjectInstance;
        if (employee.CategoryId == 1)
            return ValidationResult.Success;

        var emailStr = value as string;
        return string.IsNullOrWhiteSpace(emailStr)
            ? new ValidationResult("Value is required.")
            : ValidationResult.Success;
    }
}

public sealed class EmployeeModel
{
    [Required]
    public int CategoryId { get; set; }
    [RequireWhenCategory]
    public string Email { get; set; } // If CategoryId == 1 then it is required
}

这只是一个示例。它可能存在强制类型转换问题,而且我不确定这是否是解决此问题的最佳方法。


“我不确定这是解决问题的最佳方法。”还有哪些其他方法可以解决这个问题? - Scott Chamberlain
3
这是一个不错的方法,实际上我希望避免在控制器中添加验证逻辑,因为这需要进行很多更改(根据更改需求),而我不想这样做。 - Shubhajyoti Ghosh
10
为了节省时间并获得更多的灵活性,而不是为每个特定情况创建自定义验证属性,请查看ExpressiveAnnotations。在这种情况下,您可以使用它来对“Email”字段进行注释,注释如下:[RequiredIf("CategoryId == 1")]。请注意,此翻译中保持了原文的意思和表达方式,并尽力使其通俗易懂。 - jwaliszko
2
实际上,这个评论是错误的:如果CategoryId == 1,则不需要。 - bombek
1
太棒了!救了我的命!谢谢。 - leighhydes
显示剩余2条评论

7

以下是我的建议,如果出现“当前的AssigneeType值为Salesman,需要提供AssigneeId”这样的错误信息,这将会给您一个很好的提示。对于枚举也同样适用。

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class RequiredForAnyAttribute : ValidationAttribute
{
    /// <summary>
    /// Values of the <see cref="PropertyName"/> that will trigger the validation
    /// </summary>
    public string[] Values { get; set; }

    /// <summary>
    /// Independent property name
    /// </summary>
    public string PropertyName { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var model = validationContext.ObjectInstance;
        if (model == null || Values == null)
        {
            return ValidationResult.Success;
        }

        var currentValue = model.GetType().GetProperty(PropertyName)?.GetValue(model, null)?.ToString();
        if (Values.Contains(currentValue) && value == null)
        {
            var propertyInfo = validationContext.ObjectType.GetProperty(validationContext.MemberName);
            return new ValidationResult($"{propertyInfo.Name} is required for the current {PropertyName} value {currentValue}");
        }
        return ValidationResult.Success;
    }
}

像这样使用它

public class SaveModel {
    [Required]
    public AssigneeType? AssigneeType { get; set; }

    [RequiredForAny(Values = new[] { nameof(AssigneeType.Salesman) }, PropertyName = nameof(AssigneeType))]
    public Guid? AssigneeId { get; set; }
}

我复制了你的属性,谢谢分享 :) - ilyas varol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接