How to validate an input against a changing validation requirements

 

Introduction

Data annotation is a server side mechanism that is used to validate a certain model attribute value in MVC.It binds a model attribute to a certain validation attribute type .Common validation attribute types include

  • Required
  • Range
  • DataType
  • Regular expression
  • ....

Regular expression data annotation is used to validate a model attribute value against a certain pattern,as example below

The following data annotation checks if a model attribute value qualifies to be a valid e-mail address

[RegularExpression(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", ErrorMessage = "Email is not valid.")]

The model attributes are bound to the proper data annotation while creating the model

<>

What if the pattern is subject to change as per user requirements

for example user can control the complexity degree of user passwords

	 public partial class PasswordComplexityRuleDataModel
    {
        public int Id { get; set; }
        public bool MustContainLettersNumbers { get; set; }
        public bool MustContainSpecialCharacters { get; set; }
        public bool MustContainUpperLower { get; set; }
        public short MinLength { get; set; }
       
    }

Solution 1

call a certain validation function on each action marked as (post) Example
  1. model
    				public partial class UserDataModel
        {
    
    
          /**/
    
    				public string passwordinvalid { get; set; }
    
        }
    			..
  2. Controller
    		
    		
    		
    				   public IActionResult Save(UserDataModel user)
            {
                //if(PasswrodRequirementAreMet(user.Password))
                //{
                //ModelState.AddModelError("passwordinvalid", "");
                 //                         ||
    			//                          add a span bound to this property in view}
                if (ModelState.IsValid)
                {
                    _userServiceInterface.SaveUser(user);
                    return RedirectToAction(nameof(Index));
                }
                return View(user);
            }
    		..
    		

This solution has a drawback of calling it on every action of type (post)

Solution 2

  1. Create a custom validation attribute to take care of validating the input
    //
    
    
     class CustomPassWordValidation:ValidationAttribute
     {
       protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
    		  PasswordValid = CheckPasswordAgainstPasswordSettings(value.ToString());
    			  
    				if (PasswordValid != "password valid")
    				{
    						ErrorMessage = PasswordValid;
    					return new ValidationResult(ErrorMessage);
    				}
    				return ValidationResult.Success;
    		}
    		 string CheckPasswordAgainstPasswordSettings(string password)
            {
    			/**/
    			return "password valid";
    		}
    }
    
    ...
  2. In the data model containing your attribute,bind the attribute to the attribute validator created above
    	 public class UserViewModel
        {
    	[CustomValidationAttribute.CustomPassWordValidation(ErrorMessage ="travesh")]
    	   public string Password { get; set; }
    	   ..
    }

  • If your coding standards follows the dependency injection supporting nature of asp.net core mvc,the function checking password validity may be calling a function in another interface
  • you can call the interface instance using the following syntax

//


 class CustomPassWordValidation:ValidationAttribute
 {
 // an object type (service interface type ) 
  protected IPasswordComplexityRuleService _passwordComplexityRuleService 
  
   protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
		  //call the interface instance
		 _passwordComplexityRuleService =(IPasswordComplexityRuleService) validationContext.GetService(typeof(IPasswordComplexityRuleService));
		  PasswordValid = CheckPasswordAgainstPasswordSettings(value.ToString());
			  
				if (PasswordValid != "password valid")
				{
						ErrorMessage = PasswordValid;
					return new ValidationResult(ErrorMessage);
				}
				return ValidationResult.Success;
		}
		 string CheckPasswordAgainstPasswordSettings(string password)
        {
			/*interface instance is used here*/
			return "password valid";
		}
}

...

Comments

Popular posts from this blog

Validate that a certain checkbox is checked before submit(ASP.NET MVC)

An example of a (LINQ) approach to solve recurring problems