I have a problem that is not uncommon when building a plug-in architecture.
-
Assembly A is the core code — the framework.
-
Assembly B is a plugin to that code, expected to load dynamically at runtime and make code available for Assembly A to use.
In Visual Studio, Project B (which generates Assembly B) has a reference to Project A (which generates Assembly A), so it can reference the types in Project A and compile just fine. Both projects compile without error and generate DLLs.
But, at runtime, I get cast exceptions like this:
'MyType' cannot be converted to type 'MyType'
I’ve come to understand that a type defined in one project and referenced in another are considered different types at runtime, even if they resolve fine at compile time.
But, I thought this could be fixed by loading Assembly B into the correct context. So I switched from ‘Assembly.LoadFrom’ to ‘Assembly.Load’ and put Assembly B in the probing path. The idea is that it would load into the same context as Assembly A, and they would be one big, happy family.
I downloaded the Fusion log viewer and watched the assemblies load. Both Assembly A and Assembly B load like this:
Assembly is loaded in default load context.
So, I have ensured they are both loaded in the same load context.
Still, I can’t share types between the two Assemblies. I get casting errors when I try to pass an object (whose type is defined in Assembly A) as a parameter from code in Assembly A to a method on an object in Assembly B.
To summarize:
-
MyType is defined in Assembly A
-
From Assembly A, I load Assembly B at runtime into the same load context using ‘Assembly.Load’
-
From Assembly A, I use Reflection to invoke a static method on a class in Assembly B. I pass this method an object of MyType as a parameter (which is expected, and which compiled just fine).
-
Fails with: ‘MyType’ cannot be converted to type ‘MyType’
Here’s the code I use to invoke the method, if that matters. This code executes in Assembly A:
TypeFromAssemblyB.GetMethod('MyMethod').Invoke(null, new object[] { ObjectOfTypeDefinedInAssemblyA });
I was sure this should work as you’ve described it, so I wrote a quick and dirty example. My entry assembly is called PluginTest and contains the following class:
And my plugin assembly is called Plugin. It references the PluginTest project in Visual Studio and only contains this class:
Finally back in PluginTest (the executable) I have this code in Main:
As expected this pops up a console window and writes ‘Hello World’ to it. So, in principle, what you are trying to do should work…
(On preview I like Jonathan’s idea that it may be a version mismatch – do a clean build of the entire solution and make sure that all the dlls get copied to the right folders)