ASP.NET MVC ValidationAttribute Get a different display property name

I created my own CompareLessThan validation attribute by copying ASP.NET MVC 3 CompareAttribute and instead of checking for equality, I verify that one property is smaller than the other. If there is an error on the client side, the message "{0} must be less than {1}" is displayed to the user.

My model is configured as follows with Display attributes referencing a resource file.

[CompareLessThan("AmountAvailable", ErrorMessageResourceName="CompareLessThan", ErrorMessageResourceType = typeof(Resources.ValidationMessages))] [Display(Name = "Amount", ResourceType = typeof(Resources.Labels))] public decimal Amount { get; set; } [Display(Name = "AmountAvailable", ResourceType = typeof(Resources.Labels))] public decimal AmountAvailable { get; set; } 

Then the GetClientValidationRules spot check method is exactly the same as in CompareAttribute

 public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(OtherProperty), this.AllowEquality); } 

Here we create an error message that will be displayed to the user if there is a problem. I can get the display name from the resource file for the property that is decorated with my CompareLessThan custom attribute, but my question is, how can I get the display name of the β€œother” property with which we are comparing? In the IsValid method, we refer to a validationContext from which I can generate a PropertyInfo object for the "other" property, and I think I get the display name. But in GetClientValidationRules I do not have access to this.

I could always just pass a different value for the display name of another property, but I was hoping there would be a way to get it, as I already specify it with data annotations.

Any ideas?

+6
source share
3 answers

The answer provided by nemesv does not work as the metadata.Model property is 0. But through the metadata we have the full name of the model, so you can create a new instance of this model and then create a new DataAnnonationsModelMetadataProvider from this create instance. From there we can get the display name of another property.

 public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { Type type = Type.GetType(metadata.ContainerType.FullName); var model = Activator.CreateInstance(type); var provider = new DataAnnotationsModelMetadataProvider(); var otherMetaData = provider.GetMetadataForProperty(() => model, type, this.OtherProperty); this.otherPropertyDisplayName = otherMetaData.DisplayName; yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(this.OtherProperty), this.AllowEquality); } 

I really don't like this solution (although it works), as it seems there should be a better way. Does anyone have any other ideas?

+5
source

As in ASP.NET MVC 4, I managed to get another property:

 PropertyInfo otherPropertyInfo = this.Metadata.ContainerType.GetProperty(attribute.DependentProperty); 

Then I got the Display attribute from the property:

 var displayAttribute = otherPropertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true). FirstOrDefault() as DisplayProperty; 

In your case:

 // GetName() is important to get the translated name if you're using a resource file... this.otherPropertyDisplayName = displayAttribute.GetName(); 

GetName() link:

http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.displayattribute.name%28v=vs.95%29.aspx

+6
source

I have not tried, but you can get the model properties using the metadata.Properties property

 metadata.Properties.Single(p => p.PropertyName == "OtherPropName").DisplayName; 

EDIT: since the properties are empty, you can always do it (albeit very elegantly). You can generate metadata for yourself.

 var provider = new DataAnnotationsModelMetadataProvider(); var otherMetaData = provider.GetMetadataForProperty(() => metaData.Model, metaData.ModelType, "OtherPropertyName"); 
+4
source

Source: https://habr.com/ru/post/899262/


All Articles