Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Want to change the Validation attribute at runtime ASP.Net MVC

Want to change the Validation attribute at runtime ASP.Net MVC

Scheduled Pinned Locked Moved C#
helpasp-netcsharparchitecturequestion
15 Posts 3 Posters 19 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Richard DeemingR Richard Deeming

    Not easily, but it can be done. You're going to need to create a custom DataAnnotationsModelValidatorProvider, and modify the rules it returns. validation - Possible to change Data Annotations during Runtime? (ASP.NET MVC's [Range] [Required] [StringLength] etc.) - Stack Overflow[^] Eg:

    public class CustomModelValidatorProvider : DataAnnotationsModelValidatorProvider
    {
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
    if (metadata.Model is ServiceFunctionCategoryLKP model && metadata.PropertyName == nameof(model.Code) && model.CodeLength >= 0)
    {
    var newAttributes = new List<Attribute>(attributes);
    var stringLength = newAttributes.OfType<StringLengthAttribute>().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);
    }
    

    }

    Register in Globals.asax.cs:

    ModelValidatorProviders.Providers.Clear();
    ModelValidatorProviders.Providers.Add( new CustomValidatorProvider() );

    NB: You're effectively allowing the user to override the validation rule by modifying a hidden field on the page. As a result, the validation can't really be trusted. It would be better to create a separate model class for each required code length.


    "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

    I Offline
    I Offline
    indian143
    wrote on last edited by
    #5

    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."

    Richard DeemingR 1 Reply Last reply
    0
    • I indian143

      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."

      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #6

      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 the StringLength 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

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      I 2 Replies Last reply
      0
      • Richard DeemingR Richard Deeming

        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 the StringLength 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

        I Offline
        I Offline
        indian143
        wrote on last edited by
        #7

        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."

        1 Reply Last reply
        0
        • Richard DeemingR Richard Deeming

          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 the StringLength 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

          I Offline
          I Offline
          indian143
          wrote on last edited by
          #8

          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."

          Richard DeemingR 1 Reply Last reply
          0
          • I indian143

            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."

            Richard DeemingR Offline
            Richard DeemingR Offline
            Richard Deeming
            wrote on last edited by
            #9

            You register the provider in Global.asax.cs:

            ModelValidatorProviders.Providers.Clear();
            ModelValidatorProviders.Providers.Add( new CustomValidatorProvider() );

            I'd expect to see the PropertyName set to null 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 the CodeLength property; you need to customise the validators for the Code 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

            "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

            I 1 Reply Last reply
            0
            • Richard DeemingR Richard Deeming

              You register the provider in Global.asax.cs:

              ModelValidatorProviders.Providers.Clear();
              ModelValidatorProviders.Providers.Add( new CustomValidatorProvider() );

              I'd expect to see the PropertyName set to null 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 the CodeLength property; you need to customise the validators for the Code 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

              I Offline
              I Offline
              indian143
              wrote on last edited by
              #10

              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."

              Richard DeemingR 1 Reply Last reply
              0
              • I indian143

                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."

                Richard DeemingR Offline
                Richard DeemingR Offline
                Richard Deeming
                wrote on last edited by
                #11

                Sorry, I picked the wrong property to test against. Replace metadata.Model with metadata.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

                "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                I 1 Reply Last reply
                0
                • Richard DeemingR Richard Deeming

                  Sorry, I picked the wrong property to test against. Replace metadata.Model with metadata.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

                  I Offline
                  I Offline
                  indian143
                  wrote on last edited by
                  #12

                  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;
                  
                  Richard DeemingR 1 Reply Last reply
                  0
                  • I indian143

                    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;
                    
                    Richard DeemingR Offline
                    Richard DeemingR Offline
                    Richard Deeming
                    wrote on last edited by
                    #13

                    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 the if (model.CodeLength != 0) block outside of the if (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

                    "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                    I 1 Reply Last reply
                    0
                    • Richard DeemingR Richard Deeming

                      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 the if (model.CodeLength != 0) block outside of the if (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 Offline
                      I Offline
                      indian143
                      wrote on last edited by
                      #14

                      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."

                      Richard DeemingR 1 Reply Last reply
                      0
                      • I indian143

                        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."

                        Richard DeemingR Offline
                        Richard DeemingR Offline
                        Richard Deeming
                        wrote on last edited by
                        #15

                        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

                        "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                        1 Reply Last reply
                        0
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • World
                        • Users
                        • Groups