路过秋天

同样的3年,有的人从学生到当了MVP了,而我却在原地,卖弄当年的代码,秋天的风,有点凄,有点凉!

公告信息
内涵是很强大的~~~别看外表~~~当犀利哥入侵不了的时候,感觉有种莫名的失落~~~
文章档案
最新评论

C# Aop拦截调用目标对象方法(原创)

先说下场景,C#中为什么要使用Aop,而我又是在哪里使用Aop?

本人只是想拦截实体类的Set的方法,然后在Set之前,调用一下其它方法,把值赋给另一个对象。

而我做的都是在实体类的基类里处理:

比如:

public class OrmBase

让所有继承这个基类的实体类都具有Orm操作功能。

虽然在OrmBase中可以提供方法,让所有的子类的属性都这样操作:

public class Users:OrmBase
{
public int _ID;
public int ID 
{
get;
set
{
  base.SetXX(value);
 }
}

不过每个实体都这样写,虽然是啥没问题,不过能简化的还是简化。因此,直接在基类里敲定好,直接拦截set方法,在里面直接调用SetXX就搞定了,这样继承的就不用加多一个SetXX,而是像传统一样即可。

为此,首先用Aop的拦截:

传统的Aop使用RealProxy,使用非常简单,需要两个类:

1:在要拦截的类头上加个属性标识:

[AopAttribute]
public class OrmBase

OK,加上一个标识,就可以被拦截了,那这个属性是啥?

2:继承代理属性标识类,用来挂在要拦截的类的头上:

    class AopAttribute : ProxyAttribute
    {
        public override MarshalByRefObject CreateInstance(Type serverType)
        {
            AopProxy realProxy = new AopProxy(serverType);
            return realProxy.GetTransparentProxy() as MarshalByRefObject;
        }
    }

看,就两行,非常简单,中间调用了继承RealProxy的AopProxy类。

3:AopProxy类,就是拦截的消息处理,先上个简单版,免的大伙看不懂:

 class AopProxy : RealProxy
    {
        public AopProxy(Type serverType)
            : base(serverType)
        {
        }
        public override IMessage Invoke(IMessage msg)
        {
            //消息拦截之后,就会执行这里的方法。
        }
    }

OK,简单吧,就这么两个类,就可以实现拦截了,不过重点就是这里拦截之后的代码,稍为复杂点,一般照抄就行了,拦截的代码如下:

 if (msg is IConstructionCallMessage) // 如果是构造函数

            {

                IConstructionCallMessage constructCallMsg = msg as IConstructionCallMessage;

                IConstructionReturnMessage constructionReturnMessage = this.InitializeServerObject((IConstructionCallMessage)msg);

                RealProxy.SetStubData(this, constructionReturnMessage.ReturnValue);

                return constructionReturnMessage;

            }

            else if (msg is IMethodCallMessage) //如果是方法调用(属性也是方法调用的一种)

            {

                IMethodCallMessage callMsg = msg as IMethodCallMessage;

                object[] args = callMsg.Args;

                IMessage message;

                try

                {

                    if (callMsg.MethodName.StartsWith("set_") && args.Length == 1)

                    {

                        //这里检测到是set方法,然后应试怎么调用对象的其它方法呢?

                    }

                    object o = callMsg.MethodBase.Invoke(GetUnwrappedServer(), args);

                    message = new ReturnMessage(o, args, args.Length, callMsg.LogicalCallContext, callMsg);

                }

                catch (Exception e)

                {

                    message = new ReturnMessage(e, callMsg);

                }

                return message;

            }

            return msg;

为了调用原始对象的其它方法,我花了近一天的时间查资料,可惜网络上并没有相应的信息,多数的人应用,都是引向一个其它方法(一个不需要调用原始对象的方法)

于是,我按传统方式,想尽办法的想获取到原始对象,然后进行类型转换,再调用,经过九九八十一招,还是失败了。

中间省一大堆......痛苦的经历和尝试.......

最后发现,还是需要用方法调用的方式:

1:获取要调用的方法:

在构造函数中,根据传进来的serverType,获取到SetXX的方法MethodInfo:

method = serverType.GetMethod("SetXX", BindingFlags.NonPublic | BindingFlags.Instance);

2:在拦截方法中调用:

 if (callMsg.MethodName.StartsWith("set_") && args.Length == 1)

{

                        method.Invoke(GetUnwrappedServer(), new object[] { callMsg.MethodName.Substring(4), args[0] });//对属性进行调用

  }

就是这么简单,就实现对原始对象的方法进行调用了。

同理,如果需要调用方法的其它方法,提前获取,后续调用即可。


秋色园是QBlog的官方站点,由路过秋天创建,基于cyqdata数据层框架开发的支持多用户、多语言、多数据库(access,mssql,oracle)、目录级url等功能强大的博客系统
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"

2012/5/29 23:58:15 | 网络篇 | |

#3天上人间2012/8/18 23:34:45
看懂了,但是第一种方法似乎还是简单些,多几个类的内存开销会大些吧
#2游客[注册][220.178.63.*]2012/6/25 15:38:53
写的太简单了,很多代码没有交代清楚。
#1xjwebs2012/6/5 10:51:15
有没有实例啊,没看明白。
  • 发表评论