问题
I have a model with properties that look like this:
public class YourDetails {
[Required(ErrorMessage = "Code is required")]
[StringLength(10, ErrorMessage = "Code length is wrong", MinimumLength = 2)]
[Range(0, int.MaxValue, ErrorMessage = "Please enter a value bigger than {1}")]
public int Code { get; set; }
}
The UI validation is setup the usual out of the box way with unobtrusive JS validation plugin.
The issue: I have 2 navigation actions, back and next. Next is fine, validation fires when things are wrong, and when things are right i.e. .isValid()
returns true, the data is passed to the DB service etc etc.
However when I press 'back' I have a requirement to validate the form/ViewModel differently prior to saving. I.e. make sure Code
is a positive integer, but don't bother with the Required
or StringLength
validation.
So basically I want to validate fully on Next but partially on Back. Is that possible?
回答1:
When I've done something similar in the past the easiest way i found was to use fluent validation http://fluentvalidation.codeplex.com/wikipage?title=mvc. You can pass parameters to the validator and switch to different rule sets.
回答2:
I've used the following conditional "Required" & "StringLength" attributes in the past and they work well.
Required If Attribute:
using System;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
namespace Website.Core.Mvc.DataAnnotations
{
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class RequiredIfAttribute : RequiredAttribute
{
public string OtherProperty { get; set; }
public object OtherPropertyValue { get; set; }
public RequiredIfAttribute(string otherProperty, object value)
: base()
{
OtherProperty = otherProperty;
OtherPropertyValue = value;
}
private object _TypeId = new object();
public override object TypeId
{
get
{
return _TypeId;
}
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
PropertyInfo property = validationContext.ObjectType.GetProperty(this.OtherProperty);
if (property == null)
{
return new ValidationResult(this.OtherProperty + " not found");
}
// Get
object actualOtherPropertyValue = property.GetValue(validationContext.ObjectInstance, null);
// If the other property matches the expected value then validate as normal
if (IsRequired(OtherPropertyValue, actualOtherPropertyValue))
{
// Call base and validate required as normal
ValidationResult isValid = base.IsValid(value, validationContext);
return isValid;
}
return ValidationResult.Success;
}
protected virtual bool IsRequired(object otherPropertyValue, object actualOtherPropertyValue)
{
return object.Equals(OtherPropertyValue, actualOtherPropertyValue);
}
}
}
String Length If Attribute:
using System.ComponentModel.DataAnnotations;
using System.Reflection;
namespace Website.Core.Mvc.DataAnnotations
{
public class StringLengthIfAttribute : StringLengthAttribute
{
public string OtherProperty { get; set; }
public object OtherPropertyValue { get; set; }
public StringLengthIfAttribute(int maximumLength, string otherProperty, object value)
: base(maximumLength)
{
OtherProperty = otherProperty;
OtherPropertyValue = value;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
PropertyInfo property = validationContext.ObjectType.GetProperty(this.OtherProperty);
if (property == null)
{
return new ValidationResult(this.OtherProperty + " not found");
}
// Get
object actualOtherPropertyValue = property.GetValue(validationContext.ObjectInstance, null);
// If the other property matches the expected value then validate as normal
if (object.Equals(OtherPropertyValue, actualOtherPropertyValue))
{
// Call base and validate required as normal
return base.IsValid(value, validationContext);
}
return null;
}
}
}
Example Usage:
public class MyModel
{
[RequiredIf("IsBack", false)]
public string Name { get; set; }
public bool IsBack { get; set; }
}
来源:https://stackoverflow.com/questions/15811559/asp-net-mvc-choose-which-validation-annotations-to-use