41

I am trying to create a proxy class dynamically. I know there are some very good frameworks out there to do this but this is purely a pet project as a learning exercise so would like to do it myself.

If, for example, I have the following class implementing an interface:

interface IMyInterface
{
    void MyProcedure();
}

class MyClass : IMyInterface
{
    void MyProcedure()
    {
        Console.WriteLine("Hello World");
    }
}

To intercept methods to this class in order to log them, I am creating another class (my version of a proxy class) which implements the same interface but contains a reference to the 'real' class. This class performs an action (e.g. logging) and then calls the same method on the real class.

For example:

class ProxyClass : IMyInterface
{
    private IMyInterface RealClass { get; set; }

    void MyProcedure()
    {
        // Log the call
        Console.WriteLine("Logging..");

        // Call the 'real' method
        RealClass.MyProcedure();
    }
}

The caller then calls all methods on the proxy class instead (I am using a basic home-brew IoC container to inject the proxy class in place of the real class). I am using this method because I would like to be able to swap out RealClass at run time to another class implementing the same interface.

Is there a way to create ProxyClass at run time and populate its RealClass property so it can be used as a proxy for the real class? Is there a simple way to do this or do I need to use something like Reflection.Emit and generate the MSIL?

Tarik
  • 79,711
  • 83
  • 236
  • 349
Dave S
  • 1,403
  • 1
  • 15
  • 23
  • What do you mean generate dynamically? Do you mean you have a Type object and want to instantiate an object of this type? – JJ15k Mar 31 '13 at 20:10
  • Yes. I have would like to create an instance of ProxyClass at runtime from IMyInterface, populate its 'RealClass' property with a reference to a real class so it can be used to intercept all calls to the real class. I will edit the question to clarify thank you. – Dave S Mar 31 '13 at 20:14
  • 1
    See Castle's DynamicProxy http://www.castleproject.org/projects/dynamicproxy/ – Peter Ritchie Mar 31 '13 at 20:18

4 Answers4

60

Have a look at System.Runtime.Remoting.Proxies.RealProxy. You can use this to create an instance that appears to be the target type from the perspective of the caller. RealProxy.Invoke provides a point from which you can simply invoke the target method on the underlying type or perform additional processing before/after the call (logging, for example).

Here's an example of a proxy that logs to the console before/after each method invocation:

public class LoggingProxy<T> : RealProxy
{
    private readonly T _instance;

    private LoggingProxy(T instance)
        : base(typeof(T))
    {
        _instance = instance;
    }

    public static T Create(T instance)
    {
        return (T)new LoggingProxy<T>(instance).GetTransparentProxy();
    }

    public override IMessage Invoke(IMessage msg)
    {
        var methodCall = (IMethodCallMessage)msg;
        var method = (MethodInfo)methodCall.MethodBase;

        try
        {
            Console.WriteLine("Before invoke: " + method.Name);
            var result = method.Invoke(_instance, methodCall.InArgs);
            Console.WriteLine("After invoke: " + method.Name);
            return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: " + e);
            if (e is TargetInvocationException && e.InnerException != null)
            {
                return new ReturnMessage(e.InnerException, msg as IMethodCallMessage);
            }

            return new ReturnMessage(e, msg as IMethodCallMessage);
        }
    }
}

Here is how you would use it:

IMyInterface intf = LoggingProxy<IMyInterface>.Create(new MyClass());
intf.MyProcedure();

The output to console would then be:

Before invoke: MyProcedure
Hello World
After invoke: MyProcedure

bradmo
  • 784
  • 6
  • 7
  • 2
    This is what I was looking for and has pointed me in the right direction. Thank you. – Dave S Apr 01 '13 at 21:14
  • 26
    An important limitation, however, is that the type to wrap into the proxy should derive from MarshalByRefObject. – Piedone Nov 03 '13 at 23:03
  • 2
    @Piedone, type to wrap should be an interface or derive from MarshalByRefObject – chapluck Jan 28 '17 at 21:33
  • 1
    I spent a couple hours implementing a proxy using this approach only to run into a marshaling error. This is not useful unless you can restructure your class hierarchy to derive from MarshalByRefObject. – Leonardo Raele Nov 24 '18 at 21:06
  • 1
    For .NET Core: https://stackoverflow.com/q/38467753 – Pang Oct 19 '20 at 08:18
2

I wouldn't recommend doing this. Usually you use some well-known libraries such as Castle or EntLib. For some complicated classes it could be quite a challenge to dynamically generate a proxy. Here is an example of doing that using "Is" polymorphism. For this you have to declare all your methods in base as virtual. The way you were trying to do this ("Has") also possible, but for me looks more complicated.

public class A
{
    public virtual void B()
    {
        Console.WriteLine("Original method was called.");
    }
}

class Program
{

    static void Main(string[] args)
    {
        // Create simple assembly to hold our proxy
        AssemblyName assemblyName = new AssemblyName();
        assemblyName.Name = "DynamicORMapper";
        AppDomain thisDomain = Thread.GetDomain();
        var asmBuilder = thisDomain.DefineDynamicAssembly(assemblyName,
                     AssemblyBuilderAccess.Run);

        var modBuilder = asmBuilder.DefineDynamicModule(
                     asmBuilder.GetName().Name, false);

        // Create a proxy type
        TypeBuilder typeBuilder = modBuilder.DefineType("ProxyA",
           TypeAttributes.Public |
           TypeAttributes.Class |
           TypeAttributes.AutoClass |
           TypeAttributes.AnsiClass |
           TypeAttributes.BeforeFieldInit |
           TypeAttributes.AutoLayout,
           typeof(A));
        MethodBuilder methodBuilder = typeBuilder.DefineMethod("B", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot);
        typeBuilder.DefineMethodOverride(methodBuilder, typeof(A).GetMethod("B"));


        // Generate a Console.Writeline() and base.B() calls.
        ILGenerator ilGenerator = methodBuilder.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.EmitWriteLine("We caught an invoke! B method was called.");

        ilGenerator.EmitCall(OpCodes.Call, typeBuilder.BaseType.GetMethod("B"), new Type[0]);
        ilGenerator.Emit(OpCodes.Ret);

        //Create a type and casting it to A. 
        Type type = typeBuilder.CreateType();
        A a = (A) Activator.CreateInstance(type);

        // Test it
        a.B();
        Console.ReadLine();
    }
}
Archeg
  • 8,364
  • 7
  • 43
  • 90
1

You can use dynamic objects as described in this question, but for a dynamically-generated, strongly-typed object you'll have to use Reflection.Emit, as you suspected. This blog has example code showing the dynamic creation and instantiation of a Type.

I have read that Roslyn has features which make creation of dynamic proxies easier, so maybe take a look there, too.

Community
  • 1
  • 1
Steve Wilkes
  • 7,085
  • 3
  • 29
  • 32
0

Maybe I have misunderstood the question, how about a constructor?

class ProxyClass : IMyInterface
{
    public ProxyClass(IMyInterface someInterface)
    {
        RealClass = someInterface;
    }
   // Your other code...
}
Jason
  • 1,385
  • 9
  • 11