小试牛刀:自制一个轻量级验证框架(A Lightweight Model-Validation Framework Of Sopaco)

在软件开发中经常需要写数据验证的代码(有的是通过xml进行配置),对于web客户端而言我们可以使用jquery的validation插件,得意于js语言的灵活特性,可以快速的写出整洁高效的js验证代码。

而在服务端这边,用静态语言写出的代码给人印象就不那么灵巧了。幸好C#在3.x中加入了lambda expression、Extension Methods等新语法特性以及相关的编译器支持,再加上即将发布的DLR赋予C#动态语言能力,使得我们可以在语言层次上写出与js相媲美的十足灵活的漂亮代码。

这个小验证框架内部大量使用lambda表达式和linq集成查询,使得对框架的使用和功能扩展都非常容易。

先看下下效果:

 

效果示例
// 我们定义一个简单类型AccountModel
public   class  AccountModel
    {
        
public   int  Sid {  get set ; };
        
public   string  Balance {  get set ; };
    } 

// 我们需要对AccountModel进行数据验证,使用如下代码初始化一个验证器。 
      ValidateTypeDictionary.Instance // 获取验证字典实例
                .RegisterType < AccountModel > () // 注册一个AccountModel类型的Validator
                .ResolveValidator < AccountModel > () // 得到类型为AccountModel的Validator
                .Setup(p  =>  p.a  !=   5 ) // 设置自定义规则,需要AccountModel.a不等于5
                .Setup(p  =>  p.b.EndsWith( " abc " )) // 设置自定义规则,需要AccountModel.b以”abc“结尾
                .IntRule < AccountModel > (p  =>  p.a,  1 50 ) // 这是扩展方法,需要a介于1与50之间
                .EmailRule(p  =>  p.b); // 这是扩展的方法,验证是否为邮件格式,同样你也可以扩展自己的验证方法。

// 以后如果需要验证对象就这样使用:
             if (ValidateTypeDictionary.Instance.Validate < AccountModel > (model2)){ …… };

 

通过类型字典注册每一个实体模型对应的验证规则,然后只需要通过Setup()方法放入验证逻辑,也可以在合适的时候重置验证逻辑。除此以外,可以使用扩展方法特性为Validate加入特定的验证逻辑(将在下面给出示范),方便的第三方扩充框架功能。

先来看看接口定义

