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?
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.
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.
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.
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.
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
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(); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With