Sistema de Escrita Plugin C #
-
21-08-2019 - |
Pergunta
Eu estou tentando escrever um sistema de plugins para fornecer alguma extensibilidade para uma aplicação da mina assim que alguém pode escrever um plugin (s) para a aplicação sem tocar código do aplicativo principal (e risco quebrar alguma coisa).
Eu tenho a base "IPlugin" interface de escrita (atm, nada é implementado ainda)
Aqui está como eu sou de carga:
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);
}
}
}
Um amigo tentou ajudar, mas eu realmente não entendia o que estava errado.
A estrutura da pasta de plugins é o seguinte:
\
\ Plugins \
Todos os plugins referenciar um dll chamado "Lab.Core.dll" no diretório [root] e não está presente no diretório Plugins por causa das referências duplicadas sendo carregado.
O sistema plug-in é carregado a partir Lab.Core.dll que também é referenciado pelo meu executável. Digite "IPlugin" está em Lab.Core.dll também. Lab.Core.dll é, exatamente como o nome, o núcleo da minha aplicação.
EDIT:
Pergunta: Por quê? / O que é essa exceção que estou recebendo e como eu poderia ir sobre corrigi-lo
edição final:
Ok, então eu decidi re write-lo depois de olhar para algum código fonte um amigo escreveu para um regulador de TF2.
Aqui está o que eu tenho e ele funciona:
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;
}
}
}
Solução
Parece que você tem uma referência circular. Você disse que seus plugins referência Lab.Core.DLL, mas você também dizem que os plugins são carregados a partir Lab.Core.DLL.
Am I mal entendido o que está acontecendo aqui?
EDIT: OK, agora que você adicionou a sua pergunta para a pergunta ...
Você precisa ter Lab.Core.DLL acessível para o plug-in a ser carregado uma vez que é uma dependência. Normalmente, isso significaria tê-lo no mesmo diretório ou no GAC.
Eu suspeito que há problemas de design mais profundas em jogo aqui, mas este é o seu problema imediato.
Outras dicas
A extensibilidade Framework Managed (MEF) é uma nova biblioteca no .NET que permite uma maior reutilização de aplicações e componentes. Usando MEF, aplicações .NET pode fazer a mudança de ser compilado estaticamente para compor dinamicamente. Se você está construindo aplicações extensíveis, estruturas extensíveis e extensões de aplicação, então MEF é para você.
Edit: CodePlex está indo embora - o código foi movido para Github para fins de arquivamento apenas: https: // github.com/MicrosoftArchive/mef
Como uma resposta lado, eu uso essas 2 interfaces de aplicação da referida
///<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);
}