qq_45526359 2024-04-30 09:56 采纳率: 0%
浏览 49

C# 怎么在一个类库项目中去捕捉全局异常,或者使用AOP切面处理所有异常

想在类库项目中拦截所有异常并统一处理。像Web项目一样有个异常过滤器一样的东西,捕捉到后统一处理

  • 写回答

5条回答 默认 最新

  • 专家-皆知 2024-04-30 09:56
    关注

    参考免费微信小程序:皆我百晓生 作答,经由专家-皆知整理回复,如问题解决,望采纳;如仍有疑问,请评论回复。

    在C#的类库项目中实现全局异常捕获,可以采用AOP(面向切面编程)的思想,因为.NET Framework本身并不直接支持AOP,但可以通过一些框架来实现,比如PostSharp。对于.NET Core和.NET 5及以上版本,可以利用依赖注入结合中间件或者自定义日志处理的方式来实现类似的功能,但在类库项目中,我们更倾向于轻量级的解决方案,因此下面我会提供两种方法:一种是使用PostSharp(如果项目允许引入第三方库),另一种是通过扩展方法和委托来模拟AOP的行为。

    使用PostSharp(适用于不排斥引入第三方库的情况)

    1. 安装PostSharp:首先,你需要通过NuGet包管理器安装PostSharp。

      Install-Package PostSharp
      
    2. 创建一个Attribute:然后,创建一个继承自OnExceptionAspect的自定义特性,用于捕获异常。

      using PostSharp.Aspects;
      using System;
      
      [Serializable]
      public class GlobalExceptionAspect : OnExceptionAspect
      {
          public override void OnException(MethodExecutionArgs args)
          {
              Exception ex = args.Exception;
              // 在这里处理异常,例如记录日志、通知等
              Console.WriteLine($"捕获到异常: {ex.Message}");
              // 可以选择重新抛出异常或者不处理
              args.FlowBehavior = FlowBehavior.Continue; // 不中断方法执行
              // 或者
              // args.FlowBehavior = FlowBehavior.Return; // 中断方法执行并返回
              // 如果你想重新抛出异常
              // throw ex;
          }
      }
      
    3. 应用到类库的方法上:在需要捕获异常的方法上应用这个特性。

      public class MyClass
      {
          [GlobalExceptionAspect]
          public void MyMethodThatMayThrow()
          {
              // 方法逻辑...
              throw new InvalidOperationException("演示异常");
          }
      }
      

    不使用第三方库的简化AOP实现

    如果你不想引入外部库,可以通过扩展方法和事件订阅来模拟AOP行为,但这需要在调用方法时显式地使用这些扩展方法。

    1. 定义事件和扩展方法

      public static class ExceptionHandlingExtensions
      {
          public static event EventHandler<ExceptionEventArgs> ExceptionOccurred;
      
          public static TResult SafeInvoke<T, TResult>(this T instance, Func<T, TResult> method)
              where T : class
          {
              try
              {
                  return method(instance);
              }
              catch (Exception ex)
              {
                  ExceptionOccurred?.Invoke(null, new ExceptionEventArgs(ex));
                  // 根据需要处理异常,比如记录日志
                  throw; // 再次抛出,以便调用者可以处理
              }
          }
      }
      
      public class ExceptionEventArgs : EventArgs
      {
          public ExceptionEventArgs(Exception exception)
          {
              Exception = exception;
          }
      
          public Exception Exception { get; }
      }
      
    2. 使用扩展方法

      然后在你的类库方法调用时使用这个SafeInvoke方法。

      public class MyClass
      {
          public int DoWork(int value)
          {
              if (value < 0) throw new ArgumentException("Value cannot be negative.");
              return value * 2;
          }
      }
      
      // 调用方
      MyClass myClass = new MyClass();
      try
      {
          var result = myClass.SafeInvoke(c => c.DoWork(-1));
      }
      catch (Exception ex)
      {
          // 这里可以处理捕获的异常
      }
      
    3. 订阅异常事件

      在程序启动或初始化阶段,订阅ExceptionOccurred事件来集中处理异常。

      ExceptionHandlingExtensions.ExceptionOccurred += (sender, args) =>
      {
          Console.WriteLine($"全局异常处理: {args.Exception.Message}");
          // 进行日志记录等操作
      };
      

    这两种方法各有优劣,使用PostSharp更为直接和强大,但需要额外的依赖;而第二种方法更为轻量,但需要在每个可能抛出异常的方法调用上显式使用扩展方法。根据项目需求选择合适的方式。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 4月30日