Goal
I have a couple of interfaces and some dlls that provide implementations for these interfaces. I want to load the implementation into a new AppDomain (so I can unload the dll later) and instatiate the implementation in the new AppDomain and then use a clientside(here the default AppDomain) proxy to wrap the actual implementation object. The goal is to create these ClientProxy
instances once and change their actual implementations whenever while not loading the implementations assembly into the default AppDomain.
Problem
When calling a method on the ClientProxy __TransparentProxy object that gets another ClientProxy as argument I get the following Exceptions:
System.Runtime.Remoting.RemotingException:
'The argument type 'System.MarshalByRefObject' cannot be converted into parameter type 'IData'.'
With inner Exception:
InvalidCastException: Object must implement IConvertible.
When passing the __TransparentProxy obtained directly from the Server AppDomain the ClientProxy works.
Setup
Cloneable from: https://github.com/mailgerigk/remoting
Interfaces:
public interface IData
{
int Foo { get; set; }
}
public interface ILogic
{
void Update(IData data);
}
Interface Impl in _impl.dll:
public class DataImpl : MarshalByRefObject, IData
{
public int Foo { get; set; }
}
public class LogicImpl : MarshalByRefObject, ILogic
{
public void Update(IData data)
{
data.Foo++;
}
}
Serverside AssemblyLoader:
class AssemblyLoader : MarshalByRefObject
{
public Assembly Assembly { get; private set; }
public AssemblyLoader(string assemblyFile)
{
Assembly = Assembly.LoadFrom(assemblyFile);
}
public object CreateInstance(string typeName)
{
return Activator.CreateInstance(Assembly.GetType(typeName));
}
}
ClientProxy:
class ClientProxy : RealProxy
{
private RealProxy innerProxy;
public ClientProxy(Type interfaceType, object proxyObject)
: base(interfaceType)
{
SetInnerProxy(proxyObject);
}
public void SetInnerProxy(object proxyObject)
{
innerProxy = RemotingServices.GetRealProxy(proxyObject);
}
public override IMessage Invoke(IMessage msg)
{
return innerProxy.Invoke(msg);
}
}
Main:
class Program
{
static void Main(string[] args)
{
var app = AppDomain.CreateDomain("ImplDomain", null,
AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.RelativeSearchPath,
true);
var assmblyLoader = app.CreateInstanceFromAndUnwrap(
typeof(AssemblyLoader).Assembly.Location, typeof(AssemblyLoader).FullName,
false, BindingFlags.CreateInstance, null,
new object[]
{
"_impl.dll"
},
null, null) as AssemblyLoader;
var dataImpl = assmblyLoader.CreateInstance("DataImpl") as IData;
var logicImpl = assmblyLoader.CreateInstance("LogicImpl") as ILogic;
logicImpl.Update(dataImpl); // Works
Console.WriteLine(dataImpl.Foo); // prints 1
var clientDataProxy = new ClientProxy(typeof(IData), dataImpl);
var clientDataImpl = clientDataProxy.GetTransparentProxy() as IData;
var clientLogicProxy = new ClientProxy(typeof(ILogic), logicImpl);
var clientLogicImpl = clientLogicProxy.GetTransparentProxy() as ILogic;
clientLogicImpl.Update(dataImpl); // Works
Console.WriteLine(clientDataImpl.Foo); // prints 2
clientLogicImpl.Update(clientDataImpl); // throws System.Runtime.Remoting.RemotingException
Console.WriteLine(clientDataImpl.Foo);
}
}
IRemotingTypeInfo
and implement theCanCastTo
member (even though you've already specified theIData
interface in the constructor). Disclaimer: I could be wildly off base. Even if I am, though, you may be able to gleam more about what's happening by setting a breakpoint there. – SolanCanCastTo
gets called 4 times on theDataImpl
proxy with thefromType
arguments: 2xContextBoundObject
then 2xAppDomain
. Handing the call down to the impl proxy results in all 4 returningfalse
. – Vanatta