Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically creating a proxy class

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?

like image 429
Dave S Avatar asked Mar 31 '13 20:03

Dave S


People also ask

What is dynamic proxy class in Java?

A dynamic proxy class is a class that implements a list of interfaces specified at runtime such that a method invocation through one of the interfaces on an instance of the class will be encoded and dispatched to another object through a uniform interface.

What will you use Java dynamic proxies API?

Dynamic proxies allow one single class with one single method to service multiple method calls to arbitrary classes with an arbitrary number of methods. A dynamic proxy can be thought of as a kind of Facade, but one that can pretend to be an implementation of any interface.

What is a dynamic proxy invocation handler?

Java Language Reflection API Dynamic Proxies A Dynamic Proxy is an instance of an interface that is created with a so-called invocation handler that intercepts all method calls and allows the handling of their invocation manually.

What is dynamic proxy in spring?

Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice). If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used.


2 Answers

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

like image 126
bradmo Avatar answered Oct 19 '22 03:10

bradmo


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();     } } 
like image 37
Archeg Avatar answered Oct 19 '22 05:10

Archeg