MVC验证:低于/高于其他值

30

在MVC.Net中,如何最好地验证模型,其中我想接受最小/最大值。

不是针对字段的个别min/max值。而是针对用户指定最小/最大值的单独字段。

public class FinanceModel{
   public int MinimumCost {get;set;}
   public int MaximumCost {get;set;}
}

所以我需要确保MinimumCost始终小于Maximum cost。

5个回答

29

有一个名为 Foolproof 的 NuGet 包,可以为您提供这些注释。话虽如此 - 编写自定义属性既简单又是一种很好的实践。

使用 Foolproof 如下:

public class FinanceModel{
   public int MinimumCost {get;set;}

   [GreaterThan("MinimumCost")]
   public int MaximumCost {get;set;}
}

1
接受自定义验证器只是作为学习工具。感谢提供 Foolproof 的参考。无论如何,我都会将其保留在手边。 - Ben Ford
Foolproof似乎不接受自定义错误消息。 - Manuel Reis
2
自定义错误消息的指定方式如下[GreaterThan("MinimumCost"), ErrorMessage = "必须大于最低成本"] - Chris
5
这里稍作更正:错误信息应该是这样的,[GreaterThan("MinimumCost", ErrorMessage = "必须大于最低成本")]。 - César León

27
你可以在这里使用自定义验证属性,以下是我的日期示例。但是你也可以将其用于整数。 首先,这是模型:
public DateTime Beggining { get; set; }

[IsDateAfterAttribute("Beggining", true, ErrorMessageResourceType = typeof(LocalizationHelper), ErrorMessageResourceName = "PeriodErrorMessage")]
public DateTime End { get; set; }

这里是属性本身:

public sealed class IsDateAfterAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string testedPropertyName;
    private readonly bool allowEqualDates;

    public IsDateAfterAttribute(string testedPropertyName, bool allowEqualDates = false)
    {
        this.testedPropertyName = testedPropertyName;
        this.allowEqualDates = allowEqualDates;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var propertyTestedInfo = validationContext.ObjectType.GetProperty(this.testedPropertyName);
        if (propertyTestedInfo == null)
        {
            return new ValidationResult(string.Format("unknown property {0}", this.testedPropertyName));
        }

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

        if (value == null || !(value is DateTime))
        {
            return ValidationResult.Success;
        }

        if (propertyTestedValue == null || !(propertyTestedValue is DateTime))
        {
            return ValidationResult.Success;
        }

        // Compare values
        if ((DateTime)value >= (DateTime)propertyTestedValue)
        {
            if (this.allowEqualDates && value == propertyTestedValue)
            {
                return ValidationResult.Success;
            }
            else if ((DateTime)value > (DateTime)propertyTestedValue)
            {
                return ValidationResult.Success;
            }
        }

        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = this.ErrorMessageString,
            ValidationType = "isdateafter"
        };
        rule.ValidationParameters["propertytested"] = this.testedPropertyName;
        rule.ValidationParameters["allowequaldates"] = this.allowEqualDates;
        yield return rule;
    }

9
您需要在客户端验证中完成此示例:jQuery.validator.addMethod('isdateafter', function (value, element, params) { if (!/Invalid|NaN/.test(new Date(value))) { return new Date(value) > new Date(); } return isNaN(value) && isNaN($(params).val()) || (parseFloat(value) > parseFloat($(params).val())); }, ''); jQuery.validator.unobtrusive.adapters.add('isdateafter', {}, function (options) { options.rules['isdateafter'] = true; options.messages['isdateafter'] = options.message; }); - LoBo
似乎由于if (this.allowEqualDates && value == propertyTestedValue)这一行存在错误。这个可以正常工作:if (this.allowEqualDates && value.Equals(propertyTestedValue)),或者甚至是这个:if (this.allowEqualDates && (DateTime)value == (DateTime)propertyTestedValue) - publicgk

6

对于客户端验证,使用allowEqualDates和propertyTested参数(补充Boranas上面的答案,但过长无法在评论中回复):

// definition for the isdateafter validation rule
if ($.validator && $.validator.unobtrusive) {
    $.validator.addMethod('isdateafter', function (value, element, params) {
        value = Date.parse(value);
        var otherDate = Date.parse($(params.compareTo).val());
        if (isNaN(value) || isNaN(otherDate))
            return true;
        return value > otherDate || (value == otherDate && params.allowEqualDates);
    });
    $.validator.unobtrusive.adapters.add('isdateafter', ['propertytested', 'allowequaldates'], function (options) {
        options.rules['isdateafter'] = {
            'allowEqualDates': options.params['allowequaldates'],
            'compareTo': '#' + options.params['propertytested']
        };
        options.messages['isdateafter'] = options.message;
    });
}

更多信息:非侵入式验证jQuery 验证

1
在VB中针对整数的模型:

模型

<UtilController.IsIntegerGreatherOrEqualThan("PropertyNameNumberBegins", "PeriodErrorMessage")>
        Public Property PropertyNameNumberEnds As Nullable(Of Integer)

VALIDATION

Public Class IsIntegerGreatherOrEqualThan
        Inherits ValidationAttribute

        Private otherPropertyName As String
        Private errorMessage As String

        Public Sub New(ByVal otherPropertyName As String, ByVal errorMessage As String)
            Me.otherPropertyName = otherPropertyName
            Me.errorMessage = errorMessage
        End Sub

        Protected Overrides Function IsValid(thisPropertyValue As Object, validationContext As ValidationContext) As ValidationResult

            Dim otherPropertyTestedInfo = validationContext.ObjectType.GetProperty(Me.otherPropertyName)

            If (otherPropertyTestedInfo Is Nothing) Then
                Return New ValidationResult(String.Format("unknown property {0}", Me.otherPropertyName))
            End If

            Dim otherPropertyTestedValue = otherPropertyTestedInfo.GetValue(validationContext.ObjectInstance, Nothing)

            If (thisPropertyValue Is Nothing) Then
                Return ValidationResult.Success
            End If

            ''  Compare values
            If (CType(thisPropertyValue, Integer) >= CType(otherPropertyTestedValue, Integer)) Then
                Return ValidationResult.Success
            End If

            ''  Wrong
            Return New ValidationResult(errorMessage)
        End Function
    End Class

我从代码中删除了“FormatErrorMessage”,因为它会添加“'The Field'+ {errorMessage} + 'is invalid'”。我正在进行日期检查,所以我用日期替换了整数。效果很好,也节省了我的时间。谢谢。 - PHBeagle
所以 errorMessage 显示了错误的信息?当我使用它时,我没有注意到它。 - Dani
不是真的错了,只是多余的措辞。通过使用“返回新的ValidationResult(errorMessage)”就可以了。 - PHBeagle

-8

为什么你没有使用范围验证器。 语法:

    [Range(typeof(int), "0", "100", ErrorMessage = "{0} can only be between {1} and {2}")]
    public int Percentage { get; set; }

2
如果您查看我的原始问题或现有答案,您会发现我试图验证的情况是用户可以选择上限/下限,而不是当他们必须输入现有高/低值之间的值时。 - Ben Ford

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