Want to change the Validation attribute at runtime ASP.Net MVC
-
Just checking, is it going to remove all the other Validations that I have put on other classes? Thanks, Abdul Aleem "There is already enough hatred in the world lets spread love, compassion and affection."
No. It checks that the instance being validated is the specific model class; that the property being validated is the
Code
property; and it only replaces theStringLength
validator on that property.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
No. It checks that the instance being validated is the specific model class; that the property being validated is the
Code
property; and it only replaces theStringLength
validator on that property.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
OK Got it, and you are saying that there is just one risk in it that it can be overridden in the derived classes, understandable, thanks a lot Richard for giving me the information. Thank you very much have a wonderful weekend buddy. Thanks, Abdul Aleem "There is already enough hatred in the world lets spread love, compassion and affection."
-
No. It checks that the instance being validated is the specific model class; that the property being validated is the
Code
property; and it only replaces theStringLength
validator on that property.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Hi Richard, One last thing, I have created the method in the following way:
public class CustomModelValidatorProvider : System.Web.Mvc.DataAnnotationsModelValidatorProvider { protected override IEnumerable GetValidators(System.Web.Mvc.ModelMetadata metadata, ControllerContext context, IEnumerable attributes) { if (metadata.Model is LookupTable) { LookupTable model = metadata.Model as LookupTable; if (metadata.PropertyName == GetPropertyName(() => model.CodeLength) && (model.CodeLength > 0)) { var newAttributes = new List(attributes); var stringLength = newAttributes.OfType().FirstOrDefault(); if (stringLength != null) { newAttributes.Remove(stringLength); if (model.CodeLength != 0) { newAttributes.Add(new StringLengthAttribute(model.CodeLength) { MinimumLength = model.CodeLength, ErrorMessage = @"The field {{0}} length must be at least {model.CodeLength}." }); } attributes = newAttributes; } } } return base.GetValidators(metadata, context, attributes); } public string GetPropertyName(Expression\> propertyLambda) { var me = propertyLambda.Body as MemberExpression; if (me == null) { throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'"); } return me.Member.Name; } }
can you please let me know how can I decorate or use it on my Model class, can you please give me that example, I am asking this question because this value is coming as null: metadata.PropertyName, so I am not able to compare with property name. So any help please? thank you very very much buddy - as I said earlier have a Wonderful weekend with family and friends buddy. Thanks, Abdul Aleem "There is already enough hatred in the world lets spread love, compassion and affection."
-
Hi Richard, One last thing, I have created the method in the following way:
public class CustomModelValidatorProvider : System.Web.Mvc.DataAnnotationsModelValidatorProvider { protected override IEnumerable GetValidators(System.Web.Mvc.ModelMetadata metadata, ControllerContext context, IEnumerable attributes) { if (metadata.Model is LookupTable) { LookupTable model = metadata.Model as LookupTable; if (metadata.PropertyName == GetPropertyName(() => model.CodeLength) && (model.CodeLength > 0)) { var newAttributes = new List(attributes); var stringLength = newAttributes.OfType().FirstOrDefault(); if (stringLength != null) { newAttributes.Remove(stringLength); if (model.CodeLength != 0) { newAttributes.Add(new StringLengthAttribute(model.CodeLength) { MinimumLength = model.CodeLength, ErrorMessage = @"The field {{0}} length must be at least {model.CodeLength}." }); } attributes = newAttributes; } } } return base.GetValidators(metadata, context, attributes); } public string GetPropertyName(Expression\> propertyLambda) { var me = propertyLambda.Body as MemberExpression; if (me == null) { throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'"); } return me.Member.Name; } }
can you please let me know how can I decorate or use it on my Model class, can you please give me that example, I am asking this question because this value is coming as null: metadata.PropertyName, so I am not able to compare with property name. So any help please? thank you very very much buddy - as I said earlier have a Wonderful weekend with family and friends buddy. Thanks, Abdul Aleem "There is already enough hatred in the world lets spread love, compassion and affection."
You register the provider in
Global.asax.cs
:ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add( new CustomValidatorProvider() );I'd expect to see the
PropertyName
set tonull
for the class-level validation, but I'd expect the method to be called again for each property on the class. You're currently checking whether the validators are for theCodeLength
property; you need to customise the validators for theCode
property instead.if (metadata.PropertyName == GetPropertyName(() => model.Code) && ...
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
You register the provider in
Global.asax.cs
:ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add( new CustomValidatorProvider() );I'd expect to see the
PropertyName
set tonull
for the class-level validation, but I'd expect the method to be called again for each property on the class. You're currently checking whether the validators are for theCodeLength
property; you need to customise the validators for theCode
property instead.if (metadata.PropertyName == GetPropertyName(() => model.Code) && ...
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
ModelValidatorProviders.Providers.Clear(); ModelValidatorProviders.Providers.Add( new CustomValidatorProvider() ); I did this registration in the Global.asax.cs file, in the Application_Start() event. And even if I changed the Condition to:
if (metadata.PropertyName == GetPropertyName(() => model.Code) && (model.CodeLength > 0))
Still I am getting the metadata.PropertyName null always, can you please suggest me what am I missing? Just asking am I using any wrong namespace in references?, Because it was saying there is an ambiguous class names and those classes present in both the following namespaces using System.Web.ModelBinding; using System.Web.Mvc; Am I using any wrong namespace or something like that kind of error, I am not understanding why is it giving metadata.PropertyName as null in all the cases? Thanks, Abdul Aleem "There is already enough hatred in the world lets spread love, compassion and affection."
-
ModelValidatorProviders.Providers.Clear(); ModelValidatorProviders.Providers.Add( new CustomValidatorProvider() ); I did this registration in the Global.asax.cs file, in the Application_Start() event. And even if I changed the Condition to:
if (metadata.PropertyName == GetPropertyName(() => model.Code) && (model.CodeLength > 0))
Still I am getting the metadata.PropertyName null always, can you please suggest me what am I missing? Just asking am I using any wrong namespace in references?, Because it was saying there is an ambiguous class names and those classes present in both the following namespaces using System.Web.ModelBinding; using System.Web.Mvc; Am I using any wrong namespace or something like that kind of error, I am not understanding why is it giving metadata.PropertyName as null in all the cases? Thanks, Abdul Aleem "There is already enough hatred in the world lets spread love, compassion and affection."
Sorry, I picked the wrong property to test against. Replace
metadata.Model
withmetadata.Container
:if (metadata.Model is ServiceFunctionCategoryLKP model && metadata.PropertyName == nameof(model.Code) && model.CodeLength >= 0)
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Sorry, I picked the wrong property to test against. Replace
metadata.Model
withmetadata.Container
:if (metadata.Model is ServiceFunctionCategoryLKP model && metadata.PropertyName == nameof(model.Code) && model.CodeLength >= 0)
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
But still the attributes value in IEnumerable attributes coming as null when I already have one Attribute on that class and when I try to expan the attributes collection object, it shows me "Enumeration yielded no results" in the end.
public class LookupTable { public int Id { get; set; } \[Required(ErrorMessage = "Code is required.")\] public string Code { get; set; } \[Required(ErrorMessage = "Description is required.")\] public string Description { get; set; } public int? ForeignKeyId { get; set; } public string ForeignKeyValue { get; set; } public DateTime? CreatedDate {get;set;} public string CreatedBy {get;set;} public int CodeLength { get; set; } }
Do I need to add anymore Attributes to the Code Property?, what am I missing here my friend? Even after I changed my function to have Container instead of Model, still I get null at metadata.PropertyName Always metadata.PropertyName is coming as null irrespective of any changes I do at if (metadata.PropertyName == GetPropertyName(() => model.Code) && (model.CodeLength > 0)) in the below function and attributes is also coming as null.
protected override IEnumerable GetValidators(System.Web.Mvc.ModelMetadata metadata, ControllerContext context, IEnumerable attributes) { if (metadata.Model is LookupTable) { LookupTable model = metadata.Container as LookupTable; if (metadata.PropertyName == GetPropertyName(() => model.Code) && (model.CodeLength > 0)) { var newAttributes = new List(attributes); var stringLength = newAttributes.OfType().FirstOrDefault(); if (stringLength != null) { newAttributes.Remove(stringLength); if (model.CodeLength != 0) { newAttributes.Add(new StringLengthAttribute(model.CodeLength) { MinimumLength = model.CodeLength, ErrorMessage = @"The field {{0}} length must be at least {model.CodeLength}." }); } attributes = newAttributes;
-
But still the attributes value in IEnumerable attributes coming as null when I already have one Attribute on that class and when I try to expan the attributes collection object, it shows me "Enumeration yielded no results" in the end.
public class LookupTable { public int Id { get; set; } \[Required(ErrorMessage = "Code is required.")\] public string Code { get; set; } \[Required(ErrorMessage = "Description is required.")\] public string Description { get; set; } public int? ForeignKeyId { get; set; } public string ForeignKeyValue { get; set; } public DateTime? CreatedDate {get;set;} public string CreatedBy {get;set;} public int CodeLength { get; set; } }
Do I need to add anymore Attributes to the Code Property?, what am I missing here my friend? Even after I changed my function to have Container instead of Model, still I get null at metadata.PropertyName Always metadata.PropertyName is coming as null irrespective of any changes I do at if (metadata.PropertyName == GetPropertyName(() => model.Code) && (model.CodeLength > 0)) in the below function and attributes is also coming as null.
protected override IEnumerable GetValidators(System.Web.Mvc.ModelMetadata metadata, ControllerContext context, IEnumerable attributes) { if (metadata.Model is LookupTable) { LookupTable model = metadata.Container as LookupTable; if (metadata.PropertyName == GetPropertyName(() => model.Code) && (model.CodeLength > 0)) { var newAttributes = new List(attributes); var stringLength = newAttributes.OfType().FirstOrDefault(); if (stringLength != null) { newAttributes.Remove(stringLength); if (model.CodeLength != 0) { newAttributes.Add(new StringLengthAttribute(model.CodeLength) { MinimumLength = model.CodeLength, ErrorMessage = @"The field {{0}} length must be at least {model.CodeLength}." }); } attributes = newAttributes;
I don't know what to suggest. I've tested the code, and it works. :confused: If you're not putting a static
StringLength
attribute on the property, you'll need to theif (model.CodeLength != 0)
block outside of theif (stringLength != null)
block:if (stringLength != null)
{
newAttributes.Remove(stringLength);
}if (model.CodeLength != 0)
{
newAttributes.Add(new StringLengthAttribute(model.CodeLength)
{
MinimumLength = model.CodeLength,
ErrorMessage = @"The field {{0}} length must be at least {model.CodeLength}."
});
}attributes = newAttributes;
But if you're never seeing a value in
metadata.PropertyName
, then there's something else going on. I assume you have actually enabled unobtrusive validation?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
I don't know what to suggest. I've tested the code, and it works. :confused: If you're not putting a static
StringLength
attribute on the property, you'll need to theif (model.CodeLength != 0)
block outside of theif (stringLength != null)
block:if (stringLength != null)
{
newAttributes.Remove(stringLength);
}if (model.CodeLength != 0)
{
newAttributes.Add(new StringLengthAttribute(model.CodeLength)
{
MinimumLength = model.CodeLength,
ErrorMessage = @"The field {{0}} length must be at least {model.CodeLength}."
});
}attributes = newAttributes;
But if you're never seeing a value in
metadata.PropertyName
, then there's something else going on. I assume you have actually enabled unobtrusive validation?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
No I have not done this: unobtrusive validation, can you please let me know how to do it only on one particular class and property that I want. Thanks, Abdul Aleem "There is already enough hatred in the world lets spread love, compassion and affection."
-
No I have not done this: unobtrusive validation, can you please let me know how to do it only on one particular class and property that I want. Thanks, Abdul Aleem "There is already enough hatred in the world lets spread love, compassion and affection."
You enable unobtrusive validation for the site in the
web.config
file:<configuration>
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>This should be included by default, but it depends on the template you started with. Creating a MVC 3 Application with Razor and Unobtrusive JavaScript ⇒ Enabling Client-Side Validation[^] I've created a minimal sample project in VS2017 which works as expected; you can download it from OneDrive[^].
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer