使用MarshallByRefObject创建多个副本的C#插件
我正在构建一个符合以下要求的插件框架:使用MarshallByRefObject创建多个副本的C#插件,c#,plugins,marshalbyrefobject,C#,Plugins,Marshalbyrefobject,我正在构建一个符合以下要求的插件框架: 随意加载/卸载插件 加载的插件中的调用方法 从插件向所有者引发回调事件 为此,我创建了一个新的AppDomain,并将插件程序集加载到其中 到目前为止,我的实现在一定程度上是有效的,但我相信我正在本地appDomain和新appDomain中创建插件的实例 当我第一次加载时,会收到重复的回调消息。当我多次加载/卸载时,会收到多条回调消息添加到列表中。这向我表明,我不仅在远程加载插件程序集,而且在本地加载插件程序集,因此我的“卸载”机制没有按我所希望的那
- 随意加载/卸载插件
- 加载的插件中的调用方法
- 从插件向所有者引发回调事件
public interface IPlugin
{
string Name();
string Version();
string RunProcess();
// custom event handler to be implemented, event arguments defined in child class
event EventHandler<PluginEventArgs> CallbackEvent;
//event EventHandler<EventArgs> CallbackEvent;
void OnProcessStart(PluginEventArgs data);
void OnProcessEnd(PluginEventArgs data);
}
(3) 插件类实现示例
[Serializable]
public class Plugin_1 : IPlugin
{
System.Timers.Timer counter;
int TimerInterval;
string PluginName = "My plugin";
public string Name()
{
return "CMD";
}
public bool Start()
{
OnStart(new PluginEventArgs());
RunProcess();
return true;
}
// OnTimer event, process start raised, sleep to simulate doing some work, then process end raised
public void OnCounterElapsed(Object sender, EventArgs e)
{
OnProcessStart(new PluginEventArgs());
OnProcessEnd(new PluginEventArgs());
Stop();
}
public bool Stop()
{
// simulate waiting for process to finish whatever its doing....
if (counter != null)
{
counter.Stop();
OnStop(new PluginEventArgs());
}
return true;
}
public string RunProcess()
{
TimerInterval = 2000;
if (counter == null){
counter = new System.Timers.Timer(TimerInterval);
}
else {
counter.Stop();
counter.Interval = TimerInterval;
}
counter.Elapsed += OnCounterElapsed;
counter.Start();
return "";
}
public event EventHandler<PluginEventArgs> CallbackEvent;
void OnCallback(PluginEventArgs e)
{
if (CallbackEvent != null)
{
CallbackEvent(this, e);
}
}
public void OnProcessStart(PluginEventArgs Data)
{
OnCallback(new PluginEventArgs(Data.executingDomain + " - " + PluginName + " started"));
}
public void OnProcessEnd(PluginEventArgs Data)
{
OnCallback(new PluginEventArgs(Data.executingDomain + " - " + PluginName + " ended"));
}
我有一个非常相似的情况。你找到一个解决方案,你可以张贴在这里吗?这里是解决!
[Serializable]
public class Plugin_1 : IPlugin
{
System.Timers.Timer counter;
int TimerInterval;
string PluginName = "My plugin";
public string Name()
{
return "CMD";
}
public bool Start()
{
OnStart(new PluginEventArgs());
RunProcess();
return true;
}
// OnTimer event, process start raised, sleep to simulate doing some work, then process end raised
public void OnCounterElapsed(Object sender, EventArgs e)
{
OnProcessStart(new PluginEventArgs());
OnProcessEnd(new PluginEventArgs());
Stop();
}
public bool Stop()
{
// simulate waiting for process to finish whatever its doing....
if (counter != null)
{
counter.Stop();
OnStop(new PluginEventArgs());
}
return true;
}
public string RunProcess()
{
TimerInterval = 2000;
if (counter == null){
counter = new System.Timers.Timer(TimerInterval);
}
else {
counter.Stop();
counter.Interval = TimerInterval;
}
counter.Elapsed += OnCounterElapsed;
counter.Start();
return "";
}
public event EventHandler<PluginEventArgs> CallbackEvent;
void OnCallback(PluginEventArgs e)
{
if (CallbackEvent != null)
{
CallbackEvent(this, e);
}
}
public void OnProcessStart(PluginEventArgs Data)
{
OnCallback(new PluginEventArgs(Data.executingDomain + " - " + PluginName + " started"));
}
public void OnProcessEnd(PluginEventArgs Data)
{
OnCallback(new PluginEventArgs(Data.executingDomain + " - " + PluginName + " ended"));
}
public class ProxyLoader : MarshalByRefObject
{
public AssemblyInstanceInfo LoadAndExecute(string assemblyName, EventHandler<PluginContract.PluginEventArgs> proxyLoader_RaiseCallbackEvent)
{
AssemblyInstanceInfo AInfo = new AssemblyInstanceInfo();
//nb: this AppDomain.CurrentDomain is in its own context / different from the caller app domain?
Assembly pluginAssembly = AppDomain.CurrentDomain.Load(assemblyName);
foreach (Type type in pluginAssembly.GetTypes())
{
if (type.GetInterface("IPlugin") != null)
{
object instance = Activator.CreateInstance(type, null, null);
AInfo.ObjectInstance = instance;
string s = ((PluginContract.IPlugin)instance).RunProcess(); // main procedure
AInfo.ASM = pluginAssembly;
((PluginContract.IPlugin)instance).CallbackEvent += proxyLoader_RaiseCallbackEvent;
((PluginContract.IPlugin)instance).Start();
instance = null;
}
}
return AInfo;
}
}
public event EventHandler<PluginContract.PluginEventArgs> Callback;
void OnCallback(PluginContract.PluginEventArgs e)
{
if (Callback != null)
{
Callback(this, e);
}
}
public void ProxyLoader_RaiseCallbackEvent(object source, PluginContract.PluginEventArgs e)
{
OnCallback(new PluginContract.PluginEventArgs(str));
}