I'm trying to load a type from a different assembly (not known at build time) as 'dynamic' and execute a method on that type. My goal is to completely disconnect the 'plugin' from the parent application such that there is no requirement for any shared code or common interface type. The interface is implied by way of an expected method signature on the loaded type.
This works:
dynamic myObj = Assembly.Load("MyAssembly").CreateInstance("MyType");
myObj.Execute();
However this will load the type into the current AppDomain along with all its dependent assemblies. I want to modify this to allow me to do that same thing in a separate AppDomain.
This works but doesn't make use of the dynamic keyword, I need to know the explicit type that I am instantiating to be able to call the Execute method:
var appDomain = AppDomain.CreateDomain(domainName, evidence, setup);
var myObj = appDomain.CreateInstanceAndUnwrap(assembly, type);
typeof(IMyInterface).InvokeMember("Execute", BindingFlags.InvokeMethod, null, myObj);
This is essentially my target case and I have been trying to get something like this working:
dynamic myObj = ad.CreateInstanceAndUnwrap(assembly, type);
myObj.Execute();
I keep ending up with a RuntimeBinderException with the message "'System.MarshalByRefObject' does not contain a definition for 'Execute'". This message makes sense, sure it doesn't contain a definition for 'Execute', but I know the type that I am instantiating does indeed contain an 'Execute' method. I imagine there's something going on here with the transparent proxy that is preventing this from working but I'm not sure what.
My actual class that I am trying to instantiate looks like this:
[Serializable]
public class MyClass : MarshalByRefObject {
public void Execute() {
// do something
}
}
I have also tried this with a shared interface (not my primary goal, but I'm trying to figure this out first) so it would look like:
[Serializable]
public class MyClass : MarshalByRefObject, IPlugin {
public void Execute() {
// do something
}
}
Where IPlugin is a known type in the parent application and the plugin has the appropriate reference at build time but this doesn't seem to work either.
I'm guessing at this point that it's not possible to load a type as dynamic across the AppDomain boundary.
Is there a way to actually get this to work?
As leppie indicated, you'll have to implement the IDynamicMetaObjectProvider
interface to wrap the proxy that's being returned to you, and then you can use make dynamic
calls on that.
In your implementation, you'd want to take the wrapped proxy and forward all calls to the static ExecuteMessage
method on the RemotingServices
class, which will take your proxy, as well as an IMethodCallMessage
interface implementation.
Note that implementing the IMethodCallMessage
interface is not trivial. Also, you'd have to properly interpret the IMethodReturnMessage
interface implementation to get the return value, ref
and out
parameters correctly (if any).
That said, it's generally a better idea to provide an assembly that contains only an interface for the client and server to assume; if a method is changed in any way on the server side, even though the client side uses dynamic
, you'd still have to change the call site to accommodate the change. At least with the interface, you get some type of compile-time check, which is always preferred to a run-time error.
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