I开发者_开发百科 have a DateTime TemplateEditor and I would like to add regex validation to it. I have a RegularExpression attribute that I could decorate the model with, but I dont want to have to decorate every datetime property in all my models with a regex.
Is there way I can my custom TemplateEditor add the appropriate unobstrusive tags when it renders the textbox for it?
Instead of adding your validator in the template, you should insert your validator using a custom ModelMetadataValidatorProvider
. First, create your ModelMetadataProvider class:
public class MyModelMetadataValidatorProvider : DataAnnotationsModelValidatorProvider
{
internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory = Create;
internal static Dictionary<Type, DataAnnotationsModelValidationFactory> AttributeFactories = new Dictionary<Type, DataAnnotationsModelValidationFactory>() {
{
typeof(RegularExpressionAttribute),
(metadata, context, attribute) => new RegularExpressionAttributeAdapter(metadata, context, (RegularExpressionAttribute)attribute)
}
};
internal static ModelValidator Create(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute)
{
return new DataAnnotationsModelValidator(metadata, context, attribute);
}
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
{
List<ModelValidator> vals = base.GetValidators(metadata, context, attributes).ToList();
// inject our new validator
if (metadata.ModelType.Name == "DateTime")
{
DataAnnotationsModelValidationFactory factory;
RegularExpressionAttribute regex = new RegularExpressionAttribute(
"^(((0?[1-9]|1[012])/(0?[1-9]|1\\d|2[0-8])|(0?[13456789]|1[012])/(29|30)|(0?[13578]|1[02])/31)/(19|[2-9]\\d)\\d{2}|0?2/29/((19|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|(([2468][048]|[3579][26])00)))$");
regex.ErrorMessage = "Invalid date format";
if (!AttributeFactories.TryGetValue(regex.GetType(), out factory))
factory = DefaultAttributeFactory;
vals.Add(factory(metadata, context, regex));
}
return vals.AsEnumerable();
}
}
Next, register your ModelMetadataValidatorProvider in Global.asax.cs
in Application_Start
.
ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new MyModelMetadataValidatorProvider());
Now, when you access a model, a RegularExpressionAttribte will be attached to each DateTime field. You can also extend this to provide a localized DateTime regular expression and message.
counsellorben
This is just elaborating (and fixing a couple little problems) on Consellorben's answer
public class ExtendedDataAnnotationsModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory = Create;
internal static Dictionary<Type, DataAnnotationsModelValidationFactory> AttributeFactories = new Dictionary<Type, DataAnnotationsModelValidationFactory>()
{
{
typeof(RegularExpressionAttribute),
(metadata, context, attribute) => new RegularExpressionAttributeAdapter(metadata, context, (RegularExpressionAttribute)attribute)
}
};
internal static ModelValidator Create(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute)
{
return new DataAnnotationsModelValidator(metadata, context, attribute);
}
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
{
if(!attributes.Any(i => i is RegularExpressionAttribute))
{
if (typeof(DateTime).Equals(metadata.ModelType) || (metadata.ModelType.IsGenericType && typeof(DateTime).Equals(metadata.ModelType.GetGenericArguments()[0])))
{
DataAnnotationsModelValidationFactory factory;
RegularExpressionAttribute regex = null;
switch (metadata.DataTypeName)
{
case "Date":
regex = new RegularExpressionAttribute(RegExPatterns.Date) { ErrorMessage = "Invalid date. Please use a m/d/yyyy format" };
break;
case "Time":
regex = new RegularExpressionAttribute(RegExPatterns.Time) { ErrorMessage = "Invalid time. Please use a h:mm format" };
break;
default: //DateTime
regex = new RegularExpressionAttribute(RegExPatterns.DateAndTime) { ErrorMessage = "Invalid date / time. Please use a m/d/yyyy h:mm format" };
break;
}
if (!AttributeFactories.TryGetValue(regex.GetType(), out factory))
factory = DefaultAttributeFactory;
yield return factory(metadata, context, regex);
}
}
}
}
and then register it in the global.asax like so:
ModelValidatorProviders.Providers.Add(new ExtendedDataAnnotationsModelValidatorProvider());
精彩评论