欢迎来到.net学习网

欢迎联系站长一起更新本网站!QQ:879621940

您当前所在位置:首页 » ASP.Net » 正文

热门阅读

利用AOP实现给Model类赋值验证

创建时间:2014年04月29日 09:58  阅读次数:(12438)
分享到:
在三层模型中,我们通常会有一个Model层,用来和其它层传递数据。在给Model层赋值时,免不了要对数据进行某种规则的验证,比如需要验证某个字段是否允许为空,或者某个字段的值必须在一个范围内等等。当然我们可以在给字段赋值先验证,验证合格后才赋值给字段。这里我们主要讲怎么利用AOP实现Model层自已验证。

首先,我们需要使用Attribute特性来声明各种规则。如下:
[FieldTypeDecimal(0,100)]
[NonEmpty]
public decimal Price
{
  get;
  set;
}

上面的示例中,FieldTypeDecimal与NonEmpty就是两个自定义特性,NonEmpty用来标识Price不能为空,FieldTypeDecimal用来标识Price的赋值范围,[FieldTypeDecimal(0,100)]就表示FieldTypeDecimal的值只能大于等于0或小于等于1000。

定义分别如下:
FieldTypeDecimal 
/// <summary >
/// 验证属性的值是否大于或等于最小值,或者小于或等于最大值。
/// </summary >
public class FieldTypeDecimal : Attribute
{
    /// <summary >
    /// 是否验证最小值
    /// </summary >
    public bool IsValidMinValue
    {
        get;
        set;
    }

    /// <summary >
    /// 是否验证最大值
    /// </summary >
    public bool IsValidMaxValue
    {
        get;
        set;
    }

    private int minValue;
    public int MinValue
    {
        get { return minValue; }
        set { minValue = value; }
    }

    private int maxValue;
    public int MaxValue
    {
        get { return maxValue; }
        set { maxValue = value; }
    }

    public FieldTypeDecimal(int minValue)
    {
        this.IsValidMinValue = true;
        this.minValue = minValue;
    }

    public FieldTypeDecimal(int minValue, int maxValue)
    {
        this.IsValidMinValue = true;
        this.IsValidMaxValue = true;
        this.minValue = minValue;
        this.maxValue = maxValue;
    }
}

NonEmpty 
/// <summary >
/// 不可以为空
/// </summary >
public class NonEmpty : Attribute
{
    public NonEmpty(){ }
}

注意:这两个类一定要继承Attribute。

然后将两个特性应用于某个Model类中,如下:
[ValidProxyAttribute]
public class Sale_QuotationSheetDetail : ContextBoundObject
{
  [FieldTypeDecimal(0,100)]
  [NonEmpty]
  public decimal Price
  {
    get;
    set;
  }
}

注意上面Sale_QuotationSheetDetail 类一定要继承ContextBoundObject,这个非常重要。
注意看上面的ValidProxyAttribute类,我们也有应用了一个自定义特性ValidProxyAttribute,这个特性如下:
/// <summary >
/// 字段需要验证的标识
/// </summary >
public class ValidProxyAttribute : ProxyAttribute
{
    public override MarshalByRefObject CreateInstance(Type serverType)
    {
        ValidProxy validProxy = new ValidProxy(serverType);

        return validProxy.GetTransparentProxy() as MarshalByRefObject;
    }
}

实现本文的功能最重要的部分来了,ValidProxy 类。
ValidProxy 类其实就是RealProxy的一个子类,我们可以重写Invoke方法,来拦截Price属性的赋值方法"Set_Price"(任何类的属性的set操作,其实都是一个Set_XXX的方法。),来验证值是否满足规则。
public class ValidProxy : RealProxy
{
    public ValidProxy(Type serverType)
        : base(serverType)
    { }