接口定义 
namespace  Sopaco.Lib.Validate.ModelValidate
{
    
public   interface  IValidateTypeDictionary
    {
        IValidateTypeDictionary RegisterType
< TModel > ();
        IValidator
< TModel >  ResolveValidator < TModel > ();
        
bool  Validate < TModel > (TModel model);
    }


namespace  Sopaco.Lib.Validate.ModelValidate
{
    
public   interface  IValidator < TModel >
    {
        IValidator
< TModel >  Setup(Func < TModel,  bool >  f);
        
bool  ValidateModel(TModel model);
        
void  ResetValidator();
    }
}

 

 

IValidatorTypeDictionary为我们提供注册(为了方便使用也提供了验证接口)、获取验证对象的方法。IValidator提供具体的自定义验证设置和验证方法调用。

具体实现上我使用了泛型字典,Validator类实现IValidator,每个Validator<TModel>都是单例,由于CLR提供真泛型支持,所以每个需要验证的类型都能对应一个Validator实例。

 

实现 
namespace  Sopaco.Lib.Validate.ModelValidate
{
    
public   class  ValidateTypeDictionary : IValidateTypeDictionary
    {
        
#region  Fields
        
public   static   readonly  IValidateTypeDictionary Instance;
        
#endregion  

        
#region  Constructors & Initializer
        
static  ValidateTypeDictionary()
        {
            Instance 
=   new  ValidateTypeDictionary();
        }
        
private  ValidateTypeDictionary()
        {
        }
        
#endregion  

        
#region  IValidateTypeDictionary 成员 

        
public  IValidateTypeDictionary RegisterType < TModel > () // 注册到类型字典中
        {
            
if  (Validator < TModel > .Instance  ==   null )
                Validator
< TModel > .Instance  =   new  Validator < TModel > ();
            
return   this ;
        } 

        
public   bool  Validate < TModel > (TModel model)
        {
            var validator 
=  ResolveValidator < TModel > ();
            
if (validator  ==   null )
            {
                
throw   new  NonValidatorException();
            }
            
return  validator.ValidateModel(model);
        } 

        
public  IValidator < TModel >  ResolveValidator < TModel > ()
        {
            
return  Validator < TModel > .Instance;
        }
        
#endregion
    }
}



namespace  Sopaco.Lib.Validate.ModelValidate
{
    
public   class  Validator < TModel >  : IValidator < TModel >
    {
        
#region  Fields
        
internal  IList < Func < TModel,  bool >>  _validateRules;
        
internal   static  Validator < TModel >  Instance;
        
#endregion  

        
#region  Constructors & Initializer
        
public  Validator()
        {
            Init();
        }
        
private   void  Init()
        {
            
// _validateRules = Enumerable.Empty<Func<TModel, bool>>();
            _validateRules  =   new  List < Func < TModel,  bool >> ();
        }
        
#endregion  

        
#region  IValidator<TModel> 成员 

        
public  IValidator < TModel >  Setup(Func < TModel,  bool >  rule)
        {
            _validateRules.Add(rule);;
            
return   this ;
        } 

        
public   bool  ValidateModel(TModel model)
        {
            
return  _validateRules.Aggregate(
                
true ,
                (prev, f) 
=>  f.Invoke(model)
                );
        } 

        
public   void  ResetValidator()
        {
            _validateRules.Clear();
        }
        
#endregion  
    }
}

 

 

 

下面说说如何扩展:

框架本身并没有提供验证逻辑,验证逻辑是使用者去写,对于常用的验证,比如验证电子邮件格式,身份证好等如果频繁的调用Setup方法就很臃肿了,所以我们可以基于框架借助扩展方法来增强框架功能。

下面我给出了示范,添加一个正则表达式验证扩展方法和更为具体的电子邮件验证扩展方法还有一个对整数范围的验证扩展方法。可以根据需要扩展更多的验证逻辑。

可以由第三方来扩展
namespace  Sopaco.Lib.Validate.ModelValidate.ValidateExtensions
{
    
public   static   class  ValidateRules
    {
        
public   static  IValidator < TModel >  IntRule < TModel > ( this  IValidator < TModel >  validator, Func < TModel,  int >  func,  int  min,  int  max)
        {
            Func
< TModel,  bool >  f
                
=  p  =>
                    {
                        
int  property  =  func.Invoke(p);
                        
return  property  >=  min  &&  property  <=  max;
                    };
            validator.Setup(f);
            
return  validator;
        } 

        
public   static  IValidator < TModel >  StringRule < TModel > ( this  IValidator < TModel >  validator, Func < TModel,  string >  func,  string  pattern)
        {
            Func
< TModel,  bool >  f
                
=  p  =>
                {
                    
string  property  =  func.Invoke(p);
                    
return   new  Regex(pattern).IsMatch(property);
                };
            validator.Setup(f);
            
return  validator;
        }
        
public   static  IValidator < TModel >  EmailRule < TModel > ( this  IValidator < TModel >  validator, Func < TModel,  string >  func)
        {
            StringRule
< TModel > (validator, func,  @" ^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ " );
            
return  validator;
        }
    }
}
SourceCode放在SkyDriver上了:
 

 

The reproduction or distribution of copyright works in wJiang's blog for research, private study or internal reference purpose is permitted provided there is an acknowledgement of the source where appropriate

网名:

无疆_炎戎
无疆_寒冰

实名:

姜萌

姜萌@LiveSpace:
姜萌@cnblogs

你可能感兴趣的:(validation)