使用PIAB和VAB实现业务实体的自动验证

 微软企业库的VAB(Validation Application Block)用来提供对业务实体的字段有效性进行验证,PIAB(Policy Injection Application Block)用来实现AOP技术,关于VAB的内容请参考园子里TerryLee
(http://www.cnblogs.com/Terrylee/archive/2006/12/25/Enterprise_Library_3_Validation_Application_Block.html)的文章,关于PIAB的内容请参考Artech(http://www.cnblogs.com/artech/archive/2008/08/08/1263418.html)的文章。

   我们做系统时根据需求会写很多业务实体,这些实体一般用来作为业务层方法的参数(输入或者输出),例如 public bool AddUser(UserEntity userentity)这个业务方法,UserEntity是我们定义的业务实体,我们在写这个方法时,先要对这个实体里面的属性值进行合法性验证,才能 进行以后的操作,当然,我们可以在在这个方法中手工写一些验证的代码来完成,只是比较麻烦而已,我们也可以借助VAB,在实体定义的属性上增加一些验证的 Attribute,如下:

 


public class UserEntity : BaseEntity<UserEntity>
    {

        [NotNullValidator]
        [StringLengthValidator(
150, MessageTemplate = "姓名必须在1-50个字之间!")]
        
public string UserName { getset; }
        
        [RangeValidator(
0,RangeBoundaryType.Inclusive,100,RangeBoundaryType.Inclusive, MessageTemplate="年龄必须在0-100之间!

")]
        public int Age { getset; }

        [RegexValidator(
@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", MessageTemplate = "Email地址不正确!")]
        
public string Email { getset; }
    }

 

这样我们就可以利用VAB提供的验证方法Validation.Validate(userentity)来进行验证了,并对验证的结果做 进一步的处理;对于每个方法都要这么验证也是一件很麻烦的事情,我们可以把验证的代码简化一下(就是把验证的代码和验证结果处理的代码封装一下),仔细看 上面的代码,我们的实体类是继承自BaseEntity<T>泛型类的,这个泛型类的代码如下:

 


public abstract class BaseEntity<T> where T:class
    {

        
public void ValidateEntity()
        {
            ValidationResults results 
= Validation.Validate(this as T);
            StringBuilder sb 
= new StringBuilder();
            
foreach (ValidationResult result in results)
            {
                sb.AppendFormat(
"字段: {0},消息: {1}", result.Key.ToString(), result.Message);
                sb.Append(
"\n");
            }
            
if (sb.Length > 0)
            {
                
throw new CustomException(sb.ToString());
            }
        }
}

 

这个泛型类对对所有继承自这个泛型类的实体验证方法进行了封装,如验证发现问题,就抛出一个自定义的CustomException异 常,UI层Catch这个异常来提示用户;这样我们就可以在AddUser方法的内部调用userentity.ValidateEntity()来进行 验证了,如下代码:

public bool AddUser(UserEntity userentity)

        {

            userentity.ValidateEntity();

            return true;

        }

这样就好了很多,但还是有点麻烦,为啥还要写哪行验证的代码呢,要是程序员忘了写不是很麻烦?这就要用到AOP技术了,在这个方法执行前自动调用验 证的那个函数ValidateEntity();想到这里,我的心情无比激动啊,赶紧去搞一个AOP的CallHandler,在这里真是要感谢Artech同志了,看了他的文章,让我不费力的就写了个ValidateCallHandler和ValidateCallHandlerAttribute,要是有人看不懂下面的代码的话,建议先去Artech同志的博客去看看,代码如下:

 


namespace AOPValidate.Business
{
    
/// <summary>
    
/// 
    
/// </summary>
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    
public class ValidateCallHandlerAttribute: HandlerAttribute
    {
        
        
public override ICallHandler CreateHandler()
        {
            
return new ValidateCallHandler(Order);
        }
    }
    
/// <summary>
    
/// 
    
/// </summary>
    public class ValidateCallHandler : ICallHandler
    {
        
public ValidateCallHandler(int order)
        {
            Order 
= order;
        }
        
#region ICallHandler 成员
        
public int Order { setget; }
     
        
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            PreCall(input);
            IMethodReturn result 
= getNext()(input, getNext);
            
return result;
        }
        
#endregion


      

        
/// <summary>
        
/// 方法执行前
        
/// </summary>
        
/// <param name="input"></param>
        private void PreCall(IMethodInvocation input)
        {
            
for (int i = 0; i < input.Arguments.Count; ++i)
            {
                
object obj = input.Inputs[0];
                
try
                {
                    obj.GetType().InvokeMember(
"ValidateEntity", BindingFlags.InvokeMethod | BindingFlags.Public | 

BindingFlags.Instance, 
null,obj, null);
                }
                
catch (Exception ex) 
                {
                    
throw ex.InnerException;
                }
            }
        }

    }
}

 

那个PreCall(IMethodInvocation input)方法就是用来在方法执行前先执行ValidateEntity的实体验证方法的,说实在的,我真的不想用反射啊!可是除了反射,我想不到其他 的办法啊,哪位高人给指点一下啊?还有我也不想用Try啊!可是要是不用try和catch,执行的时候会报错,因为我们在验证方法里抛出了一个异常,虽 然是自定义的异常,也是系统异常!我就把整个异常catch下来,再throw我们自定义的异常,因为那里面有我们的验证结果啊,我们还要提示给用户看 呢。OK,不管怎么说,先实现了再说,我们来修改一下AddUser方法和它所在的类,如下:

 


public class TestValitate : MarshalByRefObject
    {
    
       [ValidateCallHandler()]
        
public bool AddUser(UserEntity userentity)
        {
            
//userentity.ValidateEntity();
            return true;
        }
    }
然后写个测试,看看:
TestValitate test 
= PolicyInjection.Create<TestValitate>();
            UserEntity userentity 
= new UserEntity();
            userentity.UserName 
= "xiaozhuang";
            userentity.Age 
= 101;
            userentity.Email 
= "iamxiaozhuang@163.com";
            
try
            {
                test.AddUser(userentity);
            }
            
catch (CustomException ex)
            {
                Console.Write(ex.Message);
            }

            Console.ReadKey();

 

posted on 2008-12-05 17:30  执法长老  阅读(245)  评论(0编辑  收藏  举报

导航