Getting interface methods from a dynamically loaded class in .NET - c#

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.

Related

Can I run code prior to a CLR type being loaded?

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?

Issue implementing public interface in C#

C# class libary - targetting .NET2 framework.
I'm trying to implement a public interface (exposed from a second referenced assembly) in a small class. The interface has only 3 methods: one is fine, but for some reason I can't implement the other two of them without the compiler complaining for each one that:
my class "does not implement InterFaceName.MethodName"
"InterFaceName.MethodName in explicit interface declaration is not a member of interface".
The only difference between the one method which compiles and the other two is that the problem methods each have a parameter which is an Office Interop (Word) type. The other parameters are either bool or members of other public interfaces.
I can add my class definition here if it helps, but I would need to do some paraphrasing since I'm not the "owner" of the other assembly (it is a commercial product) and I'm not sure how they'd feel about me "exposing" it...
That's kind of vague I know, but I'm hoping someone's run into this kind of error before.
Thanks for any pointers.
This can often happen if the referenced assembly is built against a different version of the Office Interop assemblies.
As a result, even though visibly the parameters declared for "MethodName" may appear to match the interface from the referenced assembly, since the assembly versions are different, the method declaration does not actually match the decleration from the referenced assembly.
Double check you are using the exact same version of the interop assemblies.

Using a type, without knowing about the dll

is it possible to use an interface type, that is defined in a huge external dll, without referencing that dll?
in other words, there will be one core or global dll, that references the external dll, and all the projects reference this global one, so the external dlls are hidden from the other projects.
I want to use the type in my code, while knowing only about the global AllInterfaces project.
can that work? and if so, what needs to be done for such a scenario?
Is it possible to use an interface type that is defined in a huge external dll, without referencing that dll at compile time?
Not really, no. The compiler has the reasonable expectation that the types it needs are available.
Is it possible to use an interface type that is defined in a huge external dll, without referencing that dll at runtime?
Yes. We added that feature to C# 4. The "proper" name for the feature is something like "Type Embedding with Type Equivalence", but everyone just calls it "No PIA".
The motivation for the feature is the one faced most obviously by Visual Studio Tools For Office developers. VSTO developers write C# code that customizes, say, an Excel spreadsheet with some managed code. They communicate with Excel via a managed interface, but of course Excel actually exposes a set of COM interfaces. To bridge that gap, the Office team supplies a Primary Interop Assembly, or PIA. The PIA is a huge external library that contains nothing but metadata that describes how the managed interfaces correspond to the unmanaged interfaces of the COM objects.
The problem is that the Office team does not by default install the PIA when your customer buys Office! Therefore you have to ship the PIA with your customization. And the PIA is so large, it is often many times the size of the customization, which makes your download longer. And so on; it's not an ideal situation by any means.
The No-PIA feature allows the compiler to link only the portions of the PIA you actually use into your library, so that you do not have to ship the PIA with it.
Now, you might ask "what if I have two customizations that communicate with each other, and both use the IFoo interface from a PIA that I am not shipping?" The runtime identifies types by the assembly they came from, and so the two IFoo interfaces would be considered different types, and therefore not compatible.
The "No PIA" feature takes this into account as well. It does the same trick you use in COM to solve this problem: the assembly instructs the runtime to unify all interfaces that have the same GUID into the same logical type even if they come from different assemblies. This thereby explains the requirement that every interface that you use with "no PIA" has to be marked as though it were a COM interop interface with a GUID.
On the command line, use /L instead of /R to reference an assembly as a "no PIA" assembly.
Do a web search on "no PIA" and you'll find more information on this feature.
If you want to use that interface type in your code, that interface should be visible to your code. You code won't compile.
You can write adapter interface in your global dll, for the original interface and use that every where.
It cannot be done statically but you can do it using reflection.
With C# 4 you can use the dynamic keyword.
However, I fail to see how not knowing the interface in advance is going to help you - how are you going to know which methods to call?
You are trying to fool type identity. The CLR identifies a type by these properties:
Assembly display name
[AssemblyVersion]
[AssemblyCulture]
The assembly's PublicKeyToken value
The assembly's processor architecture (implicit)
The type's namespace name
The type's name.
Faking the type namespace name and name isn't difficult, the hard thing to do is faking the assembly properties. You are dead in the water if the assembly is strong-named (non-null PublicKeyToken) or if it is stored in the GAC, you can't get the substitute loaded. Faking the culture and architecture isn't hard to do, you'll have to get the display name and version right.
And of course, you'll have to get the interface declaration exactly right. Intentionally invoking DLL Hell like this is otherwise an Extremely Bad Idea. Not in the least because you now can never get the real assembly loaded.

get information on an assembly

I want to get information on an Assembly in my C# application. I use the following:
Assembly.GetCallingAssembly();
This works perfectly returning information on the calling Assembly.
I want to share this functionality with other applications, so I include this in a class in my class library.
I reference this class library in multiple applications. When I make a call to this method from my applications, it returns information on the class library and not the application. Is there a way I can alter my above code to return information on the web applications assembly while still having the code included in the class library?
Instead of having the class library being intelligent why don't you have the caller pass an Assembly as argument to the method? So when you call the method from within some application you would pass Assembly.GetExecutingAssembly() and the method within the class library will now be able to fetch the assembly of the actual caller.
I'm not sure what you provide on top of reflections, but maybe you're abstracting a facility that doesn't need to be abstracted. Reflections already handles this, so why not let it do its job?
But if this API gives you back some useful information (such as plugging nicely into your database, etc), then maybe your approach makes some sense. But I still recommend that you refactor it:
Put this code in only one shared project/assembly, and just link that project/assembly when you need to call that functionality. Needing to duplicate code to get your job done is considered code smell.
Take an Assembly object as a parameter, rather than trying to determine the current assembly. This will allow more flexibility in case you come up with some code that wants to get data on a bunch of other assemblies, and will still allow you to pass the current assembly. (Note: Darin already made this point)

How to properly cast objects created through reflection

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()

Categories

Resources