I'm trying to wrap my head around reflection, so I decided to add plugin capability to a program that I'm writing. The only way to understand a concept is to get your fingers dirty and write the code, so I went the route of creating a simple interface library consisting of the IPlugin and IHost interfaces, a plugin implementation library of classes that implement IPlugin, and a simple console project that instantiates the IHost implementation class that does simple work with the plugin objects.
Using reflection, I wanted to iterate through the types contained inside my plugin implementation dll and create instances of types. I was able to sucessfully instantiate classes with this code, but I could not cast the created object to the interface.
I tried this code but I couldn't cast object o as I expected. I stepped through the process with the debugger and the proper constructor was called. Quickwatching object o showed me that it had the fields and properties that I expected to see in the implementation class.
loop through assemblies
loop through types in assembly
// Filter out unwanted types
if (!type.IsClass || type.IsNotPublic || type.IsAbstract )
continue;
// This successfully created the right object
object o = Activator.CreateInstance(type);
// This threw an Invalid Cast Exception or returned null for an "as" cast
// even though the object implemented IPlugin
IPlugin i = (IPlugin) o;
I made the code work with this.
using System.Runtime.Remoting;
ObjectHandle oh = Activator.CreateInstance(assembly.FullName, type.FullName);
// This worked as I intended
IPlugin i = (IPlugin) oh.Unwrap();
i.DoStuff();
Here are my questions:
Activator.CreateInstance(Type t) returns an object, but I couldn't cast the object to an interface that the object implemented. Why?
Should I have been using a different overload of CreateInstance()?
What are the reflection related tips and tricks?
Is there some crucial part of reflection that I'm just not getting?
I'm just guessing here because from your code it's not obvious where do you have definition of IPlugin interface but if you can't cast in your host application then you are probably having IPlugin interface in your host assembly and then at the same time in your plugin assembly. This won't work.
The easiest thing is to make this work is to have IPlugin interface marked as public in your host assembly and then have your Plugin assembly reference host application assembly, so both assemblies have access to the very same interface.
hmmm... If you are using Assembly.LoadFrom to load your assembly try changing it Assembly.LoadFile instead.
Worked for me
From here: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx
#lubos hasko
You nailed it on the nose. My original design did have three different assemblies with both the host and plugin implementation referencing the plugin interface assembly.
I tried a separate solution with a host implementation and interface assembly and a plugin implementation assembly. Within that solution, the code in the first block worked as expected.
You've given me a bit more to think about, because I'm not quite understanding why two assemblies referencing a common assembly don't get the same type out of the common assembly.
I was just trying to work this out myself and managed to stumble on the answer!
I had 3 different C# projects
A - Plugin Interface project
B - Host exe project -> references A
C - Plugin Implementation project -> references A
I was getting the casting error as well until I changed the assembly name for my Plugin Interface proj to match the namespace of what I was trying to cast to.
E.g.
IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);
was failing because the assembly that the IPluginModule interface was defined in was called 'Common', The -type- I was casting to was 'Blah.Plugins.Common.IPluginModule' however.
I changed the Assembly name for the interface proj to be 'Blah.Plugins.Common' meant that the cast then succeeded.
Hopefully this explanation helps someone. Back to the code..
Is your type not public, if so, call the overload that takes in a boolean:
Activator.CreateInstance(type, true);
Also, in your first example, see if o is null and if not, print out o.GetType().Name to see what it really is.
#Haacked
I tried to keep the pseudocode simple. foreach's take up a lot of space and braces. I clarified it.
o.GetType().FullName returns Plugins.Multiply which is the expected object. Plugins.Multiply implements IPlugin. I stepped through the process in the debugger quite a few times until I gave up for the evening. Couldn't figure out why I couldn't cast it because I watched the constructor fire until I got grumpy about the whole mess. Came back to it this evening and made it work, but I still don't understand why the cast failed in the first code block. The second code block works, but it feels off to me.
The link to egghead above is the main solution to the problem use Assembly.LoadFile() instead of .LoadFrom()
Related
I'm working with one application that that has and C# API. This program has different versions of it. But the api stays the same through its versions.
So i have written a managed code to one of its versions, and now i want to run the same code at different version of the application at runtime where i exactly know witch version of the app is running.
Question is:
Is it possible to replace assembly version and dll location at run time without writing unmanaged code using reflections?
Yes, you can use Assembly.LoadFrom to load an assembly. You can then use reflection to go thru the types of said assembly and call methods.
To avoid needing to use reflection for everything there should be a shared interface-assembly that define your api. There should also be a single entry point to the API. So you can use reflection find the class that implements the entry-interface, create an instance of this class and cast it to the interface. That lets the rest of the code use actual types.
You still need to be careful however, if there is any miss match between the interface and the actual types, you will get an runtime exception. You will not get an exception when the interface method is called (as might be expected), but when the method that calls the interface method is called. This due to the jitter resolving types when a method is compiled, and this is done the first time it is called.
I have a .NET dll wrapper around a mixed (Managed/Unmanaged) type. If some crucial dll's are missing from the hard drive or their location is not entered into the path, then the type will not load resulting in a TypeLoadException("Could not load file or assembly or one of its dependencies"). This hampers xcopy deployability of any utility that consumes this class library.
I would prefer to fix this problem without instructing all clients to change client code. I hope to achieve this by running code before the type is loaded by the CLR. I have included its dependencies in a zip file which is included with the distribution.
Clients call into a static factory method.
var MyMixedTypeInstance = MyMixedType.Create();
However, since the factory method signature return type is MyMixedType, then MyMixedType is attempted loaded before any code inside the create method is executed. I have considered make the return type an interface to avoid this. But if the interface at some deals with (eg returns) a concrete mixed type, then AFAICT I'm back to square one.
I attempted stuff like using a static constructor, but it seems (as maybe all of you others know) that types exposed by the public API are immediately loaded. However, I do not know much about how the loading of types unfold, so I may be missing something obvious. I know that you can help the CLR resolve assemblies, but I do not know if this relates to a type.
Naturally, it would be possible to create a complete separate "MakeSureNeededBinariesAreInPlaceAndInPath" kind of method and demand/force all clients to invoke it prior to calling the Create() method, but I would like to avoid it if I can.
Is there for instance any attribute I can decorate the type with to intercept the type loading of the class?
I have this as the main class of my dll:
namespace PTEmu
{
public class DatabaseProtocol : IDatabaseProtocol
{
(constructors and methods)
}
}
This code I use to Load the DLL and create an instance of the class
var assembly = Assembly.LoadFrom("database\\" + file);
var t = assembly.GetType("PTEmu.DatabaseProtocol");
var protocol = Activator.CreateInstance(t) as IDatabaseProtocol;
Assembly.LoadFrom, assembly.GetType and Activator.CreateInstance itself, doesn't throw any errors.
I can't see what is wrong, sice I took this piece of code from another project that worked fine with it.
If I remove as IDatabaseProtocol, it returns an object, but not an object like the interface I want, so I can call the methods easily...
This is a problem of type identity. The identity of a type in .NET is not just the namespace name and type name. It also includes the assembly from which it came. So the mistake here is that you had two distinct interface types. One that came from your main assembly, another that came from the plugin assembly. Adding the source code file with Add Link isn't good enough, it matters which assembly the type got compiled into. Or in other words, the source code file plays no role at all in the type identity.
Notable perhaps is that this rule was changed in .NET 4. The identity of a type can be the solely determined by the value of the [Guid] attribute applied to the type. This enabled the "Embed Interop Types" feature in the properties of an assembly reference. Also known as the No PIA feature. It is however only valid on COM interface types. It put an end to having to install massive PIAs when you write code that automates Office apps.
You'll however have to do the exact equivalent of a PIA, a third assembly that defines the interface type and is referenced by both projects.
I solved my problem by adding a new project named framework that stores the interface. Then I referenced it in my two other projects.
Don't bother and don't waste your time!
Create a new DIFFERENT class library for interfaces
Create an interface in this new library
implement the interface in your class (other project)
try to re-run
TAADAAAM!!!
.net need this interface to be in OTHER class library and not the same one!!
I had almost similar issue. But in my case the interface was already in a different shared class library.
Solution was to set the "Copy Local" property for the shared reference project to "No".
I've got a .dll library I'm writing that interfaces with a proprietary COM assembly. My goal is to publish my work online once it's built, however I need to remove the COM assembly as a project reference to avoid distribution of this proprietary dll. So what I'm trying to be able to do is dynamically load the assembly at runtime, and invoke methods where I need them. Traditionally I've used object reflection for unknown types, however this can get slow at times, and involves several ugly instanciations. In .NET 4.0 is there a way to cleanly get all the methods and toss them into a dynamic class/interface at runtime?
I'm currently getting the object like this:
Type myClassType = Type.GetTypeFromProgID("MyClass.Myclass.1");
object classObj = Activator.CreateInstance(myClassType);
I thought I'd be able to use Type.GetMethods(), however it only returns the generic ones (Equals, ToString, GetLifetime..., etc.). I know the class uses an interface, so I tried looking into dynamically loading the interface also. That led me to Reflection.Emit, and the Microsoft.Xrm.Sdk, which I am failing to understand so far.
If there's a way for me to invoke methods without needing to throw a bunch of BindingFlags every few lines, I'd greatly appreciate a nudge in the right direction
I do have the GUID for both the Class and the Interface if that helps at all.
If I were at your situation(and if i have understand the problem correctly):
I would separate the Interface,s library (DLL) from implementation library(DLL)
Then the implementation library would be loaded dynamically and my main source code that is
referenced to Interface library would be complied
Type myClassType = Type.GetTypeFromProgID("MyClass.Myclass.1");
myClassIntrface classObj =
Activator.CreateInstance(myClassType) as myClassIntrface;
classObj.CallSomeInterfaceMethod();
hope this will be useful pal.
I am preparing for MCTS 70-536, after reading this article. I am not 100% sure I understand the concept of typeforwarding. I find the steps given in the article even more confusing. Whats the deal if I am copying the sourcecode of type to be forwarded and recompiling it. What happens with old dll and the client ??
Type forwarding allows you to relocate a type between assemblies. So originally it is TypeA in AssemblyA. By applying type-forwarding, you can end with TypeA in AssemblyB.
The subtlety is the code that is already compiled doesn't see the change - they ask for the type in AssemblyA, and the runtime silently gives them the type from AssemblyB. This is very important if you have existing code.
However; new code cannot be recompiled referencing TypeA without you referencing AssemblyB.
So:
old clients don't need to be recompiled
however, you do need to rebuild both AssemblyA and AssemblyB in the above example
new code (or any recompiled code) must now reference AssemblyB (the new one)