如何监控插件工作

How to monitor Plugin work

我的团队正在开发一个插件项目,其中主机应用程序协调插件工作(每个插件都有特定的功能,将在单独的线程上执行)。我正在编写主机应用程序并定义 IPlugin 接口;其他人会开发插件。

问题是:如何知道插件何时完成或抛出异常。我有一个解决方案是使用事件和委托让插件回调主机应用程序,但我认为这种方法并不是很好。因为如果开发插件的人实现了我的 IPlugin 接口但忘记编写引发事件的代码。

在这种情况下,插件可以插入我的主机应用程序,但我的主机应用程序无法知道此插件何时完成或抛出异常或其他通信,这非常糟糕。

我的代码是这样的:

IPlugin.cs:

public delegate void OnFinishDelegate(IPlugin p, AMessageEventArgs e);
public delegate void OnExceptionDelegate(IPlugin p, AMessageEventArgs e);
public interface IPlugin
{
    event OnFinishDelegate OnFinish;
    event OnExceptionDelegate OnException;
    void DoWork();
}

事件参数:

public class AMessageEventArgs:EventArgs
{
    private string message;
    public string Message
    {
        get { return message; }
        set { message = value; }
    }
}

主机应用程序:

static void Main(string[] args)
        {
            // ...ignore load plugin code
            //
            IPlugin p = new Plugin();            

            // register event with IPlugin
            p.OnFinish += new OnFinishDelegate(OnFinishHandler);
            p.OnException += new OnExceptionDelegate(OnExceptionHandler);

            // let plugin do its work on a subthread
            Thread t = new Thread(p.DoWork);
            t.Start();

            // and then main continue do other work...
        }

        // if plugin throw exception, in the host application will 
        // handle this exception...
        private static void OnExceptionHandler(IPlugin p, AMessageEventArgs e)
        {
            // in here will process exception of plugin...
        }

        // if plugin completed its work, it will use OnFinish event to 
        // notify to host application
        private static void OnFinishHandler(IPlugin p,AMessageEventArgs e)
        {
            // in here will process completed work event
        }

我希望插件代码如下所示:

public class Plugin:IPlugin
    {
        // use event to callback host application
        public event OnFinishDelegate OnFinish;
        public event OnExceptionDelegate OnException;

        // Create an EventArgs
        AMessageEventArgs e = new AMessageEventArgs();
        public void DoWork()
        {
            try
            {
                // execute update data
                UpdateData();
            }
            catch (Exception ex)
            {
                e.Message = ex.Message;

                // if have any exception, Plugin will raise an event in host application
                // but if developer forget write below three lines of code, my host application will
                // out of control.
                if (OnException!=null)
                {
                    OnException(this,e);
                }
            }

            // if have no exception, Plugin will use OnFinish event to talk to host application
            // to know that this plugin completed its work
            // but if developer forget write below three lines of code, my host application will
            // out of control.
            if (OnFinish!=null)
            {
                OnFinish(this,e);
            }
        }

如何解决这个问题?

附加问题:我的IPlugin接口定义好了吗?如果不好,你能建议我改进这个界面吗?

谢谢!

我认为插件不需要知道它们 运行 在不同的线程中。我只想:

interface IPlugin { 
    void DoWork(); 
}

然后宿主程序会处理捕获异常和所有线程,比如:

Thread t = new Thread(() => {
    try {
        plugin.DoWork();
    }
    catch (Exception ex) {
        // handle exception or save it to handle in the main thread
    }
});
t.Start();

您已正确识别接口中 event 模型的问题 - 当插件实现 IPlugin 接口时,他们必须定义 OnException 事件,但是不需要他们使用它。

使用单个 DoWork 方法定义您的 IPlugin 接口,并允许标准异常模式报告成功完成或错误状态。如果 DoWork 方法 returns 正常,则插件完成(不需要 OnFinish 事件)。如果 DoWork 抛出异常,您的主应用程序可以捕获异常并处理它(不需要 OnException 事件)。

我建议查看 Task Parallel Library for executing the plugins. It provides more control than using threads directly, including exception handling

我刚刚阅读了 HeadFist 设计模式并发现了一个解决方案:工厂方法。
就我而言,我应该使用抽象 class 而不是接口 (IPlugin)。在这个摘要 class 中,我定义了一个 Operate() 方法,它将向我的主机应用程序报告结果(完成结果或异常结果)。第二种方法是 DoWork() 方法,第三方程序员可以编写他的函数而不关心 OnComplete 或 OnException 事件。
我的代码如下:
摘要class:

public delegate void OnFinishDelegate(APlugin p, AMessageEventArgs e);
    public delegate void OnExceptionDelegate(APlugin p, AMessageEventArgs e);
    public abstract class APlugin
    {
        public  event OnFinishDelegate OnFinish;
        public event OnExceptionDelegate OnException;

        AMessageEventArgs e = new AMessageEventArgs();
        public void Operate()
        {
            try
            {
                // implement plugin work
                // we don't care how does the third party programmer write his Plugin program
                DoWork();

                // if DoWork() completed , it will raise an OnFinish event
                // in my host application
                e.Message = "Completed";
                if (OnFinish != null)
                {
                    OnFinish(this, e);
                }
            }
            catch(Exception ex)
            {
                // if DoWork() throw exception, it will raise an OnException event
                // in my host application
                e.Message = ex.Message;
                if (OnException!=null)
             {
               OnException(this,e);
             }
            }            
        }

        // In here, the third party programmer will override this DoWork() method
        private abstract void DoWork();
    }

主机应用程序代码:

static void Main(string[] args)
        {
            // ...ignore load plugin code
            //
            APlugin p = new Plugin();

            // register event with IPlugin
            p.OnFinish += new OnFinishDelegate(OnFinishHandler);
            p.OnException += new OnExceptionDelegate(OnExceptionHandler);

            // let plugin do its work on a subthread
            Thread t = new Thread(p.Operate);
            t.Start();

            // and then main continue do other work...
        }

        // if plugin throw exception, in the host application will 
        // handle this exception...
        private static void OnExceptionHandler(APlugin p, AMessageEventArgs e)
        {
            // in here will process exception of plugin...
        }

        // if plugin completed its work, it will use OnFinish event to 
        // notify to host application
        private static void OnFinishHandler(APlugin p, AMessageEventArgs e)
        {
            // in here will process completed work event
        }

>

和插件代码(必须如下所示):

class Plugin:APlugin
    {
        public override void DoWork()
        {
            // in here, the third party programmer can write anything
            // for example: update data in database
            UpdateData();
        }

        private void UpdateData()
        {
            // do update data
        }
    }