Question

In a call to the RealProxy base constructor, you pass the Type of the target object to be proxied. What I would like to do is dynamically add interfaces to the proxied type so that the resultant proxied type can be cast to the additional interfaces.

For example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace ConsoleApplication17
{
    class Program
    {
        static void Main(string[] args)
        {
            MyProxy<IFoo> proxy = new MyProxy<IFoo>(new Foo());

            IFoo proxiedFoo = (IFoo)proxy.GetTransparentProxy();

            // make a proxied call...
            proxiedFoo.DoSomething();

            // cast proxiedFoo to IDisposable and dispose of it...
            IDisposable disposableFoo = proxiedFoo as IDisposable;

            // disposableFoo is null at this point.

            disposableFoo.Dispose();
        }
    }
}

public interface IFoo
{
    void DoSomething();
}

public class Foo : IFoo, IDisposable
{
    #region IFoo Members

    public void DoSomething()
    {
        //
    }

    #endregion

    #region IDisposable Members

    public void Dispose()
    {
        // dispose
    }

    #endregion
}

public class MyProxy<T> : RealProxy where T : class
{
    private T _target;

    public MyProxy(T target) :
        base(CombineType(typeof(T), typeof(IDisposable)))
    {
        this._target = target;
    }

    private static Type CombineType(Type type1, Type type2)
    {
        // How to implement this method, Reflection.Emit????
        throw new NotImplementedException();
    }

    public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
    {
        return InvokeRemoteCall((IMethodCallMessage)msg, this._target);
    }

    /// <summary>
    /// Invokes the remote call.
    /// </summary>
    /// <param name="methodCall">The method call.</param>
    /// <param name="target">The target.</param>
    /// <returns>A <see cref="ReturnMessage"/></returns>
    private static IMessage InvokeRemoteCall(IMethodCallMessage methodCall, object target)
    {
        MethodInfo method = methodCall.MethodBase as MethodInfo;

        object callResult = (target != null) ? method.Invoke(target, methodCall.InArgs) : null;

        LogicalCallContext context = methodCall.LogicalCallContext;

        var query = method.GetParameters().Where(param => ((ParameterInfo)param).IsOut);

        ParameterInfo[] outParameters = query.ToArray();

        return new ReturnMessage(callResult, outParameters, outParameters.Count(), context, methodCall);
    }
}
}

So in order to be able cast the proxied type to IDisposable, I need to be able to send IDisposable in addition to IFoo to the RealProxy base constructor call.

In essence, how do I implement this method to dynamically add IDisposable to IFoo to be proxied.

private static Type CombineType(Type type1, Type type2)
{
    // How to implement this method, Reflection.Emit????
    throw new NotImplementedException();
}
Was it helpful?

Solution 2

I solved it. Here is the full solution using Reflection Emit.

using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace ConsoleApplication17
{
    class Program
    {
        static void Main(string[] args)
        {
            MyProxy<IFoo> proxy = new MyProxy<IFoo>(new Foo());

            IFoo proxiedFoo = (IFoo)proxy.GetTransparentProxy();

            // make a proxied call...
            proxiedFoo.DoSomething();

            // cast proxiedFoo to IDisposable and dispose of it...
            IDisposable disposableFoo = proxiedFoo as IDisposable;

            // disposableFoo is null at this point.

            disposableFoo.Dispose();
        }
    }

    public interface IFoo
    {
        void DoSomething();
    }

    public class Foo : IFoo, IDisposable
    {
        #region IFoo Members

        public void DoSomething()
        {
            Console.WriteLine("DoSomething called!");
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            // dispose
            Console.WriteLine("Disposing Foo!");
        }

        #endregion
    }

    public class MyProxy<T> : RealProxy where T : class
    {
        private T _target;

        public MyProxy(T target) :
            base(CombineType(typeof(T), typeof(IDisposable)))
        {
            this._target = target;
        }

        private static Type CombineType(Type type1, Type type2)
        {
            // How to implement this method, Reflection.Emit????
            return DynamicInterfaceFactory.GenerateCombinedInterfaceType(type1, type2);
        }

        public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
        {
            return InvokeRemoteCall((IMethodCallMessage)msg, this._target);
        }

        /// <summary>
        /// Invokes the remote call.
        /// </summary>
        /// <param name="methodCall">The method call.</param>
        /// <param name="target">The target.</param>
        /// <returns>A <see cref="ReturnMessage"/></returns>
        private static IMessage InvokeRemoteCall(IMethodCallMessage methodCall, object target)
        {
            MethodInfo method = methodCall.MethodBase as MethodInfo;

            object callResult = (target != null) ? method.Invoke(target, methodCall.InArgs) : null;

            LogicalCallContext context = methodCall.LogicalCallContext;

            var query = method.GetParameters().Where(param => ((ParameterInfo)param).IsOut);

            ParameterInfo[] outParameters = query.ToArray();

            return new ReturnMessage(callResult, outParameters, outParameters.Count(), context, methodCall);
        }
    }

    public static class DynamicInterfaceFactory
    {
        public static Type GenerateCombinedInterfaceType(Type type1, Type type2)
        {            
            if (!type1.IsInterface)
                throw new ArgumentException("Type type1 is not an interface", "type1");

            if (!type2.IsInterface)
                throw new ArgumentException("Type type2 is not an interface", "type2");

            //////////////////////////////////////////////
            // Module and Assembly Creation

            var orginalAssemblyName = type1.Assembly.GetName().Name;

            ModuleBuilder moduleBuilder;

            var tempAssemblyName = new AssemblyName(Guid.NewGuid().ToString());

            var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
                tempAssemblyName,
                System.Reflection.Emit.AssemblyBuilderAccess.RunAndCollect);

            moduleBuilder = dynamicAssembly.DefineDynamicModule(
                tempAssemblyName.Name,
                tempAssemblyName + ".dll");


            var assemblyName = moduleBuilder.Assembly.GetName();

            //////////////////////////////////////////////

            //////////////////////////////////////////////
            // Create the TypeBuilder

            var typeBuilder = moduleBuilder.DefineType(
                type1.FullName,
                TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);

            typeBuilder.AddInterfaceImplementation(type1);
            typeBuilder.AddInterfaceImplementation(type2);

            //////////////////////////////////////////////

            //////////////////////////////////////////////
            // Create and return the defined type

            Type newType = typeBuilder.CreateType();

            return newType;

            //////////////////////////////////////////////
        }
    }
}

