使用 C# 和 Web API 自定义所需属性,并使用带有验证上下文的私有访问修饰符

Ebb*_*bbs 5 c# requiredfieldvalidator data-annotations asp.net-web-api

我有以下自定义必需属性:

public class RequiredIfAttribute : RequiredAttribute
{
    private string _DependentProperty;
    private object _TargetValue;

    public RequiredIfAttribute(string dependentProperty, object targetValue)
    {
        this._DependentProperty = dependentProperty;
        this._TargetValue = targetValue;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var propertyTestedInfo = validationContext.ObjectType.GetProperty(this._DependentProperty);

        if (propertyTestedInfo == null)
        {
            return new ValidationResult(string.Format("{0} needs to be exist in this object.", this._DependentProperty));
        }

        var dependendValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

        if (dependendValue == null)
        {
            return new ValidationResult(string.Format("{0} needs to be populated.", this._DependentProperty));
        }

        if (dependendValue.Equals(this._TargetValue))
        {
            var x = validationContext.ObjectType.GetProperty("_Mappings");

            var objectInstance = (Dictionary<object, string[]>)x.GetValue(validationContext.ObjectInstance, null);

            var isRequiredSatisfied = false;

            foreach (var kvp in objectInstance)
            {
                if (kvp.Key.Equals(this._TargetValue))
                {
                    foreach (var field in kvp.Value)
                    {
                        var fieldValue = validationContext.ObjectType.GetProperty(field).GetValue(validationContext.ObjectInstance, null);

                        if (fieldValue != null && field.Equals(validationContext.MemberName))
                        {
                            isRequiredSatisfied = true;
                            break;
                        }
                    }
                }
            }

            if (isRequiredSatisfied)
            {
                return ValidationResult.Success;
            }
            else
            {
                return new ValidationResult(string.Empty);
            }
        }
        else
        {
            // Must be ignored
            return ValidationResult.Success;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图用它实现的是我想根据模型中的属性进行条件验证。它还需要足够通用,以便在多个模型上重复使用。当指定的属性具有特定值(我在属性中指定)时,自定义所需的验证需要匹配这些值。例如在此模型中:

public class PaymentModel
{
    public Dictionary<object, string[]> _Mappings 
    {
        get
        {
            var mappings = new Dictionary<object, string[]>();

            mappings.Add(true, new string[] { "StockID" });
            mappings.Add(false, new string[] { "Amount" });

            return mappings;
        }
    }

    [Required]
    public bool IsBooking { get; set; }

    [RequiredIfAttribute("IsBooking", false)]
    public decimal? Amount { get; set; }

    [RequiredIf("IsBooking", true)]
    public int? StockID { get; set; }

    public PaymentModel()
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

如果该IsBooking属性是true,那么我希望StockId被要求,但如果它是false,那么Amount应该被要求。

目前我的解决方案有效,但有两个问题:

  1. 对财产有依赖性_Mappings,我不想有这种依赖性。有谁知道我将如何按照我的方式去做?
  2. 如果我必须按_Mappings原样使用该属性,有什么方法可以将它用作private访问修饰符吗?目前我只能使我的解决方案工作如果_Mappingspublic,因为validationContext.ObjectType.GetProperty("_Mappings")找不到private修饰符。(如果我想在 Web API 响应中将此模型序列化为 JSON,那么理想情况下我不想发送我的验证映射。)

Mar*_*tin 3

您不必使用 _Mappings 属性,下面的代码检查相关属性是否具有与您在属性中指定的值相匹配的值,如果存在匹配,则它会检查您正在验证的属性是否具有值。

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
    var propertyTestedInfo = validationContext.ObjectType.GetProperty(this._DependentProperty);

    if (propertyTestedInfo == null)
    {
        return new ValidationResult(string.Format("{0} needs to be exist in this object.", this._DependentProperty));
    }

    var dependendValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

    if (dependendValue == null)
    {
        return new ValidationResult(string.Format("{0} needs to be populated.", this._DependentProperty));
    }

    if (dependendValue.Equals(this._TargetValue))
    {
        var fieldValue = validationContext.ObjectType.GetProperty(validationContext.MemberName).GetValue(validationContext.ObjectInstance, null);


        if (fieldValue != null)
        {
            return ValidationResult.Success;
        }
        else
        {
            return new ValidationResult(string.Format("{0} cannot be null", validationContext.MemberName));
        }
    }
    else
    {
        // Must be ignored
        return ValidationResult.Success;
    }
}
Run Code Online (Sandbox Code Playgroud)