Can dll-files be used as plug and play modules [duplicate] - c#

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

Related

C# weird assembly behaviour

I experienced some weird assembly behaviour. I execute an invocation successful and my desired method gets executed, but this method cant access any public static values of objects of a public static class. All the values are null like if the method accesses an empty copy of the class, but thats impossible since the class is static.
To invoke the method i loaded the assembly like the following:
public static Assembly loadedAssembly = Assembly.LoadFrom( //path of the dll );
Then the invoked method can access only empty values from the other static class. But setting the Assembly as following enables the method to access all the values properly.
public static Assembly loadedAssembly = Assembly.GetExecutingAssembly();
I thought both of them are the same, because the Assembly i load from the directory is exactly the same as the one that gets executed at this time. An if comparison confirmed that those are not the same though. It seems that the Assembly loaded straight from the directory is not "initialised", so all its members are null. Can you please tell me what is going on there and why the ones Assembly members are all null.
It may be that the constructor on the static class hasn't been called yet.
If you haven't called any methods on the static class, the constructor wouldn't have been called, and the fields on it wouldn't have been initialized.
If you're trying to access fields on it, you may want to try changing them to properties.
You do not need to load the assembly, You just need the type to execute the static method using reflection, I use below to invoke my static method's that returns string.
private static string ExecuteStaticMethod(Type objectType, string methodName, string defaultValue = null)
{
var retVal = defaultValue;
if (string.IsNullOrEmpty(retVal))
{
var methodInfo = objectType.GetMethod(methodName);
if (methodInfo != null)
{
retVal = methodInfo.Invoke(null, null) as string;
}
}
return retVal;
}
Since no one provided the desired answer, i´ll go for it. The issue i had there was basically a wrong understanding from Assemblies. The problem is that i loaded this Assembly right from the directory:
public static Assembly loadedAssembly = Assembly.LoadFrom( //path of the dll );
But this Assembly didnt get initialsed yet, it cointains the information about members and types, but not their values. Those are contained in the current executing Assembly which can be accessed this way:
public static Assembly loadedAssembly = Assembly.GetExecutingAssembly();
And in this current executing Assembly contains those assigned values for it´s members.
So Assembly.LoadFrom() can only be used if you need information about the types and members from this Assembly but not for invoking assigned values.

Reflection C# - GetType() Returns Null [duplicate]

This code:
Type.GetType("namespace.a.b.ClassName")
returns null.
I have in the usings:
using namespace.a.b;
The type exists, it's in a different class library, and I need to get it by it's name given as string.
Type.GetType("namespace.qualified.TypeName") only works when the type is found in either mscorlib.dll or the currently executing assembly.
If neither of those things are true, you'll need an assembly-qualified name:
Type.GetType("namespace.qualified.TypeName, Assembly.Name")
You can also get the type without assembly qualified name but with the dll name also, for example:
Type myClassType = Type.GetType("TypeName,DllName");
I had the same situation and it worked for me. I needed an object of type "DataModel.QueueObject" and had a reference to "DataModel" so I got the type as follows:
Type type = Type.GetType("DataModel.QueueObject,DataModel");
The second string after the comma is the reference name (dll name).
Try this method.
public static Type GetType(string typeName)
{
var type = Type.GetType(typeName);
if (type != null) return type;
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
type = a.GetType(typeName);
if (type != null)
return type;
}
return null;
}
If the assembly is part of the build of an ASP.NET application, you can use the BuildManager class:
using System.Web.Compilation
...
BuildManager.GetType(typeName, false);
Dictionary<string, Type> typeCache;
...
public static bool TryFindType(string typeName, out Type t) {
lock (typeCache) {
if (!typeCache.TryGetValue(typeName, out t)) {
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) {
t = a.GetType(typeName);
if (t != null)
break;
}
typeCache[typeName] = t; // perhaps null
}
}
return t != null;
}
if your class is not in current assambly you must give qualifiedName and this code shows how to get qualifiedname of class
string qualifiedName = typeof(YourClass).AssemblyQualifiedName;
and then you can get type with qualifiedName
Type elementType = Type.GetType(qualifiedName);
As Type.GetType(String) need the Type.AssemblyQualifiedName you should use Assembly.CreateQualifiedName(String, String).
string typeName = "MyNamespace.MyClass"; // Type.FullName
string assemblyName = "MyAssemblyName"; // MyAssembly.FullName or MyAssembly.GetName().Name
string assemblyQualifiedName = Assembly.CreateQualifiedName(assemblyName , typeName);
Type myClassType = Type.GetType(assemblyQualifiedName);
The Version, Culture and PublicKeyToken are not required for assemblyName that's why you can use MyAssembly.GetName().Name.
About Type.GetType(String) :
If the type is in the currently executing
assembly or in Mscorlib.dll, it is sufficient to supply the type name
qualified by its namespace.
When I have only the class name I use this:
Type obj = AppDomain.CurrentDomain.GetAssemblies().SelectMany(t => t.GetTypes()).Where(t => String.Equals(t.Name, _viewModelName, StringComparison.Ordinal)).First();
If it's a nested Type, you might be forgetting to transform a . to a +
Regardless, typeof( T).FullName will tell you what you should be saying
EDIT: BTW the usings (as I'm sure you know) are only directives to the compiler at compile time and cannot thus have any impact on the API call's success. (If you had project or assembly references, that could potentially have had influence - hence the information isnt useless, it just takes some filtering...)
I am opening user controls depending on what user controls the user have access to specified in a database. So I used this method to get the TypeName...
Dim strType As String = GetType(Namespace.ClassName).AssemblyQualifiedName.ToString
Dim obj As UserControl = Activator.CreateInstance(Type.GetType(strType))
So now one can use the value returned in strType to create an instance of that object.
If the assembly is referenced and the Class visible :
typeof(namespace.a.b.ClassName)
GetType returns null because the type is not found, with typeof, the compiler may help you to find out the error.
Try using the full type name that includes the assembly info, for example:
string typeName = #"MyCompany.MyApp.MyDomain.MyClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
Type myClassType = Type.GetType(typeName);
I had the same situation when I was using only the the namesspace.classname to get the type of a class in a different assembly and it would not work. Only worked when I included the assembly info in my type string as shown above.
Make sure that the comma is directly after the fully qualified name
typeof(namespace.a.b.ClassName, AssemblyName)
As this wont work
typeof(namespace.a.b.ClassName ,AssemblyName)
I was stumped for a few days on this one
For me, a "+" was the key!
This is my class(it is a nested one) :
namespace PortalServices
{
public class PortalManagement : WebService
{
public class Merchant
{}
}
}
and this line of code worked:
Type type = Type.GetType("PortalServices.PortalManagement+Merchant");
This solution above seems to be the best to me, but it didn't work for me, so I did it as follows:
AssemblyName assemblyName = AssemblyName.GetAssemblyName(HttpContext.Current.Server.MapPath("~\\Bin\\AnotherAssembly.dll"));
string typeAssemblyQualifiedName = string.Join(", ", "MyNamespace.MyType", assemblyName.FullName);
Type myType = Type.GetType(typeAssemblyQualifiedName);
The precondition is that you know the path of the assembly. In my case I know it because this is an assembly built from another internal project and its included in our project's bin folder.
In case it matters I am using Visual Studio 2013, my target .NET is 4.0. This is an ASP.NET project, so I am getting absolute path via HttpContext. However, absolute path is not a requirement as it seems from MSDN on AssemblyQualifiedNames
I cheated. Since the types I want to create (by name) are all in In a dll I control, I just put a static method in the dll in the assembly that takes a simple name, and calls type.GetType from that context and returns the result.
The original purpose was so that the type could be specified by name in configuration data. I've since change the code so that the user specified a format to process. The format handler classes implement a interface that determines if the type can parse the specified format. I then use reflection to find types that implement the interface, and find one that handles the format. So now the configuration specifies a format name, a not a specific type. The reflection code can look at adjacent dlls and load, them so I have a sort poor man's plug-in architecture.
Very late reply, but if anyone is dealing with this a decade later:
There is a very, very small chance that your class in Visual Studio has a Build Action set to "Content" instead of "Compile".
Click on your class in Solution Explorer, then look at the properties.
Check that Build Action is "Compile", not "Content".

Dynamically load a DLL from a specific folder?

At the moment, I have this code :
var shellViewLibrary = Assembly.LoadFrom(Path.Combine(_DllsPath, _DllShellView));
IEnumerable<Type> types = shellViewLibrary.GetTypes();
foreach (Type type in types)
{
var typeIShellViewInterface = type.GetInterface(_NamespaceIShellView, false);
if (typeIShellViewInterface != null)
{
//here
}
}
The thing is that where I got //here I want to use Activator.CreateInstance to create an object whose type is type in a specific folder (that is outside the build folder)
I tried about 20 different things, most of them with this : http://msdn.microsoft.com/en-us/library/d133hta4.aspx
but none works...
The typical thing I tried is :
object MyObj = Activator.CreateInstance(shellViewLibrary.FullName, type.FullName);
or
object MyObj = Activator.CreateInstance(Path.Combine(_DllsPath, _DllShellView), type.FullName);
I always got different exception, the most common being :
XamlParseException
I feel like that I'm not using Activator.CreateInstance in the right way with 2 parameters. What should I do ?
This is an example of "Dynamically Loading a .dll from a Specific Folder" at runtime.
// Check if user has access to requested .dll.
string strDllPath = Path.GetFullPath(strSomePath);
if (File.Exists(strDllPath))
{
// Execute the method from the requested .dll using reflection (System.Reflection).
Assembly DLL = Assembly.LoadFrom(strDllPath);
Type classType = DLL.GetType(String.Format("{0}.{1}", strNmSpaceNm, strClassNm));
if (classType != null)
{
// Create class instance.
classInst = Activator.CreateInstance(classType);
// Invoke required method.
MethodInfo methodInfo = classType.GetMethod(strMethodName);
if (methodInfo != null)
{
object result = null;
result = methodInfo.Invoke(classInst, new object[] { dllParams });
return result.ToString();
}
}
}
This took me a while to work out so I hope it is of some use...
Once you call this line
var shellViewLibrary = Assembly.LoadFrom(Path.Combine(_DllsPath, _DllShellView));
The assembly has been loaded in to memory. So long as you specify types correctly from this then you will be able to use Activator.CreateInstance to create the types. ie: It is not necessary to further specify where the type is.
Regarding Activator, from MSDN the CreateInstance method can accept a System.Type. I would just use this method inside your if-statement:
Activator.CreateInstance(Type type);
What I would try to do to debug this is first create the type and then pass it in to CreateInstance. You may find that the Type creation itself is failing (due to unresolved assembly) or the instantiation of that type (due to exception in the constructor). At first glance your code here appears to be correct:
foreach (Type type in types)
{
var typeIShellViewInterface = type.GetInterface(_NamespaceIShellView, false);
if (typeIShellViewInterface != null)
{
try
{
// I assume you are calling this line at the point marked 'here'.
// To debug the creation wrap in a try-catch and view the inner exceptions
var result = Activator.CreateInstance(type);
}
catch(Exception caught)
{
// When you hit this line, look at caught inner exceptions
// I suspect you have a broken Xaml file inside WPF usercontrol
// or Xaml resource dictionary used by type
Debugger.Break();
}
}
}
In your question you specify that you are getting a XamlParseException. It sounds to me like the type in question is a UserControl (or otherwise refers to a WPF Xaml resource file) and there is an error in that Xaml file, i.e. nothing to do with your usage of Assembly.Load or Activator.CreateInstance.
Could you try posting the inner exception(s) to get a better idea on what the problem is?
Check out MEF and Prism. MEF is a dependency injection library that helps with this. You can load all of your dependencies from a specific folder and make dynamically load them.
Prism is a pattern that leverages dependency injection and works great with MEF to load libraries dynamically
if you're trying to create a type with the Activator class from a DLL that's outside your application, you need to first load this DLL inside your application domain.
The easiest and quickest way to do this is by using the Assembly.LoadFile method.
more information about that method can be found here : http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadfile.aspx
When the assembly is properly loaded you can use the Activator to create an instance from the type inside the DLL.
We use this mechanic to run custom code in our application.
I'm not sure what you mean by this:
create an object whose type is type in a specific folder (that is outside the build folder)
A type only exists in an assembly. Path is entirely irrelevant to types in .NET
I assume that by "path" you really mean "namespace", meaning that you don't know in which namespace the type exists. You have already loaded the assembly in your code. Inspect the assembly using reflection to find the type you're looking for. Then pass the Type object that represents the type you're looking for to Activator.CreateInstance

C# 4.0: casting dynamic to static

This is an offshoot question that's related to another I asked here. I'm splitting it off because it's really a sub-question:
I'm having difficulties casting an object of type dynamic to another (known) static type.
I have an ironPython script that is doing this:
import clr
clr.AddReference("System")
from System import *
def GetBclUri():
return Uri("http://google.com")
note that it's simply newing up a BCL System.Uri type and returning it. So I know the static type of the returned object.
now over in C# land, I'm newing up the script hosting stuff and calling this getter to return the Uri object:
dynamic uri = scriptEngine.GetBclUri();
System.Uri u = uri as System.Uri; // casts the dynamic to static fine
Works no problem. I now can use the strongly typed Uri object as if it was originally instantiated statically.
however....
Now I want to define my own C# class that will be newed up in dynamic-land just like I did with the Uri. My simple C# class:
namespace Entity
{
public class TestPy // stupid simple test class of my own
{
public string DoSomething(string something)
{
return something;
}
}
}
Now in Python, new up an object of this type and return it:
sys.path.append(r'C:..path here...')
clr.AddReferenceToFile("entity.dll")
import Entity.TestPy
def GetTest():
return Entity.TestPy(); // the C# class
then in C# call the getter:
dynamic test = scriptEngine.GetTest();
Entity.TestPy t = test as Entity.TestPy; // t==null!!!
here, the cast does not work. Note that the 'test' object (dynamic) is valid--I can call the DoSomething()--it just won't cast to the known static type
string s = test.DoSomething("asdf"); // dynamic object works fine
so I'm perplexed. the BCL type System.Uri will cast from a dynamic type to the correct static one, but my own type won't. There's obviously something I'm not getting about this...
--
Update: I did a bunch of tests to make sure my assembly refs are all lining up correctly. I changed the referenced assembly ver number then looked at the dynamic objects GetType() info in C#--it is the correct version number, but it still will not cast back to the known static type.
I then created another class in my console app to check to see I would get the same result, which turned out positive: I can get a dynamic reference in C# to a static type instantiated in my Python script, but it will not cast back to the known static type correctly.
--
even more info:
Anton suggests below that the AppDomain assembly binding context is the likely culprit. After doing some tests I think it very likely is. . . but I can't figure out how to resolve it! I was unaware of assembly binding contexts so thanks to Anton I've become more educated on assembly resolution and the subtle bugs that crop up there.
So I watched the assembly resolution process by putting a handler on the event in C# prior to starting the script engine. That allowed me to see the python engine start up and the runtime start to resolve assemblies:
private static Type pType = null; // this will be the python type ref
// prior to script engine starting, start monitoring assembly resolution
AppDomain.CurrentDomain.AssemblyResolve
+= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
... and the handler sets the var pType to the Type that python is loading:
static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
if (args.LoadedAssembly.FullName ==
"Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null")
{
// when the script engine loads the entity assembly, get a reference
// to that type so we can use it to cast to later.
// This Type ref magically carries with it (invisibly as far as I can
// tell) the assembly binding context
pType = args.LoadedAssembly.GetType("Entity.TestPy");
}
}
So while the type used by python is the same on in C#, I'm thinking (as proposed by Anton) that the different binding contexts mean that to the runtime, the two types (the one in the 'load binding context' and the 'loadfrom binding context) are different--so you can't cast on to the other.
So now that I have hold of the Type (along with it's binding context) loaded by Python, lo and behold in C# I can cast the dynamic object to this static type and it works:
dynamic test = scriptEngine.GetTest();
var pythonBoundContextObject =
Convert.ChangeType(test, pType); // pType = python bound
string wow = pythonBoundContextObject .DoSomething("success");
But, sigh, this doesn't totally fix the problem, because the var pythonBoundContextObject while of the correct type, still carries the taint of the wrong assembly binding context. This means that I can't pass this to other parts of my code because we still have this bizzare type mismatch where the invisible specter of binding context stops me cold.
// class that takes type TestPy in the ctor...
public class Foo
{
TestPy tp;
public Foo(TestPy t)
{
this.tp = t;
}
}
// can't pass the pythonBoundContextObject (from above): wrong binding context
Foo f = new Foo(pythonBoundContextObject); // all aboard the fail boat
So the resolution is going to have to be on the Python side: getting the script to load in the right assembly binding context.
in Python, if I do this:
# in my python script
AppDomain.CurrentDomain.Load(
"Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null");
the runtime can't resolve my type:
import Entity.TestPy #fails
Here's an answer from the IronPython team which covers the same problem:
C# / IronPython Interop with shared C# Class Library
(Lifted from http://lists.ironpython.com/pipermail/users-ironpython.com/2010-September/013717.html )
I bet that IronPython loads your entity.dll into a different assembly load context, so that you have two copies of it loaded and the types in them are of course different. You might be able to work around this issue by hooking AppDomain.AssemblyReslove/AppDomain.AssemblyLoad and returning your local assembly (typeof (Entity.TestPy).Assembly) when IronPython tries to load it, but I don't guarantee that this will work.
You don't experience this with System.Uri because mscorlib.dll (and maybe some other system assemblies) is treated specially by the runtime.
Update: IronPython FAQ states that if the assembly isn't already loaded clr.AddReferenceToFile uses Assembly.LoadFile, which loads into the 'Neither' context. Try accessing a method from Entity.TestPy before calling IronPython to load the assembly into the default Load context.

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

Categories

Resources