Call interception method in C # using proxy

What I'm trying to do is intercept calls to object methods and properties for end-to-end tasks. I am using proxy based AOP using ContextBoundObject .

However, this does not work for calls to recursive methods. The first call against the target will be intercepted by the proxy and successfully called, which will allow me to make a cross call here. However, subsequent method calls from the first method will remain within the target class and are not intercepted by the proxy server, as if there were no marshaling!

Is there any way to make it work? (I try to avoid third-party libraries like PostSharp, Unity or Spring.Net)

 class Program { static void Main(string[] args) { var t = new SimpleObject(); t.TestMethod1(); } } [Intercept] class SimpleObject : ContextBoundObject { public string TestMethod1() { return TestMethod2(); } public string TestMethod2() { return "test"; } } [AttributeUsage(AttributeTargets.Class)] public class InterceptAttribute : ContextAttribute, IContributeObjectSink { public InterceptAttribute() : base("Intercept") { } public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg) { return false; } public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink) { return new InterceptSink(nextSink); } } public class InterceptSink : IMessageSink { public IMessageSink NextSink { get; private set; } public InterceptSink(IMessageSink nextSink) { this.NextSink = nextSink; } public IMessage SyncProcessMessage(IMessage msg) { IMethodCallMessage mcm = (msg as IMethodCallMessage); // { cross-cut here } IMessage rtnMsg = this.NextSink.SyncProcessMessage(msg); IMethodReturnMessage mrm = (rtnMsg as IMethodReturnMessage); // { cross-cut here } return mrm; } public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) { return null; } } 
+4
source share
1 answer

C # designers have never been AOP supporters, there is no easy way to intercept method calls without using proxies and marshaling, which have their drawbacks! If someone wants to intercept method / property calls (e.g. cross cut issues), I found RealProxy to help.

RealProxy From MSDN:

A client that uses the object through any kind of remote boundary, in fact using a transparent proxy for the object. A transparent proxy provides the illusion that the actual object is in client space. This is achieved by redirecting calls made to it by a real object using the remote access infrastructure.

Note. A type proxied using RealProxy must either be an interface or inherit from MarshalByRefObject .

Here's some implementation of RealProxy using the Factory method to create a proxy object at runtime:

 public abstract class RuntimeProxy { public static readonly object Default = new object(); public static Target Create<Target>(Target instance, RuntimeProxyInterceptor interceptor) where Target : class { return (Target)new InternalProxy<Target>(instance, interceptor).GetTransparentProxy(); } public static Target Create<Target>(Target instance, Func<RuntimeProxyInvoker, object> factory) where Target : class { return (Target)new InternalProxy<Target>(instance, new InternalRuntimeProxyInterceptor(factory)).GetTransparentProxy(); } class InternalProxy<Target> : RealProxy where Target : class { readonly object Instance; readonly RuntimeProxyInterceptor Interceptor; public InternalProxy(Target instance, RuntimeProxyInterceptor interceptor) : base(typeof(Target)) { Instance = instance; Interceptor = interceptor; } public override IMessage Invoke(IMessage msg) { var methodCall = (IMethodCallMessage)msg; var method = (MethodInfo)methodCall.MethodBase; try { var result = Interceptor.Invoke(new InternalRuntimeProxyInterceptorInvoker(Instance, method, methodCall.InArgs)); if (result == RuntimeProxy.Default) result = method.ReturnType.IsPrimitive ? Activator.CreateInstance(method.ReturnType) : null; return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); } catch (Exception ex) { if (ex is TargetInvocationException && ex.InnerException != null) return new ReturnMessage(ex.InnerException, msg as IMethodCallMessage); return new ReturnMessage(ex, msg as IMethodCallMessage); } } } class InternalRuntimeProxyInterceptor : RuntimeProxyInterceptor { readonly Func<RuntimeProxyInvoker, object> Factory; public InternalRuntimeProxyInterceptor(Func<RuntimeProxyInvoker, object> factory) { this.Factory = factory; } public override object Invoke(RuntimeProxyInvoker invoker) { return Factory(invoker); } } class InternalRuntimeProxyInterceptorInvoker : RuntimeProxyInvoker { public InternalRuntimeProxyInterceptorInvoker(object target, MethodInfo method, object[] args) : base(target, method, args) { } } } public abstract class RuntimeProxyInterceptor { public virtual object Invoke(RuntimeProxyInvoker invoker) { return invoker.Invoke(); } } public abstract class RuntimeProxyInvoker { public readonly object Target; public readonly MethodInfo Method; public readonly ReadOnlyCollection<object> Arguments; public RuntimeProxyInvoker(object target, MethodInfo method, object[] args) { this.Target = target; this.Method = method; this.Arguments = new ReadOnlyCollection<object>(args); } public object Invoke() { return Invoke(this.Target); } public object Invoke(object target) { if (target == null) throw new ArgumentNullException("target"); try { return this.Method.Invoke(target, this.Arguments.ToArray()); } catch (TargetInvocationException ex) { throw ex.InnerException; } } } 

You can use RuntimeProxy as Factory to create an object proxy object and intercept all method / property calls and call the actual method.

Here is an example:

 class SomeClass : MarshalByRefObject { public int Mul(int a, int b) { return a * b; } public void SetValue(int val) { this.Val = val; } public int Val { get; set; } } 

Use the RuntimeProxy class to create a proxy for an instance of the SomeClass class and intercept calls:

 var test = new SomeClass(); var proxy = RuntimeProxy.Create(test, t => { // cross-cut here return t.Invoke(); // invoke the actual call }); var res = proxy.Mul(3, 4); // method with return value proxy.SetValue(2); // void method, setting some property var val = proxy.Val; // property access 

You can use interface types in case you do not want to inherit the MarshalByRefObject class.

+2
source

All Articles