Dynamically Loading a DLL - c#

I am trying to simply load a dll written in C# at run time and create an instance of a class in that dll.
Assembly a = Assembly.LoadFrom(#"C:\Development\DaDll.dll");
Type type = a.GetType("FileReleaseHandler", true);
TestInterface.INeeedHelp handler = Activator.CreateInstance(type) as TestInterface.INeeedHelp;
No errors are thrown, and if I step through the code I can walk though the FileReleaseHandler Class as it executes the constructor but the value of handler is always null.
What am I missing here? or even is there a better way I should be going about this?

Where is TestInterface.INeedHelp defined? One common problem is if you've got the same interface in multiple assemblies. If both the caller and the dynamically loaded assembly reference the same interface in the same assembly, it should be okay.
One subtlety is that if the assembly is in a different directory to the calling assembly, it may end up loading a different copy of the same assembly, which can be very irritating :(

Try setting the result of Activator.CreateInstance to an object directly, and not casting.
It's possible FileReleaseHandler does not implement TestInterface.INeeedHelp, in which case, this will be set to null via the "as TestInterface.INeeedHelp".

Check the assemblies that are loaded into the application domain. Are there two assemblies with the TestInterface.INeedHelp interface in it? My suspicion is that the LoadFrom is binding this created object to a different TestInterface.INeedHelp than the one to which you are trying to cast. Try doing a normal downcast rather than a so-called "safe" cast and see what error you get.

The problem is that the LoadFrom method loads the dll into "LoadFrom" context which is different from the default context. The rules of type resolution for the types in this context differ from the ones you are used to. It is possible that the INeedHelp interface as defined in your main module from the standpoint of the runtime is different from the interface with the same name as coming from the LoadFrom context. This will cause the cast (as TestINterface) return null.
To see if this is the case try to assign the result to an object.

I would do something like :
Assembly a = Assembly.LoadFrom(#"C:\Development\DaDll.dll");
object obj = a.CreateInstance("fullClassName",other params) as IMyType
//(if it implements an interface you referenced)

Related

Why does this generic cast fail

I have the following code:
kAIDataPort<T> lOtherEndCast = ( kAIDataPort<T>)lOtherEnd;
Which raises the following exception:
[A]kAI.Core.kAIDataPort`1[UnityEngine.GameObject] cannot be cast to
[B]kAI.Core.kAIDataPort`1[UnityEngine.GameObject]. Type A originates from 'kAICore...
(Exception shrunk for readability, but there is no difference between A and B.
All the other questions on generic casting seem to relate to lists and inherited types, but here we just have an object of a certain type and not being able to cast it to precisely that type.
Not looking for a work around, I am using a non-generic base class with a non-typed method to do what I need to do, I just want to understand why this raises an exception.
This is in .NET 3.5 (since using Unity which still doesn't support .NET 4...)
Full exception:
[A]kAI.Core.kAIDataPort`1[UnityEngine.GameObject] cannot be cast to
[B]kAI.Core.kAIDataPort`1[UnityEngine.GameObject].
Type A originates from 'kAICore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'E:\dev\C#\kAI\kAI-Editor\bin\Debug\kAICore.dll'.
Type B originates from 'kAICore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'E:\dev\C#\kAI\kAI-Editor\bin\Debug\kAICore.dll'.
Update:
The problem was loading the Unity DLL twice, but it was loading the same DLL (but never unloading). The code for this is:
FileStream lDLLStream = lDllPath.GetFile().OpenRead();
byte[] lDLLArray = new byte[lDLLStream.Length];
lDLLStream.Read(lDLLArray, 0, (int)lDLLStream.Length);
lDLLStream.Close();
Assembly lLoadedAssembly = Assembly.Load(lDLLArray);
// Force the loading of the dll
lLoadedAssembly.GetExportedTypes();
return lLoadedAssembly;
The path was the same both times, so why would the case get confused about which dll to load from?
Further, loading the DLL twice this way and examining the following things just before the exception I get:
this.GetType().Equals(lOtherEnd.GetType()) false
but on the generic argument:
typeof(T).Equals(lOtherEnd.GetType().GenericTypeArguments[0]) true
It's a generic type - the cast checks four types: T1<T2> versus T3<T4>.
So, the collision can be either T1<G> vs T2<G> OR it can be T<G1> vs T<G2>.
The debug messages only printed information about 'T' and indeed it seems the same. So, check the Gs.
EDIT:
Now I would not guess you'd do that. You were precisely generating multiple images of the same assembly. All types created from them would always be different.
An assembly that is loaded FROM BYTES is never 'equal' to any other assembly. It is always loaded with new handle and never "coerced/collapsed" with any already loaded assembly. It is always described as having null codebase/location and treated similarily to "dynamic assemblies", created on-the-fly. ( I tried to find a reference for that and I cannot. I'm still quite sure about it, but I'm striking it just to warn you that it may not be true. Here's a starter for reading about assembly loading contexts: What are 3 kinds of Binding Contexts for? )
Why do you load it from raw bytes? Load it from FILE/PATH. Then it will get its codebase/location set properly and multiple loads will results in only one handle in memory.
It seems you're casting a type T1 from assembly A1 to T1 in assembly A2. Indeed both are not same. So it fails.

Unable to cast System.Runtime.Remoting.ObjectHandle

In my code I have an interface - lets say its called InterfaceName and its implementation called InterfaceImpl. Now when I dynamically try to obtain the InterfaceImpl using the following code:
object obj = Activator.CreateInstance("ProjectName","ProjectName.Folder.InterfaceImpl");
InterfaceName in = (InterfaceName)obj; //Error pops up here
I get the following error
Unable to cast object of type 'System.Runtime.Remoting.ObjectHandle' to type 'ProjectName.Folder.InterfaceName'.
Any suggestions on what might be going wrong ?
If you read the documentation about the method you are calling, it returns
A handle that must be unwrapped to access the newly created instance.
Looking at the documentation of ObjectHandle, you simply call Unwrap() in order to get the instance of the type you are trying to create.
So, I guess your real issue is... Why?
This method is designed to be called in another AppDomain, and the handle returned back to the calling AppDomain, where the proxy to the instance is "unwrapped".
What? That doesn't explain why?
Only two types can cross an AppDomain barrier. Types that are serializable (of which copies are created), and types that extend MarshalByRefObject (of which proxies are created and passed). ObjectHandle extends MarshalByRefObject, and so can cross that AppDomain barrier, whereas the type which they are representing may not extend MBRO or be serializable. This method ensures you can get that type instance across the barrier, no matter what.
So, if you are just trying to instantiate a type, you might want to look at a different overload of CreateInstance. Or just unwrap the result.
var obj = Activator.CreateInstance("A","A.B.C") as ObjectHandle;
InterfaceName in = (InterfaceName)obj.Unwrap();

InvalidCastException when creating an instance using assembly.CreateInstance

I'm looking for an explanation for the following -
I have an assembly I'm loading using
Assembly assembly = Assembly.LoadFrom(filename);
I then loop on all the types in the assembly, and wish to try and find out if a type implements a particular interface and if so I want an instance of that type, I've tried several things which did not work, but when I fell back to the most basic (and probably inefficient) way, I realised there's something more fundamental I don't understand -
foreach (Type t in assembly.GetTypes())
{
foreach (Type i in t.GetInterfaces())
{
if (i.FullName == pluginInterfaceType.FullName)
{
object o = assembly.CreateInstance(t.ToString());
IInterface plugin = (IInterface)o;
That last line causes an InvalidCastException, despite the fact that the type created definitely implements that interface.
Further more - if I use Activator.CreateInstance instead of Assembly.CreateInstance (which I don't want to do), casting to the interface works just fine.
This is most probably because the interface you are casting to is not the same you find in the class.
Either because there is more the one interface with the same name, or because you loaded it more then once. For instance, because it is defined in the assembly you are dynamically loaded, and you try to cast it to the one that is statically bound.
The InvalidCastException should contain more details, like 'cannot cast x to y'.
My guess is that the assembly containing IInterface that you are loading is not exactly the same as the one your code was built against, maybe it's a local copy of a non strongly-named assembly.

Can I load a .NET assembly at runtime and instantiate a type knowing only the name?

Is it possible to instantiate an object at runtime if I only have the DLL name and the class name, without adding a reference to the assembly in the project? The class implements a interface, so once I instantiate the class, I will then cast it to the interface.
Assembly name:
library.dll
Type name:
Company.Project.Classname
EDIT: I dont have the absolute path of the DLL, so Assembly.LoadFile won't work. The DLL might be in the application root, system32, or even loaded in the GAC.
Yes. You need to use Assembly.LoadFrom to load the assembly into memory, then you can use Activator.CreateInstance to create an instance of your preferred type. You'll need to look the type up first using reflection. Here is a simple example:
Assembly assembly = Assembly.LoadFrom("MyNice.dll");
Type type = assembly.GetType("MyType");
object instanceOfMyType = Activator.CreateInstance(type);
Update
When you have the assembly file name and the type name, you can use Activator.CreateInstance(assemblyName, typeName) to ask the .NET type resolution to resolve that into a type. You could wrap that with a try/catch so that if it fails, you can perform a search of directories where you may specifically store additional assemblies that otherwise might not be searched. This would use the preceding method at that point.
Consider the limitations of the different Load* methods. From the MSDN docs...
LoadFile does not load files into the LoadFrom context, and does not resolve dependencies using the load path, as the LoadFrom method does.
More information on Load Contexts can be found in the LoadFrom docs.
Activator.CreateInstance ought to work.
IFace object = (IFace)Activator.CreateInstance( "AssemblyName",
"TypeName" )
.Unwrap();
Note: The type name must be the fully qualified type.
Example:
var aray = (IList)Activator.CreateInstance("mscorlib","System.Collections.ArrayList").Unwrap();
aray.Add(10);
foreach (object obj in aray)
{
Console.WriteLine(obj);
}
I found this question and some answers very useful, however I did have path problems, so this answer would cover loading library by finding bin directory path.
First solution:
string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFrom(assemblyPath);
Type T = assembly.GetType("Company.Project.Classname");
Company.Project.Classname instance = (Company.Project.Classname) Activator.CreateInstance(T);
Second solution
string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFile(assemblyPath);
(Company.Project.Classname) instance = (Company.Project.Classname) assembly.CreateInstance("Company.Project.Classname");
You can use same principle for interfaces (you would be creating a class but casting to interface), such as:
(Company.Project.Interfacename) instance = (Company.Project.Interfacename) assembly.CreateInstance("Company.Project.Classname");
This example is for web application but similar could be used for Desktop application, only path is resolved in different way, for example
Path.GetDirectoryName(Application.ExecutablePath)
It's Easy.
Example from MSDN:
public static void Main()
{
// Use the file name to load the assembly into the current
// application domain.
Assembly a = Assembly.Load("example");
// Get the type to use.
Type myType = a.GetType("Example");
// Get the method to call.
MethodInfo myMethod = myType.GetMethod("MethodA");
// Create an instance.
object obj = Activator.CreateInstance(myType);
// Execute the method.
myMethod.Invoke(obj, null);
}
Here's a reference link
https://msdn.microsoft.com/en-us/library/25y1ya39.aspx
Starting from Framework v4.5 you can use Activator.CreateInstanceFrom() to easily instantiate classes within assemblies.
The following example shows how to use it and how to call a method passing parameters and getting return value.
// Assuming moduleFileName contains full or valid relative path to assembly
var moduleInstance = Activator.CreateInstanceFrom(moduleFileName, "MyNamespace.MyClass");
MethodInfo mi = moduleInstance.Unwrap().GetType().GetMethod("MyMethod");
// Assuming the method returns a boolean and accepts a single string parameter
bool rc = Convert.ToBoolean(mi.Invoke(moduleInstance.Unwrap(), new object[] { "MyParamValue" } ));
Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");
Type type = assembly.GetType("MyType");
dynamic instanceOfMyType = Activator.CreateInstance(type);
So in this way you can use functions not with getting methodinfo,and then invoking it.You will do like this instanceOfMyType.MethodName();
But you can't use Intellisense because dynamic types are typed in runtime,not in compile time.
Yes. I don't have any examples that I've done personally available right now. I'll post later when I find some. Basically you'll use reflection to load the assembly and then to pull whatever types you need for it.
In the meantime, this link should get you started:
Using reflection to load unreferenced assemblies at runtime
((ISomeInterface)Activator.CreateInstance(Assembly.LoadFile("somePath").GetTypes()[0])).SomeInterfaceMethod();
You can load an assembly using *Assembly.Load** methods. Using Activator.CreateInstance you can create new instances of the type you want. Keep in mind that you have to use the full type name of the class you want to load (for example Namespace.SubNamespace.ClassName). Using the method InvokeMember of the Type class you can invoke methods on the type.
Also, take into account that once loaded, an assembly cannot be unloaded until the whole AppDomain is unloaded too (this is basically a memory leak).
Depending how intrinsic this kind of functionality is to your project, you might want to consider something like MEF which will take care of the loading and tying together of components for you.
Yes, it is, you will want to use the static Load method on the Assembly class, and then call then call the CreateInstance method on the Assembly instance returned to you from the call to Load.
Also, you can call one of the other static methods starting with "Load" on the Assembly class, depending on your needs.
You can do this things on this way:
using System.Reflection;
Assembly MyDALL = Assembly.Load("DALL"); //DALL name of your assembly
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // name of your class
object obj = Activator.CreateInstance(MyLoadClass);
I'm using .net5 (.net core 5). What I need to do is:
static void Main()
{
//...
AppDomain.CurrentDomain.AssemblyResolve += CciBaseResolveEventHandler;
Application.Run(new FormMain());
}
private static Assembly CciBaseResolveEventHandler(object sender, ResolveEventArgs args)
{
return Assembly.LoadFile($#"{Directory.GetCurrentDirectory()}\{nameof(CciBase)}.dll");
}
Change "CciBase" to your dll name.
Make sure the dll is in the same same folder with the exe.
Do it before the main process starts (Application.Run()).

How to add an assembly in other assembly?

I have a dll called Test.dll in which I have a class called ABC which has a method FindTYpe.
Now, I have a project called TestB and I have added the reference of Test.dll in TestB.
Now, if I am trying to find a type XYZ in TestB, from Test.ABC.FindTYpe(), it's throwing an exception, TypeNotLaoded Exception.
Please have a look at the problem and tell me how can I resolve it.
You'll need to post your code for FindType(). My guess is that you're doing something like;
System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
to find a list of types to search through, and the type in TestB.dll isn't in Test.dll, so the item isn't found.
You might want to try something like this instead;
/// <summary>
/// Returns all types in the current AppDomain
/// </summary>
public static IEnumerable<Type> LoadedType()
{
return AppDomain
.CurrentDomain
.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes());
}
which should give you the all types loaded into the current application domain -- which, unless you're doing anything odd with appdomains, will be the list of all types loaded into your program.
None of the code has been tested, but it should help you find the classes and methods you'll need to use.
Mos probably the type XYZ that you are trying to find is not loaded or not present in the paths your app looks for assemblies. The Test.dll and ABC should be present it you added the reference in your project to Test.dll.
What does the code look like in FindType?
Assuming you are creating the type from the type name (a string), then you must be sure to supply the "assembly qualified" type name, not just the "local" type name.
e.g. to retrieve the type you are about to create:
Type testB = Type.GetType("TestB.XYZ, TestB");
rather than
Type testB = Type.GetType("TestB");
Can you give some more specifics, like some code snippets?

Categories

Resources