EasyCsharp - Dynamic Proxy

RealProxy实现代理

RealProxy实现 MarshalByRefObject对象的代理

对于MarshalByRefObject对象,可以使用下面的代码代理,并且对于传递到方法中的ref或out参数都可以正常返回。RemotingServices.ExecuteMessage传递的参数要求被代理对象是MarshalByRefObject类型。
Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Text;
using System.Threading.Tasks;
using SampleCommon;

namespace DynamicProxy
{
    public class DynamicProxy2
    {
        public static void Run()
        {
            G.SetLogPreStr("[DynamicProxy2]");
            var bird = new Bird();
            var proxy = EasyProxy2.NewProxy(bird);
            proxy.Say();
            int a = 2;
            int b;
            int c = proxy.Say(ref a, out b);
            G.Log("a: {0} b:{1} c:{2}", a, b, c);
        }
    }

    public interface ISay
    {
        void Say();
        int Say(ref int a, out int b);
    }

    public class Bird : MarshalByRefObject, ISay
    {
        public Bird()
        {
            G.Log("this is bird construct");
        }

        public void Say()
        {
            G.Log("this is bird say");
        }

        public int Say(ref int a, out int b)
        {
            a++;
            b = 1;
            return a;
        }
    }

    public class EasyProxy2 : RealProxy
    {
        private MarshalByRefObject _target;

        private EasyProxy2(MarshalByRefObject target)
            : base(target.GetType())
        {
            _target = target;
        }

        public override IMessage Invoke(IMessage msg)
        {
            var methodCall = (IMethodCallMessage) msg;

            G.Log("begin method {0}", methodCall.MethodName);


            IMethodReturnMessage myIMethodReturnMessage =
                RemotingServices.ExecuteMessage(_target, methodCall);

            G.Log("after method {0}", methodCall.MethodName);

            return myIMethodReturnMessage;
        }

        public static T NewProxy<T>(T target) where T : MarshalByRefObject
        {
            var easyProxy = new EasyProxy2(target);
            return (T) easyProxy.GetTransparentProxy();
        }
    }
}

Result
这里写图片描述

RealProxy实现接口代理

这种方法将实现任意对象但需要继承特定接口的对象代理。
Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Text;
using System.Threading.Tasks;
using SampleCommon;

namespace DynamicProxy
{
    public class DynamicProxy3
    {
        public static void Run()
        {
            G.SetLogPreStr("[DynamicProxy3]");
            var bird = new Bird3();
            var proxy = EasyProxy3<ISay>.NewProxy(bird);
            proxy.Say();
            int a = 2;
            int b;
            int c = proxy.Say(ref a, out b);
            G.Log("a: {0} b:{1} c:{2}", a, b, c);
        }
    }

    public class Bird3 : ISay
    {
        public Bird3()
        {
            G.Log("this is bird construct");
        }

        public void Say()
        {
            G.Log("this is bird say");
        }

        public int Say(ref int a, out int b)
        {
            a++;
            b = 1;
            return a;
        }
    }

    public class EasyProxy3<T> : RealProxy
    {
        private object _target;

        private EasyProxy3(object target)
            : base(typeof(T))
        {
            _target = target;
        }

        public override IMessage Invoke(IMessage msg)
        {
            var methodCall = (IMethodCallMessage) msg;

            G.Log("begin method {0}", methodCall.MethodName);

            object[] args = null;
            if (null != methodCall.Args && methodCall.Args.Length > 0)
            {
                args = new object[methodCall.Args.Length];
                Array.Copy(methodCall.Args, 0, args, 0, methodCall.Args.Length);
            }

            var result = methodCall.MethodBase.Invoke(_target, args);

            G.Log("after method {0}", methodCall.MethodName);

            return new ReturnMessage(result, args,
                args == null ? 0 : args.Length, methodCall.LogicalCallContext, methodCall);
        }

        public static T NewProxy(T target)
        {
            var easyProxy = new EasyProxy3<T>(target);
            return (T)easyProxy.GetTransparentProxy();
        }
    }
}

Result
这里写图片描述

上面两种方式实现的代理方法均无法对构造函数进行拦截

ProxyAttribute特性拦截

话不多说,详细内容都写在了注释里,被代理类必须继承自ContextBoundObject,这里给出完整示例。
Code

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Services;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using SampleCommon;

namespace DynamicProxy
{
    class DynamicProxy4
    {
        public static void Run()
        {
            G.SetLogPreStr("[DynamicProxy4]");
            G.Log("begin");

            //这里使用的new RayspyObject()并没有真正构建相关对象,而是被代理对象拦截重新构建,因此不要传递参数给其构造函数,无效
            var server = new RayspyObject();
            server.Say("hello");

            G.Log("end");
        }
    }

    /*
     * 1.只有需要代理的对象继承自ContextBoundObject时再可以正常拦截,否则无法拦截,即使继承MarshalByRefObject也不行
     * 2.特性是针对于类而非对象,因此构造函数中初始化的内容将无法正常传递
     */
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    [RaySpyProxy] 
    public class RayspyObject : ContextBoundObject
    {
        public RayspyObject()
        {
            G.Log("RayspyObject constructor called");
        }

        public void Say(string str)
        {
            G.Log("RayspyObject method Say invoke with msg: " + str);
        }
    }

    [AttributeUsage(AttributeTargets.Class)]
    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
    public class RaySpyProxyAttribute : ProxyAttribute
    {
        public override MarshalByRefObject CreateInstance(Type serverType)
        {
            MarshalByRefObject obj = base.CreateInstance(serverType);
            var proxy = new ObjProxy(serverType, obj);
            return (MarshalByRefObject)proxy.GetTransparentProxy();
        }
    }

    public class ObjProxy : RealProxy
    {
        private MarshalByRefObject _target = null;

        public ObjProxy(Type type, MarshalByRefObject target)
            : base(type)
        {
            this._target = target;
        }

        public override IMessage Invoke(IMessage msg)
        {
            var methodCall = (IMethodCallMessage)msg;

            G.Log("begin call {0}", methodCall.MethodName);

            var methodConstruct = methodCall as IConstructionCallMessage;

            IMethodReturnMessage back = null;
            //构造函数,只有ContextBoundObject(Inherit from MarshalByRefObject)对象才能截获构造函数
            if (methodConstruct != null)
            {
                RealProxy defaultProxy = RemotingServices.GetRealProxy(_target);

                //此时_target并没有真正构建
                //下面这句是构建_target
                defaultProxy.InitializeServerObject(methodConstruct);
                //本类是一个RealProxy,它可通过GetTransparentProxy函数得到透明代理
                back = EnterpriseServicesHelper.CreateConstructionReturnMessage(methodConstruct,
                    (MarshalByRefObject) GetTransparentProxy());
            }
            /*
             * MarshalByRefObject对象就可截获普通的调用消息,
             * MarshalByRefObject对象告诉编译器,不能将其内部简单的成员函数优化成内联代码,
             * 这样才能保证函数调用都能截获。
             */
            else
            {
                //可以进行参数验证?
                back = RemotingServices.ExecuteMessage(_target, methodCall);
            }

            G.Log("end call {0}", methodCall.MethodName);

            return back;
        }
    }
}

Result
这里写图片描述

引用

[1] MSDN ProxyAttribute
[2] MSDN RealProxy
[3] .Net中的RealProxy实现AOP
[4] Proxy代理背后的原理

猜你喜欢

转载自blog.csdn.net/wujingang/article/details/72725766