The key was to create a new interface type that is a combination of the two interfaces passed in. Then RealProxy can map the new dynamic interface methods to our MyProxy Invoke method to which we then can invoke the appropriate method.

Look at the call now to CombineType:

private static Type CombineType(Type type1, Type type2)
{
    // How to implement this method, Reflection.Emit????
    return DynamicInterfaceFactory.GenerateCombinedInterfaceType(type1, type2);
}

That then creates a simple in-memory combined interface.

public static class DynamicInterfaceFactory
{
    public static Type GenerateCombinedInterfaceType(Type type1, Type type2)
    {            
        if (!type1.IsInterface)
            throw new ArgumentException("Type type1 is not an interface", "type1");

        if (!type2.IsInterface)
            throw new ArgumentException("Type type2 is not an interface", "type2");

        //////////////////////////////////////////////
        // Module and Assembly Creation

        var orginalAssemblyName = type1.Assembly.GetName().Name;

        ModuleBuilder moduleBuilder;

        var tempAssemblyName = new AssemblyName(Guid.NewGuid().ToString());

        var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
            tempAssemblyName,
            System.Reflection.Emit.AssemblyBuilderAccess.RunAndCollect);

        moduleBuilder = dynamicAssembly.DefineDynamicModule(
            tempAssemblyName.Name,
            tempAssemblyName + ".dll");


        var assemblyName = moduleBuilder.Assembly.GetName();

        //////////////////////////////////////////////

        //////////////////////////////////////////////
        // Create the TypeBuilder

        var typeBuilder = moduleBuilder.DefineType(
            type1.FullName,
            TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);

        typeBuilder.AddInterfaceImplementation(type1);
        typeBuilder.AddInterfaceImplementation(type2);

        //////////////////////////////////////////////

        //////////////////////////////////////////////
        // Create and return the defined type

        Type newType = typeBuilder.CreateType();

        return newType;

        //////////////////////////////////////////////
    }
}

Which is passed to the RealProxy c'tor

public class MyProxy<T> : RealProxy where T : class
{
    private T _target;

    public MyProxy(T target) :
        base(CombineType(typeof(T), typeof(IDisposable)))
    {
        this._target = target;
    }

Output of program:

DoSomething called!
Disposing Foo!
Press any key to continue . . .

This is not bulletproof yet but is a starter.

OTHER TIPS

There's a very simple, built-in way of achieving that. However, it is practically undiscoverable if one doesn't already know about it :-)

In order to be able to control what cast operations are valid on the transparent proxy associated\obtained from a certain RealProxy-derived class the RealProxy needs to implement an additional interface, namely IRemotingTypeInfo.

One of the methods defined by the IRemotingTypeInfo interfaces is bool CanCastTo(Type type, object o). This method is called every time an attempt is made to cast your proxy object to some other type; the "target" type of the cast operation is accessible via the type parameter.

So, to allow your proxy to "implement" multiple interfaces just return true from the CanCastTo() methods for the types you wish to support.

Please note that after the cast the method calls on the transparent proxy are still received by the same RealProxy instance.

For a more in-depth discussion you might read this MSDN article: Create a Custom Marshaling Implementation Using .NET Remoting and COM Interop

Here's a complete example:

interface IFaceA
{
    void MethodA();
}

interface IFaceB
{
    void MethodB();
}

class MultiFaceProxy : RealProxy, IRemotingTypeInfo
{
    public MultiFaceProxy()
        :base(typeof(IFaceA)) {}

    public bool CanCastTo(Type fromType, object o)
    {
        return fromType == typeof(IFaceA) || fromType == typeof(IFaceB);
    }

    public string TypeName
    {
        get { return GetProxiedType().FullName; }
        set { throw new NotSupportedException(); }
    }

    public override IMessage Invoke(IMessage msg)
    {
        // invoke logic
        return null;
    }
}

class Program
{
    static void Main(string[] args)
    {
        MultiFaceProxy proxy = new MultiFaceProxy();

        IFaceA ifa = (IFaceA) proxy.GetTransparentProxy();
        // The following now also works thanks to CanCastTo()
        IFaceB ifb = (IFaceB)ifa;
     }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top