58

I want to build a dynamic proxy object to add certain functionality to an object.

basically i want to receive an object, wrap it with an object that looks identical to the original i got, and intercept all the calls.

class Wrapper : DynamicProxy// dynamic proxy is not a reall class, but i guess something like this exists...
{
    public static T Wrap(T obj)
    {
        return (T) new Wrapper(obj);
    }

    public override object InterceptCall(MethodInfo info, object[] args)
    {
        // do stuff
    }

}

Just to clarify, I want to do something similar to the WCF channel factory...


I'm adding a bounty, because I need a good way to proxy classes (not interfaces) and to handle non virtual methods (as if I inherited and added a methond under the "new" keyword). I'm sure all this is very possible as the .Net does it.

AK_
  • 7,981
  • 7
  • 46
  • 78
  • 5
    have you looked at http://www.castleproject.org/dynamicproxy/index.html ? – np-hard Dec 05 '11 at 14:44
  • @np-hard if you post this as an answer, i will accept it... not 100% what i was looking for, but good enough. – AK_ Dec 21 '11 at 19:25
  • Do you know the type you want to proxy at compile time, or only at runtime? – Sneal Jan 03 '12 at 16:04
  • @Sneal only at run time. probably I'll know it at compile time but i want to keep flexibility... – AK_ Jan 03 '12 at 16:10
  • That definitely makes things a lot harder, as Castle DynamicProxy can only intercept virtual methods. I think you're stuck using the profiling api. – Sneal Jan 03 '12 at 16:18
  • I already have a good answer. (Obviously no profiling) ill wait for the bounty to get nearer to the end... If no one gets it ill post it... – AK_ Jan 03 '12 at 21:05
  • The channelfactory uses an interface doesn't it? – albertjan Jan 11 '12 at 08:12
  • @the_ajp , you can use either... – AK_ Jan 12 '12 at 08:19

9 Answers9

45

You could do this with a combination of DynamicObject and ImpromptuInterface but you will have to have an Interface that implements the functions and properties you want to proxy.

public interface IDoStuff
{
    void Foo();
}

public class Wrapper<T> : DynamicObject
{
    private readonly T _wrappedObject;

    public static T1 Wrap<T1>(T obj) where T1 : class
    {
        if (!typeof(T1).IsInterface)
            throw new ArgumentException("T1 must be an Interface");

        return new Wrapper<T>(obj).ActLike<T1>();
    }

    //you can make the contructor private so you are forced to use the Wrap method.
    private Wrapper(T obj)
    {
        _wrappedObject = obj;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        try
        {
            //do stuff here

            //call _wrappedObject object
            result = _wrappedObject.GetType().GetMethod(binder.Name).Invoke(_wrappedObject, args);
            return true;
        }
        catch
        {
            result = null;
            return false;
        }
    }
}

You could of course choose to lose the type-safety and go with a DynamicObject like I showed and then drop the duck-casting.

I made a transparant extendible version of this object proxy, and open-sourced it here.

orad
  • 15,272
  • 23
  • 77
  • 113
albertjan
  • 7,739
  • 6
  • 44
  • 74
  • Could you say just a word about how ImpromptuInterface works under the hood? That is, what technique does `ActLike` use to create an object of any type? Some kind of byte code generation? – Lii Aug 12 '15 at 11:49
  • @Lii I didn't develop ImpromptuInterface. But it uses the DLR to dynamically bind to functions on the ducktyped object. And then it uses that same trick to cast it to the Interface you specify. – albertjan Aug 12 '15 at 11:54
  • What's the performance impact of something like this? AFAIK `.GetType()` is not very performance friendly. – Blue Jun 11 '17 at 07:27
  • Yeah it's prolly a smart idea to examine the type on construction and drop all the functions in a dict. Ehhh I went for simplicity in my explanation not performance. – albertjan Jun 11 '17 at 07:29
  • @FrankerZ if you look at the my project here: https://github.com/curit/DynamicProxy/blob/master/DynamicProxy/ProxyFactory.cs#L85 you'll see I did it differently there. :) – albertjan Jun 14 '17 at 07:45
17

In addition to Castle.DynamicProxy, there is also LinFu.DynamicProxy on Github.

Matt Mills
  • 8,692
  • 6
  • 40
  • 64
