簡體   English   中英

我可以將Model屬性用作Range驗證屬性的一部分

[英]Can I use a Model property as part of a Range validation attribute

在我的模型中,我有一個具有以下屬性的對象。

[Range(typeof(int), "2014", "2024", ErrorMessage = "{0} can only be beteween {1} and {2}")]
public int FiscalYear { get; set; }

下限和上限值分別為2014年和2024年。 但是,我不希望使用這些固定值,而是希望它們基於模型中的另一個屬性。

因此,例如,如果我有一個屬性CurrentFiscalYear ,我的假設Range屬性將如下所示。

[Range(typeof(int), CurrentFiscalYear, CurrentFiscalYear + 10, ErrorMessage = "{0} can only be beteween {1} and {2}")]
public int FiscalYear { get; set; }

這樣的事情可能嗎? 或者必須在編譯時提供較低和較高的值?

不,這是不可能的。 屬性參數值只是“編譯時常量”值。 換句話說,編譯程序時必須知道參數的實際值。

來自MSDN - 屬性教程

屬性參數限制為以下類型的常量值:

  • 簡單類型(bool,byte,char,short,int,long,float和double)
  • 系統類型
  • 枚舉
  • object(對象類型的屬性參數的參數必須是上述類型之一的常量值。)
  • 任何上述類型的一維陣列

這是.NET 1.1的文檔,但沒有改變。

解決方法

這根本沒有經過測試,但您可以創建一個自定義ValidationAttribute ,它在測試有效性時獲取范圍和模型屬性名稱,這些屬性名稱的值將添加到范圍值中。 您可以創建內部標准RangeAttribute來為您完成工作,甚至通過實現IClientValidatable保持客戶端驗證的工作:

public sealed class ShiftedRangeAttribute : ValidationAttribute
{
    public string MinShiftProperty { get; private set; }
    public string MaxShiftProperty { get; private set; }

    public double Minimum { get; private set; }
    public double Maximum { get; private set; }

    public ShiftedRangeAttribute(double minimum, double maximum, string minShiftProperty, string maxShiftProperty)
    {
        this.Minimum = minimum;
        this.Maximum = maximum;
        this.MinShiftProperty = minShiftProperty;
        this.MaxShiftProperty = maxShiftProperty;
    }

    public ShiftedRangeAttribute(int minimum, int maximum, string minShiftProperty, string maxShiftProperty)
    {
        this.Minimum = minimum;
        this.Maximum = maximum;
        this.MinShiftProperty = minShiftProperty;
        this.MaxShiftProperty = maxShiftProperty;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        RangeAttribute attr = this.CreateRangeAttribute(validationContext.ObjectInstance);
        return attr.GetValidationResult(value, validationContext);
    }

    internal RangeAttribute CreateRangeAttribute(object model)
    {
        double min = this.Minimum;
        if (this.MinShiftProperty != null)
        {
            min += Convert.ToDouble(model.GetType().GetProperty(this.MinShiftProperty).GetValue(model));
        }

        double max = this.Maximum;
        if (this.MaxShiftProperty != null)
        {
            max += Convert.ToDouble(model.GetType().GetProperty(this.MaxShiftProperty).GetValue(model));
        }

        return new RangeAttribute(min, max);
    }
}

如果您希望它與客戶端驗證一起使用,您還將創建DataAnnotationsModelValidator並在global.asax Application_Start()注冊它,以確保輸出客戶端驗證HTML屬性。 你可以再次欺騙並使用內置的RangeAttributeAdapter來幫助你,因為在Javascript中它最終只是一個范圍驗證器:

public class ShiftedRangeAttributeAdapter : DataAnnotationsModelValidator<ShiftedRangeAttribute>
{
    public ShiftedRangeAttributeAdapter(ModelMetadata metadata, ControllerContext context, ShiftedRangeAttribute attribute)
        : base(metadata, context, attribute)
    {
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        RangeAttribute attr = this.Attribute.CreateRangeAttribute(this.Metadata.Container);
        return new RangeAttributeAdapter(this.Metadata, this.ControllerContext, attr).GetClientValidationRules();
    }
}

...

DataAnnotationsModelValidatorProvider.RegisterAdapter(
    typeof(ShiftedRangeAttribute), typeof(ShiftedRangeAttributeAdapter));

請注意,只有包含屬性的類是頂級模型類(存儲在Metadata.Container中)時,客戶端驗證代碼才有效。 您無法訪問當前屬性的“父級”。 您需要做更多的工作來創建一個自定義的jQuery驗證器來正確處理這個問題。

然后你可以這樣使用它:

[ShiftedRange(0, 10, "CurrentFiscalYear", "CurrentFiscalYear", ErrorMessage = "{0} can only be beteween {1} and {2}")]
public int FiscalYear { get; set; }

編輯:測試后修復了一些錯誤

這可以通過編寫自定義ValidationAttribute來完成,實現可以這樣完成:

public sealed class FiscalYearAttribute : ValidationAttribute
{
    public string CurrentFiscalYear { get; set; }

    public override bool IsValid(object value)
    {
        var currentFiscalYearString = HttpContext.Current.Request[CurrentFiscalYear];
        var currentFiscalYear = int.Parse(currentFiscalYearString);
        var fiscalYear = (int) value;

        return fiscalYear >=  currentFiscalYear && fiscalYear <= currentFiscalYear + 10;
    }

    public override string FormatErrorMessage(string name)
    {
        return name + " error description here.";
    }
}

用法:

[Required]
[Display(Name = "CurrentFiscalYear")]
public int CurrentFiscalYear { get; set; }

[Display(Name = "FiscalYear")]
[FiscalYear(CurrentFiscalYear = "CurrentFiscalYear")]
public int FiscalYear { get; set; }

暫無
暫無

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

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