    public override IMessage Invoke(IMessage msg)
    {
        if (msg is IConstructionCallMessage)
        {
            IConstructionCallMessage constructCallMsg = msg as IConstructionCallMessage;

            IConstructionReturnMessage constructionReturnMessage = InitializeServerObject(constructCallMsg);

            RealProxy.SetStubData(this, constructionReturnMessage.ReturnValue);
            return constructionReturnMessage;
        }
        else if (msg is IMethodCallMessage)
        {
            IMethodCallMessage callMsg = msg as IMethodCallMessage;
            object[] args = callMsg.Args;

            IMessage message;
            try
            {
                object baseObject = GetUnwrappedServer();
                if (callMsg.MethodName.StartsWith("set_") && args.Length == 1)
                {
                    string memberName = callMsg.MethodName.substring(4);

                    MemberInfo info = baseObject.GetType().GetMember(memberName)[0];
                    string columnName = string.Empty;
                    if (info.IsDefined(typeof(IModel.FieldName), false))
                    {
                        IModel.FieldName fieldName = (IModel.FieldName)info.GetCustomAttributes(typeof(IModel.FieldName), false)[0];
                        columnName = fieldName.Name;
                    }

                    ValidObserver validObserver = new ValidObserver(columnName);

                    IModel.IMessage mes;
                    if (info.IsDefined(typeof(IModel.NonEmpty), false))
                    {
                        mes = (IModel.IMessage)info.GetCustomAttributes(typeof(IModel.NonEmpty), false)[0];                      
                        validObserver.AddMessage(mes, args[0]);
                    }
                    if (info.IsDefined(typeof(IModel.FieldTypeDecimal), false))
                    {
                        mes = (IModel.IMessage)info.GetCustomAttributes(typeof(IModel.FieldTypeDecimal), false)[0];
                        validObserver.AddMessage(mes, args[0]);
                    }

                    validObserver.Valid();
                }

                object o = callMsg.MethodBase.Invoke(baseObject, args);
                message = new ReturnMessage(o, args, callMsg.InArgCount, callMsg.LogicalCallContext, callMsg);
            }
            catch (Exception e)
            {
                message = new ReturnMessage(e, callMsg);
            }

            return message;
        }
        else
            return msg;
    }
}

上面代码中的:
string memberName = callMsg.MethodName.substring(4);

MemberInfo info = baseObject.GetType().GetMember(memberName)[0];
string columnName = string.Empty;
if (info.IsDefined(typeof(IModel.FieldName), false))
{
    IModel.FieldName fieldName = (IModel.FieldName)info.GetCustomAttributes(typeof(IModel.FieldName), false)[0];
    columnName = fieldName.Name;
}

ValidObserver validObserver = new ValidObserver(columnName);

IModel.IMessage mes;
if (info.IsDefined(typeof(IModel.NonEmpty), false))
{
    mes = (IModel.IMessage)info.GetCustomAttributes(typeof(IModel.NonEmpty), false)[0];
    validObserver.AddMessage(mes, args[0]);
}
if (info.IsDefined(typeof(IModel.FieldTypeDecimal), false))
{
    mes = (IModel.IMessage)info.GetCustomAttributes(typeof(IModel.FieldTypeDecimal), false)[0];
    validObserver.AddMessage(mes, args[0]);
}

validObserver.Valid();

部分是我的规则验证部分,大家的验证应该都会不同,这里只是给大家一个参考。

解释一下上面几个关键方法或函数:
msg is IConstructionCallMessage 如果当前执行的是构造函数
msg is IMethodCallMessage 如果当前执行的自定义方法
object[] args = callMsg.Args;  callMsg.Args表示属性的值
callMsg.MethodName 当前正在执行的方法的名称,(即set_XXXX方法)
GetUnwrappedServer() 返回当前方法所属的对象(即实现中的Sale_QuotationSheetDetail类)
info.GetCustomAttributes 为获取类的自定义特性,可以参考示例:Asp.net中如何查找类属性的自定义Attribute

这样,当我们在给Sale_QuotationSheetDetail的Price属性赋值时,都会自动执行ValidProxy 类的Invoke方法,大家可以调试下,以增加理解。
来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf

打赏

取消

感谢您的支持,我会做的更好!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

最新评论

共有评论0条
  • 暂无任何评论,请留下您对本文章的看法,共同参入讨论!
发表评论:
留言人:
内  容:
请输入问题 50+75=? 的结果(结果是:125)
结  果: