问题
I\'m trying to write a plugin system to provide some extensibility to an application of mine so someone can write a plugin(s) for the application without touching the main application\'s code (and risk breaking something).
I\'ve got the base \"IPlugin\" interface written (atm, nothing is implemented yet)
Here is how I\'m loading:
public static void Load()
{
// rawr: http://www.codeproject.com/KB/cs/c__plugin_architecture.aspx
String[] pluginFiles = Directory.GetFiles(Plugins.PluginsDirectory, \"*.dll\");
foreach (var plugin in pluginFiles)
{
Type objType = null;
try
{
//Assembly.GetExecutingAssembly().GetName().Name
MessageBox.Show(Directory.GetCurrentDirectory());
Assembly asm = Assembly.Load(plugin);
if (asm != null)
{
objType = asm.GetType(asm.FullName);
if (objType != null)
{
if (typeof(IPlugin).IsAssignableFrom(objType))
{
MessageBox.Show(Directory.GetCurrentDirectory());
IPlugin ipi = (IPlugin)Activator.CreateInstance(objType);
ipi.Host = Plugins.m_PluginsHost;
ipi.Assembly = asm;
}
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString(), \"Unhandled Exception! (Please Report!)\", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
}
}
}
A friend tried to help but I really didn\'t understand what was wrong.
The folder structure for plugins is the following:
\\
\\Plugins\\
All plugins reference a .dll called \"Lab.Core.dll\" in the [root] directory and it is not present in the Plugins directory because of duplicate references being loaded.
The plugin system is loaded from Lab.Core.dll which is also referenced by my executable. Type \"IPlugin\" is in Lab.Core.dll as well. Lab.Core.dll is, exactly as named, the core of my application.
EDIT:
Question: Why/What is that exception I\'m getting and how could I go about fixing it?
FINAL EDIT:
Ok so I decided to re-write it after looking at some source code a friend wrote for a TF2 regulator.
Here\'s what I got and it works:
public class TestPlugin : IPlugin {
#region Constructor
public TestPlugin() {
//
}
#endregion
#region IPlugin Members
public String Name {
get {
return \"Test Plugin\";
}
}
public String Version {
get {
return \"1.0.0\";
}
}
public String Author {
get {
return \"Zack\";
}
}
public Boolean OnLoad() {
MessageBox.Show(\"Loaded!\");
return true;
}
public Boolean OnAllLoaded() {
MessageBox.Show(\"All loaded!\");
return true;
}
#endregion
}
public static void Load(String file) {
if (!File.Exists(file) || !file.EndsWith(\".dll\", true, null))
return;
Assembly asm = null;
try {
asm = Assembly.LoadFile(file);
} catch (Exception) {
// unable to load
return;
}
Type pluginInfo = null;
try {
Type[] types = asm.GetTypes();
Assembly core = AppDomain.CurrentDomain.GetAssemblies().Single(x => x.GetName().Name.Equals(\"Lab.Core\"));
Type type = core.GetType(\"Lab.Core.IPlugin\");
foreach (var t in types)
if (type.IsAssignableFrom((Type)t)) {
pluginInfo = t;
break;
}
if (pluginInfo != null) {
Object o = Activator.CreateInstance(pluginInfo);
IPlugin plugin = (IPlugin)o;
Plugins.Register(plugin);
}
} catch (Exception) {
}
}
public static void LoadAll() {
String[] files = Directory.GetFiles(\"./Plugins/\", \"*.dll\");
foreach (var s in files)
Load(Path.Combine(Environment.CurrentDirectory, s));
for (Int32 i = 0; i < Plugins.List.Count; ++i) {
IPlugin p = Plugins.List.ElementAt(i);
try {
if (!p.OnAllLoaded()) {
Plugins.List.RemoveAt(i);
--i;
}
} catch (Exception) {
Plugins.List.RemoveAt(i);
--i;
}
}
}
回答1:
It sounds like you have a circular reference. You said your plugins reference Lab.Core.DLL, but you also say the plugins are loaded from Lab.Core.DLL.
Am I misunderstanding what is happening here?
EDIT: OK now that you have added your question to the question...
You need to have Lab.Core.DLL accessible to the plugin being loaded since it is a dependency. Normally that would mean having it in the same directory or in the GAC.
I suspect there are deeper design issues at play here, but this is your immediate problem.
回答2:
The Managed Extensibility Framework (MEF) is a new library in .NET that enables greater reuse of applications and components. Using MEF, .NET applications can make the shift from being statically compiled to dynamically composed. If you are building extensible applications, extensible frameworks and application extensions, then MEF is for you.
http://www.codeplex.com/MEF
Edit: CodePlex is going away - the code has been moved to Github for archival purposes only: https://github.com/MicrosoftArchive/mef
回答3:
As a side answer, i use these 2 interfaces for implementing that
///<summary>
///</summary>
public interface IPlugin {
///<summary>
///</summary>
string Name { get; }
///<summary>
///</summary>
string Description { get; }
///<summary>
///</summary>
string Author { get; }
///<summary>
///</summary>
string Version { get; }
///<summary>
///</summary>
IPluginHost Host { get; set; }
///<summary>
///</summary>
void Init();
///<summary>
///</summary>
void Unload();
///<summary>
///</summary>
///<returns></returns>
IDictionary<int, string> GetOptions();
///<summary>
///</summary>
///<param name="opcion"></param>
void ExecuteOption(int option);
}
///<summary>
///</summary>
public interface IPluginHost {
///<summary>
///</summary>
IDictionary<string, object> Variables { get; }
///<summary>
///</summary>
///<param name="plugin"></param>
void Register(IPlugin plugin);
}
来源:https://stackoverflow.com/questions/1070787/writing-c-sharp-plugin-system