簡體   English   中英

使用C#和Web API並使用帶有驗證上下文的私有訪問修飾符的自定義必需屬性

[英]Custom required attribute with C# & Web API and using private access modifier with validation context

我具有以下自定義必填屬性:

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;
        }
    }
}

我要實現的目標是,我想根據模型中的屬性有條件地進行驗證。 它還需要足夠通用,才能在多個模型上重復使用。 當指定的屬性具有特定值(我在屬性中指定)時,需要的自定義驗證必須與這些值匹配。 例如在此模型中:

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()
    {

    }
}

如果IsBooking屬性為true ,那么我希望需要StockId ,但是如果它為false ,則應該要求Amount

目前,我有解決方案,但是有兩個問題:

  1. 我不希望_Mappings屬性具有依賴性。 有誰知道我將如何按照自己的方式去做?
  2. 如果必須按_Mappings使用_Mappings屬性,是否可以將其用作private訪問修飾符? 當前,只有_Mappingspublic ,我才能使我的解決方案起作用,因為validationContext.ObjectType.GetProperty("_Mappings")無法找到private修飾符。 (如果要在Web API響應中將此模型序列化為JSON,那么理想情況下,我將不希望發送驗證映射。)

您可以將_Mappings私有。 更改此:

var propertyTestedInfo = validationContext.ObjectType.GetProperty("_Mappings");

var propertyTestedInfo = validationContext.ObjectType.GetProperty(
    "_Mappings", 
    BindingFlags.NonPublic | BindingFlags.Instance);

要使用此重載獲取私有屬性。

public PropertyInfo Type.GetProperty(string name, BindingFlags bindingAttr)

另外,如果我從您當前的代碼中正確地找到了您的意圖(並且假設您在當前_Mappings詞典中的意思是“ StockID”,其中它表示“ ReleasedStockID”),那么您可以完全不用_Mappings

public class RequiredIfAttribute : RequiredAttribute
{
    private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
    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)
    {
        // Property info for the specified dependent property.
        var propertyTestedInfo = validationContext.ObjectType.GetProperty(this._DependentProperty, Flags);
        if (propertyTestedInfo == null)
            return new ValidationResult(string.Format("{0} needs to be exist in this object.", this._DependentProperty));

        // And its value
        var dependendValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);
        if (dependendValue == null)
            return new ValidationResult(string.Format("{0} needs to be populated.", this._DependentProperty));

        // If it meets the specified "If" predicate value
        if (dependendValue.Equals(this._TargetValue))
        {
            // Get the property being validated.
            var validatedProperty = validationContext.ObjectType.GetProperty(validationContext.MemberName, Flags);
            if (validatedProperty != null)
            {
                // Debug sanity check
                AssertHasThisAttribute(validatedProperty);

                // Get the property's value.
                var validatedPropertyValue = validatedProperty.GetValue(validationContext.ObjectInstance, null);

                // And check that is is not null
                if (validatedPropertyValue != null)
                    return ValidationResult.Success;
            }
            // validation failed.
            return new ValidationResult(string.Empty);
        }

        // Must be ignored
        return ValidationResult.Success;
    }

    // Debug only sanity check.
    [Conditional("DEBUG")]
    private void AssertHasThisAttribute(PropertyInfo prop)
    {
        var attr = prop.GetCustomAttributes<RequiredIfAttribute>().FirstOrDefault();
        Debug.Assert(attr != null);
        Debug.Assert(attr._TargetValue == _TargetValue);
        Debug.Assert(attr._DependentProperty == _DependentProperty);
    }
}

您不必使用_Mappings屬性,下面的代碼檢查相關的Attribute是否具有與您在屬性中指定的值匹配的值,如果存在匹配項,則檢查要驗證的屬性是否具有值。

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;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM