Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用MarshallByRefObject创建多个副本的C#插件_C#_Plugins_Marshalbyrefobject - Fatal编程技术网

使用MarshallByRefObject创建多个副本的C#插件

使用MarshallByRefObject创建多个副本的C#插件,c#,plugins,marshalbyrefobject,C#,Plugins,Marshalbyrefobject,我正在构建一个符合以下要求的插件框架: 随意加载/卸载插件 加载的插件中的调用方法 从插件向所有者引发回调事件 为此,我创建了一个新的AppDomain,并将插件程序集加载到其中 到目前为止,我的实现在一定程度上是有效的,但我相信我正在本地appDomain和新appDomain中创建插件的实例 当我第一次加载时,会收到重复的回调消息。当我多次加载/卸载时,会收到多条回调消息添加到列表中。这向我表明,我不仅在远程加载插件程序集,而且在本地加载插件程序集,因此我的“卸载”机制没有按我所希望的那

我正在构建一个符合以下要求的插件框架:

  • 随意加载/卸载插件
  • 加载的插件中的调用方法
  • 从插件向所有者引发回调事件
为此,我创建了一个新的AppDomain,并将插件程序集加载到其中

到目前为止,我的实现在一定程度上是有效的,但我相信我正在本地appDomain和新appDomain中创建插件的实例

当我第一次加载时,会收到重复的回调消息。当我多次加载/卸载时,会收到多条回调消息添加到列表中。这向我表明,我不仅在远程加载插件程序集,而且在本地加载插件程序集,因此我的“卸载”机制没有按我所希望的那样运行。如果有人能告诉我哪里出了问题,我将不胜感激

我也知道我需要考虑插件的“生命周期”,但不确定在哪里实现

谢谢

(1) 我有一个插件接口

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));
}