问题
I'd like to provide some way of creating dynamically loadable plugins in my software. Typical way to do this is using the LoadLibrary WinAPI function to load a dll and calling GetProcAddress to get an pointer to a function inside that dll.
My question is how do I dynamically load a plugin in C#/.Net application?
回答1:
The following code snippet (C#) constructs an instance of any concrete classes derived from Base
found in class libraries (*.dll) in the application path and stores them in a list.
using System.IO;
using System.Reflection;
List<Base> objects = new List<Base>();
DirectoryInfo dir = new DirectoryInfo(Application.StartupPath);
foreach (FileInfo file in dir.GetFiles("*.dll"))
{
Assembly assembly = Assembly.LoadFrom(file.FullName);
foreach (Type type in assembly.GetTypes())
{
if (type.IsSubclassOf(typeof(Base)) && type.IsAbstract == false)
{
Base b = type.InvokeMember(null,
BindingFlags.CreateInstance,
null, null, null) as Base;
objects.Add(b);
}
}
}
Edit: The classes referred to by Matt are probably a better option in .NET 3.5.
回答2:
As of .NET 3.5 there's a formalized, baked-in way to create and load plugins from a .NET application. It's all in the System.AddIn namespace. For more information you can check out this article on MSDN: Add-ins and Extensibility
回答3:
Dynamically Loading Plug-ins
For information on how to dynamically load .NET assemblies see this question (and my answer). Here is some code for loading creating an AppDomain
and loading an assembly into it.
var domain = AppDomain.CreateDomain("NewDomainName");
var pathToDll = @"C:\myDll.dll";
var t = typeof(TypeIWantToLoad);
var runnable = domain.CreateInstanceFromAndUnwrap(pathToDll, t.FullName)
as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();
Unloading Plug-ins
A typical requirement of a plugin framework is to unload the plugins. To unload dynamically loaded assemblies (e.g. plug-ins and add-ins) you have to unload the containing AppDomain
. For more information see this article on MSDN on Unloading AppDomains.
Using WCF
There is a stack overflow question and answer that describe how to use the Windows Communication Framework (WCF) to create a plug-in framework.
Existing Plug-in Frameworks
I know of two plug-in frameworks:
- Mono.Add-ins - As mentioned in this answer to another question.
- Managed Add-in Framework (MAF) - This is the
System.AddIn
namespace as mentioned by Matt in his answer.
Some people talk about the Managed Extensibility Framework (MEF) as a plug-in or add-in framework, which it isn't. For more information see this StackOverflow.com question and this StackOverflow.com question.
回答4:
One tip is to load all plugins and such into an own AppDomain, since the code running can be potentially malicious. An own AppDomain can also be used to "filter" assemblies and types that you don't want to load.
AppDomain domain = AppDomain.CreateDomain("tempDomain");
And to load an assembly into the application domain:
AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
Assembly assembly = domain.Load(assemblyName);
To unload the application domain:
AppDomain.Unload(domain);
回答5:
Yes, ++ to Matt and System.AddIn (a two-part MSDN magazine article about System.AddIn are available here and here). Another technology you might want to look at to get an idea where the .NET Framework might be going in the future is the Managed Extensibility Framework currently available in CTP form on Codeplex.
回答6:
Basically you can do it in two ways.
The first is to import kernel32.dll and use LoadLibrary and GetProcAddress as you used it before:
[DllImport("kernel32.dll")]
internal static extern IntPtr LoadLibrary(String dllname);
[DllImport("kernel32.dll")]
internal static extern IntPtr GetProcAddress(IntPtr hModule, String procname);
The second is to do it in the .NET-way: by using reflection. Check System.Reflection namespace and the following methods:
- Assembly.LoadFile
- Assembly.GetType
- Assembly.GetTypes
- Type.GetMethod
- MethodInfo.Invoke
First you load the assembly by it's path, then get the type (class) from it by it's name, then get the method of the class by it's name again and finally call the method with the relevant parameters.
回答7:
The article is a bit older, but still applicable for creating an extensibility layer within your application:
Let Users Add Functionality to Your .NET Applications with Macros and Plug-Ins
来源:https://stackoverflow.com/questions/14278/how-to-load-plugins-in-net