I've been trying to make a module, command-line-like application. Each module can hold multiple commands. For example, "Module A" can have commands like "exit" and "echo". I'm using the following code to load and initialize my modules...
foreach (string Filename in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Modules"), "*.dll"))
{
Assembly Asm = Assembly.LoadFrom(Filename);
foreach (Type AsmType in Asm.GetTypes())
{
if (AsmType.GetInterface("ICommandModule") != null)
{
object CommandObject = Activator.CreateInstance(AsmType);
ICommandModule CommandModule;
if (CommandObject is ICommandModule)
{
CommandModule = (ICommandModule)CommandObject;
}
else
{
throw new Exception("CommandObject is not a valid ICommandModule.");
}
...
I know for a fact that the module which it is loading (Core.dll) is perfectly in compliance to the ICommandModule interface. When I make sure with if (CommandObject is ICommandModule) it throws the exception. When I removed the if statement alltogether, it told me it was unable to cast CommandObject to ICommandModule.
Your application may be finding the assembly with ICommandModule in two different directories. The assemblies may be exactly the same, but because they are in different directories the type system sees them as different.
Take Jakub's suggestion and make this change:
ICommandModule CommandModule = Activator.CreateInstance(AsmType) as ICommandModule;
You may have run into a situation where Activator.CreateInstance(AsmType) is returning null. If so, it may be that it found the declaration for the Interface itself and there is no instance creation possible for that particular AsmType. So, when debugging, make sure you know exactly which type you're trying to instantiate.
You can use Reflection to check whether an object implements a specific interface.
Here's an example:
bool isCommandModule = typeof(ICommandModule).IsAssignableFrom(commandObject);
Related resources:
Type.IsAssignableFrom Method
Try:
CommandModule = CommandObject as ICommandModule;
Related
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()).
I have a solution with 3 projects:
1) A GUI executable
2) A Class library with an containing a public API and a public interface
3) A Class library of a class that implements the above interface
I'm trying to implement a resource loader in the API, so that when the GUI calls method API.Foo() I go over every assembly inside a specific folder (found at: .\resources) which contains a copy of the assemblies I compiled (#3).
Then I want to add the resource to a list and use this list to call a function that is a part of the interface (which every resource implements)
So what I've done is:
private List<IResource> m_resources;
public void Foo()
{
string resourceDir = Directory.GetCurrentDirectory() + #"\Resources";
m_resources= new List<IResource>();
foreach (var dllFile in Directory.EnumerateFiles(resourceDir))
{
IResource dllInstance;
if (TryLoadingDLL(Path.Combine(resourceDir, dllFile), out dllInstance))
{
resources.Add(dllInstance);
}
}
}
private static bool TryLoadingDLL(string dllFullPath, out IResource instanceOfDll)
{
instanceOfDll = null;
try
{
Assembly assembly = Assembly.LoadFrom(dllFullPath);
Assembly IResourceAssambly = Assembly.LoadFrom(#"C:\MyProject\MyAPI.dll");
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
var interfaces = type.GetInterfaces();
var typeOfIResource = IResourceAssambly.GetType("MyProject.IResource");
if (interfaces.Any())
{
var interfaceType = interfaces[0]; //In debuger they have the same GUID
if (interfaceType.IsEquivalentTo(typeOfIResource)) //also tried ==
{
instanceOfDll = Activator.CreateInstance(type) as IResource;
return true;
}
}
}
}
catch (Exception e)
{
Console.Error.WriteLine("Failed to load dll {0}, exception: {1}",dllFullPath, e.Message);
return false;
}
return false;
}
Iv'e actually used this at first which gave the same result:
List<Type> derivedTypesList = typses.Where(type => type.GetInterfaces().Contains(IWNAssambly.GetType("MyProject.IResource"))).ToList();
if (derivedTypesList.Count > 0)
{
instanceOfDll = (IResource)Activator.CreateInstance(derivedTypesList[0]);
return true;
}
but then I broke it down so I can debug it easily.
When I run any of these snippets, I Indeed find 1 type that implements the interface, but when I try to cast it I get null via the as operator and an exception when casting with (IResource). The exception is:
{System.InvalidCastException: Unable to cast object of type 'MyProject.MyFirstResource' to type 'MyProject.IResource'.
at ...
The problem looked like it was coming from the types so I tried replacing
var typeOfIResource = IResourceAssambly.GetType("MyProject.IResource");
with
var typeOfIResource = typeof(MyProject.IResource);
And the result was that now it didn't find anything at all, i.e the interfaceType.IsEquivalentTo(typeOfIResource) is always false.
When I looked with the debugger on these types they looked exactly the same so I don't know what's the problem.
First, is this a good practice? I want other developers to supply me with their assemblies and if they implement the IResource interface then use reflection to create an instance and invoke the wanted method.
Second and more important at this time, what is the problem and how can I solve it?
Thanks!!!
This brings back memories; I ran into the same problem in the very first .NET program I ever wrote, which must have been fifteen years ago now.
The problem is that .NET has different "binding contexts" in which a type can be loaded, and "Load" and "LoadFrom" load into different contexts. The "same" type in two different contexts will be treated as different by the runtime, and you cannot cast between them.
This is a fairly frequently asked question on Stack Overflow; if you do a search for those terms you should find some examples of explanations and possible solutions. For example, this one:
Create object from dynamically load assembly and cast it to interface (.NET 2.0)
Also, this blog article from the early days of .NET might help explain the design
http://blogs.msdn.com/b/suzcook/archive/2003/09/19/loadfile-vs-loadfrom.aspx
Finally, the other answer is correct; if you are looking to build a plugin system, I recommend against doing it from scratch. Use MEF or MAF or some other system designed specifically to solve your problem. Loading assemblies may be the least of your worries; suppose you must live in a world where third-party plugins might be hostile? Solving that security problem is difficult, so let someone else do it for you.
Look system.component, since .NET 4 the framework MEF have been integrated. MEF
This framework permits you to flag by an attribute [Export(typeof(interface))] on every implementation of the interface regardless the dll and to load them using a catalog system. (There is one for the folder DirectoryCatalog
My issue is that I am getting different results to our older DLLs from history, when very little has changed and I don't under how the changes are relevant to the error shown.
This is part of a method, in our SecurityPluginServices.dll module, which essentially added plugins to a list so they can be utilised by the main program.
It gets all the DLLs in a set folder, then for each it runs through the code below.
private void AddPlugin(string FileName, LoggingUtilities.Source source)
{
//Create a new assembly from the plugin file we're adding..
Assembly pluginAssembly = Assembly.LoadFrom(FileName);
try
{
//Next we'll loop through all the Types found in the assembly
foreach (Type pluginType in pluginAssembly.GetTypes())
{
if (pluginType.IsPublic) //Only look at public types
{
if (!pluginType.IsAbstract) //Only look at non-abstract types
{
//Gets a type object of the interface we need the plugins to match
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
//Make sure the interface we want to use actually exists
if (typeInterface != null)
{
// Do work here
}
typeInterface = null; //Mr. Clean
}
}
}
pluginAssembly = null; //more cleanup
}
catch (ReflectionTypeLoadException ex1)
{
Console.WriteLine(ex1.Message);
}
catch (Exception ex2)
{
Console.WriteLine(ex2.Message);
}
}
The issue I am having is that everytime it gets to Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true); it always returns null.
The plugins I need to load are for NTLM and LDAP and they have changed very little in many versions and only a couple of extra properties and methods have been added, nothing to do with interfaces that the implement.
I've opened up a copy of the newer plugin DLL and one of the older ones in ILDASM and they both seem to contain the same information regarding the SecurityInterface.ISecurityPlugin that the .GetInterface method is seeking.
Newer LdapSecurity
Older LdapSecurity
Suggestion:
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Change this to a fully-qualified type name, i.e. one that includes the assembly containing your interface type.
(If you're now saying that you've got two different types by the same name, in two different assemblies, and therefore cannot include one definite assembly name, this may well be the likely cause of your issue.)
Explanation:
My other answer led me to a suspicion of what could cause your issue. Generally speaking, typeof(T) would force you to add an assembly reference to your project for the assembly that contains T. Otherwise, compilation will fail. On the other hand, textual mentions of type names such as Type.GetType("T") do not enforce a compile-time assembly reference... but they still have to be resolved to a type instance at run-time. So if you omit the assembly name, you need to keep in mind how .NET will map T to a specific assembly.
Back to your issue. First, let's note that you are not using a fully-qualified type name:
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You specify only the namespace and the type name, but not the assembly containing your interface type. Could it be that the interface type is defined more than once, i.e. in different assemblies, and your mention of that type name is resolved to type in the wrong assembly?
Let's briefly look at the MSDN documentation for Type.GetType(string) method, which describes the string parameter as follows:
"The assembly-qualified name of the type to get. […] 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."
What if the same applies to the Type.GetInterface(string, bool) method which you're using? And what if your currently executing assembly does contain a type of that name? Then that is the type that pluginType will be checked against... but it might be a different ISecurityPlugin interface type (albeit equal in name) than the one your plug-in class actually implements.
Update: Please see my other answer first, which is likely more relevant.
If you want to check whether pluginType implements the ISecurityPlugin interface, you could instead perform this check:
typeof(SecurityInterface.ISecurityPlugin).IsAssignableFrom(pluginType)
If you don't reference the assembly containing ISecurityPlugin, you can replace the first part by Type.GetType("SecurityInterface.ISecurityPlugin").
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
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.