异常处理:AOP与经典处理?

时间:2012-06-28 12:48:23

标签: c# .net exception aop spring.net

我正在升级插件加载引擎.NET),其执行以下操作:

  1. 加载插件
  2. 将它们连接到相应的数据源
  3. 启动插件
  4. 显示结果
  5. 所有插件都实现相同的接口:IPlugin,每个插件都在单独的BackGroundWorker中启动。所有BackgroundWorkers都由名为Host的模块管理。

    我的问题是Errors/Exceptions Handling。该引擎已经部署,我想找到一种优雅的方法来处理插件运行时可能抛出的Errors/Exceptions。一些Exceptions被插件插入,但不是全部。

    我正在考虑一个可以捕获错误的单独层,并为所有插件处理它们。

    我想象一种Context附加到每个Plugin,其中包含其进度级别(BackgroundWorker.ReportProgress),其状态,抛出异常(使用RunWorkerCompletedEvent)但是只有在BackgroundWorker停止后才会抛出错误。我想在抛出异常时中断它。

    我还认为面向方面编程可能是一个很好的方法。我在网上看了一下,发现了像 Spring.NET 这样的框架。但不确定它是否适合我的情况。

    [UPDATE] 以下是更多设计细节:

    • IPlugin接口:名为AbstractEnvChecker

    AbstractEnvChecker

    该应用程序是富客户端应用程序。编译插件后,将加载生成的DLL,并在简单的Windows窗体中向用户显示列表。然后,用户选择要启动的插件,并调用Plugin.DoWork()方法。

    以下是主机启动所选插件的方式:

    void LaunchPlugin(AbstractEnvChecker p_Plugin)
    {
        if (p_Plugin != null)
        {
            BackgroundWorker l_BackgroundWorker = new BackgroundWorker();
            l_BackgroundWorker.WorkerReportsProgress = true;
            l_BackgroundWorker.WorkerSupportsCancellation = true;
    
            l_BackgroundWorker.DoWork +=
                new DoWorkEventHandler(bw_DoWork);
            l_BackgroundWorker.ProgressChanged +=
                new ProgressChangedEventHandler(bw_ProgressChanged);
            l_BackgroundWorker.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    
            m_PluginByThreadMap.Add(l_BackgroundWorker, p_Plugin);
            l_BackgroundWorker.DoWork += p_Plugin.DoWork;
            l_BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(l_BackgroundWorker_RunWorkerCompleted);
            l_BackgroundWorker.RunWorkerAsync(p_Plugin);
        }
    }
    

    AOP是否是添加错误处理层的合适解决方案?

2 个答案:

答案 0 :(得分:3)

最简单的方法是将IPlugin.DoWork()方法包装在try/catch子句中。像这样的东西:

l_BackgroundWorker.DoWork += (o, e) => ExecutePlugin(o, e, p_plugin);

private void ExecutePlugin(object sender, DoWorkEventArgs e, IPlugin plugin)
{   
   try 
   { 
      plugin.DoWork(o, e);
   }
   catch (Exception e)
   {
      //do something with the error. disable the plugin maybe?
   }
}

如果这项工作然后使用Spring进行错误处理在我看来有点矫枉过正。

您可以执行的其他操作是抛出自定义异常(例如PluginException)并在应用程序中全局处理这些异常,这可以通过附加到: Application.ThreadExceptionAppDomain.CurrentDomain.UnhandledException次活动

答案 1 :(得分:1)

Spring.net使用动态编织,这基本上意味着在运行时Spring.net aop可以围绕方法调用包装异常处理程序。但Spring.net aop需要一个接缝来定位它的拦截器。

如果您的插件应该加载到UI中,那么用户(可能)可以调用不通过主机或IPlugin接口的方法,这使得弹簧很难(如果不是不可能) .net aop to intercept and wrap exception handler。

如果你的主机是一个调用myPlugin.DoWork()的控制台应用程序或服务,那么它绝对有可能拦截使用Spring.net aop插件引发的任何异常。如果您可以提供更多详细信息(请参阅您的问题的评论),那么我可以告诉您如何执行此操作。

下面的示例使用Spring.net AOP代理插件实例并使用拦截器包装它,捕获抛出的异常并将其委托给主机。请注意,你可以在没有AOP的情况下做到这一点......这取决于你。

using System;
using AopAlliance.Intercept;
using NUnit.Framework;
using Spring.Aop.Framework;

namespace Aop
{

    [TestFixture]
    public class SimpleProxyFactoryTests
    {
        [Test]
        public void Main()
        {
            var host = new Host();

            var mp = new SimplePlugin(); 
            var pf = new ProxyFactory(mp);
            pf.AddAdvice(new DelegateToHostExceptionHandlingAdvice(host));

            var proxy = (IPlugin)pf.GetProxy();

            proxy.DoWork();
        }
    }

    public interface IPlugin
    {
        void DoWork();
    }

    public class Host
    {
        public void HandleExceptionFromPlugin(Exception ex)
        {
            Console.WriteLine("Handling exception: {0}", ex.Message);
        }
    }

    public class SimplePlugin : IPlugin
    {
        public void DoWork()
        {
            Console.WriteLine("Doing it and throwing an exception ... ");

            throw new ApplicationException("Oops!");
        }
    }

    public class DelegateToHostExceptionHandlingAdvice : IMethodInterceptor 
    {
        private readonly Host _host;

        public DelegateToHostExceptionHandlingAdvice(Host host)
        {
            _host = host;
        }

        public object Invoke(IMethodInvocation invocation)
        {
            try
            {
                return invocation.Proceed();
            }
            catch (Exception ex)
            {
                 _host.HandleExceptionFromPlugin(ex);
                return null; 
            }
        }
    }
}

讨论

我希望我已经向您展示了如何利用aop框架来进行异常处理。作为Sebastian mentions in his answer,使用Spring aop 进行异常包装可能会被认为是矫枉过正 - 我同意;将他的代码示例的简单性与我的复杂性进行比较。想象一下,向团队中的新开发人员解释任何一个。

当你将它与Spring IOC容器结合使用时,Spring aop开始“闪耀”。