Harry Steinhilber
  • 5,219
  • 1
  • 25
  • 23
15

I should have written this sooner, but never mind.

My issue had a special "gotcha" I needed to be able to proxy classes and not interfaces.

There are two solutions to this:

  1. RealProxy and friends, basically means using .NET Remoting. Requires one to inherit from ContextBoundObject.

  2. Building a proxy using System.Reflection.Emit as done by spring you can also look at the code of their ProxyFactoryObject. Here are another three articles on the subject.

    • This approach has the crucial disadvantage of limiting you to overriding only virtual members.
Dai
  • 141,631
  • 28
  • 261
  • 374
AK_
  • 7,981
  • 7
  • 46
  • 78
  • No. But you can follow the links and find far better examples and explenations than anything I can write here. – AK_ Apr 02 '15 at 18:28
7

.NET 6.0 has added a new candidate to the Reflection namespace: the DispatchProxy. The team is announcing it here. A sample usage is contained in the article.

Dejan
  • 9,150
  • 8
  • 69
  • 117
5

Take a look at PostSharp. I don't know of a way to do what you want in vanilla .Net, but PostSharp offers things like "OnMethodBoundaryAspect" which can be used to either replace or wrap the code inside the method.

I've used it to do things like logging, parameter validation, exception handling etc.

There is a free Community Edition, which should work for you. You'll need it installed on your development machine, as well as any build server that you use.

Community
  • 1
  • 1
NeilD
  • 2,278
  • 3
  • 24
  • 28
2

Another option is ContextBoundObject.

There was an article on CodeProject about 8-9 years back using this approach to trace method calls.

leppie
  • 115,091
  • 17
  • 196
  • 297
0

For adding any functionality before and after of every function in a class, Real proxy is a good approach.

So now in T can be any TestClass. Create Instance like this for TestClass-

var _instance=(object)DynamicProxy(TestClass).GetTransparentProxy();

The code for Dynamic Proxy-

 class DynamicProxy<T> : RealProxy
    {
        readonly T decorated;

        public DynamicProxy(T decorated) : base(typeof(T))
        {
            this.decorated = decorated;
        }

        public override IMessage Invoke(IMessage msg)
        {
            var methodCall = msg as IMethodCallMessage;
            var methodInfo = methodCall.MethodBase as MethodInfo;
            string fullMethodName = $"{methodInfo.DeclaringType.Name}.{methodCall.MethodName}";

            try
            {
                var result = methodInfo.Invoke(decorated, methodCall.InArgs);

                return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
            }

            catch (Exception e)
            {
                return new ReturnMessage(e, methodCall);
            }
            finally
            {
            }
        }
    }
0

You can't intercept all calls for static, not virtual, or private members unless you get the CLR to hooks into each every method/property call to that object and redirect call to fake one you created. You can achieve that by using the .NET Profiler API. TypeMock Isolator for example uses it monitor an application's execution and when method is called, CLR notifies typemock isolator which allows Isolator to override the original class completely.

0

You could do this with just DynamicObject from System.Danymic namespace, without using any third party libraries.

Example code:

public class DynamicProxy: DynamicObject
    {
        private readonly T _object;

        // The inner dictionary.
        Dictionary<string, object> dictionary = new Dictionary<string, object>();

        // Getting a property.
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return dictionary.TryGetValue(binder.Name, out result);
        }

        // Setting a property.
        // You can set up access control eg. if you don't want to 
        // set certain field, you can return false before putting
        // the value into the inner dictionary
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            if (binder.Name.Equals("Rating")) return false;
            dictionary[binder.Name] = value;
            return true;
        }

        public DynamicProxy(T object)
        {
            _object = object;
            dictionary["Name"] = object.GetName();
            dictionary["Gender"] = object.GetGender();
            dictionary["Interests"] = object.GetInterests();
            dictionary["Rating"] = object.GetGeekRating();
        }

        public string GetName()
        {
            return (string)dictionary["Name"];
        }

        public int GetGeekRating()
        {
            return (int)dictionary["Rating"];
        }
}

Then on the driver class:

dynamic dynamicProxy = new DynamicProxy(person);

That way, you can set and get the fields with access control.

jin bai
  • 101
  • 3