Unable to set membernames from custom validation attribute in MVC2

后端 未结 4 2213
甜味超标
甜味超标 2020-12-11 17:04

I have created a custom validation attribute by subclassing ValidationAttribute. The attribute is applied to my viewmodel at the class level as it needs to validate more tha

相关标签:
4条回答
  • 2020-12-11 17:16

    You need to set the ErrorMessage property, so for example:

     public class DOBValidAttribute : ValidationAttribute
    {
        private static string _errorMessage = "Date of birth is a required field.";
    
        public DOBValidAttribute() : base(_errorMessage)
        {
    
        }
    //etc......overriding IsValid....
    
    0 讨论(0)
  • 2020-12-11 17:18

    When returning the validation result use the two parameter constructor. Pass it an array with the context.MemberName as the only value. Hope this helps

    <AttributeUsage(AttributeTargets.Property Or AttributeTargets.Field, AllowMultiple:=False)>
    
    
    Public Class NonNegativeAttribute
    Inherits ValidationAttribute
    Public Sub New()
    
    
    End Sub
    Protected Overrides Function IsValid(num As Object, context As ValidationContext) As ValidationResult
        Dim t = num.GetType()
        If (t.IsValueType AndAlso Not t.IsAssignableFrom(GetType(String))) Then
    
            If ((num >= 0)) Then
                Return ValidationResult.Success
            End If
            Return New ValidationResult(context.MemberName & " must be a positive number",     New String() {context.MemberName})
    
        End If
    
        Throw New ValidationException(t.FullName + " is not a valid type. Must be a number")
    End Function
    
    End Class
    
    0 讨论(0)
  • 2020-12-11 17:21

    I am not aware of an easy way fix this behavior. That's one of the reasons why I hate data annotations. Doing the same with FluentValidation would be a peace of cake:

    public class ExampleViewModelValidator: AbstractValidator<ExampleViewModel>
    {
        public ExampleViewModelValidator()
        {
            RuleFor(x => x.EndDate)
                .GreaterThan(x => x.StartDate)
                .WithMessage("end date must be after start date");
        }
    }
    

    FluentValidation has great support and integration with ASP.NET MVC.

    0 讨论(0)
  • 2020-12-11 17:24

    hello everybody.

    Still looking for solution?

    I've solved the same problem today. You have to create custom validation attribute which will validate 2 dates (example below). Then you need Adapter (validator) which will validate model with your custom attribute. And the last thing is binding adapter with attribute. Maybe some example will explain it better than me :)

    Here we go:

    DateCompareAttribute.cs:

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public class DateCompareAttribute : ValidationAttribute
    {
        public enum Operations
        {
            Equals,            
            LesserThan,
            GreaterThan,
            LesserOrEquals,
            GreaterOrEquals,
            NotEquals
        };
    
        private string _From;
        private string _To;
        private PropertyInfo _FromPropertyInfo;
        private PropertyInfo _ToPropertyInfo;
        private Operations _Operation;
    
        public string MemberName
        {
            get
            {
                return _From;
            }
        }
    
        public DateCompareAttribute(string from, string to, Operations operation)
        {
            _From = from;
            _To = to;
            _Operation = operation;
    
            //gets the error message for the operation from resource file
            ErrorMessageResourceName = "DateCompare" + operation.ToString();
            ErrorMessageResourceType = typeof(ValidationStrings);
        }
    
        public override bool IsValid(object value)
        {
            Type type = value.GetType();
    
            _FromPropertyInfo = type.GetProperty(_From);
            _ToPropertyInfo = type.GetProperty(_To);
    
            //gets the values of 2 dates from model (using reflection)
            DateTime? from = (DateTime?)_FromPropertyInfo.GetValue(value, null);
            DateTime? to = (DateTime?)_ToPropertyInfo.GetValue(value, null);
    
            //compare dates
            if ((from != null) && (to != null))
            {
                int result = from.Value.CompareTo(to.Value);
    
                switch (_Operation)
                {
                    case Operations.LesserThan:
                        return result == -1;
                    case Operations.LesserOrEquals:
                        return result <= 0;
                    case Operations.Equals:
                        return result == 0;
                    case Operations.NotEquals:
                        return result != 0;
                    case Operations.GreaterOrEquals:
                        return result >= 0;
                    case Operations.GreaterThan:
                        return result == 1;
                }
            }
    
            return true;
        }
    
        public override string FormatErrorMessage(string name)
        {
            DisplayNameAttribute aFrom = (DisplayNameAttribute)_FromPropertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
            DisplayNameAttribute aTo = (DisplayNameAttribute)_ToPropertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
    
            return string.Format(ErrorMessageString,
                !string.IsNullOrWhiteSpace(aFrom.DisplayName) ? aFrom.DisplayName : _From,
                !string.IsNullOrWhiteSpace(aTo.DisplayName) ? aTo.DisplayName : _To);
        }
    }
    

    DateCompareAttributeAdapter.cs:

    public class DateCompareAttributeAdapter : DataAnnotationsModelValidator<DateCompareAttribute> 
    {
        public DateCompareAttributeAdapter(ModelMetadata metadata, ControllerContext context, DateCompareAttribute attribute)
            : base(metadata, context, attribute) {
        }
    
        public override IEnumerable<ModelValidationResult> Validate(object container)
        {
            if (!Attribute.IsValid(Metadata.Model))
            {
                yield return new ModelValidationResult
                {
                    Message = ErrorMessage,
                    MemberName = Attribute.MemberName
                };
            }
        }
    }
    

    Global.asax:

    protected void Application_Start()
    {
        // ...
        DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(DateCompareAttribute), typeof(DateCompareAttributeAdapter));
    }
    

    CustomViewModel.cs:

    [DateCompare("StartDateTime", "EndDateTime", DateCompareAttribute.Operations.LesserOrEquals)]
    public class CustomViewModel
    {
        // Properties...
    
        public DateTime? StartDateTime
        {
            get;
            set;
        }
    
        public DateTime? EndDateTime
        {
            get;
            set;
        }
    }
    
    0 讨论(0)
提交回复
热议问题