postsharp_使用PostSharp进行DRY异常处理

postsharp

面向方面的编程? (Aspect Oriented Programming?)

所以首先要注意的是:

What is Aspect Oriented Programming (AOP)?

什么是面向方面的编程(AOP)?

AOP is a coding pattern that allows the developer to isolate repetitive and often technical code from the business logic. It differs from the normal refactoring towards the single responsibility principle. AOP completely removes the code from the visible code-base to be, and instead configurs and "injects" it at compile-time or execution-time depending on the language. Wikipedia does a good job explaining it in much deeper detail.

AOP是一种编码模式,允许开发人员从业务逻辑中分离出重复的,通常是技术性的代码。 它不同于针对单一责任原则的常规重构。 AOP完全从可见的代码库中删除了代码,而是根据语言在编译时或执行时对其进行配置和“注入”。 维基百科很好地解释了它的细节。

一个很好的例子? (One good example?)

异常处理和日志记录就是一个很好的例子。

All applications have their own way of handling exceptions, and the complexity greatly depends on the number of systems and modules integrated.

所有应用程序都有自己的异常处理方式,其复杂性很大程度上取决于集成的系统和模块的数量。

On a SOAP service, for instance, you might end up with a nasty list of try/catch(es) in order to be able to log the exceptions in different categories (Technical, Business, Unhandled) and you need to repeat this logic for every service method. On top of that, it will pollute enormously the code without adding any business value to it; it's just technical code!

例如,在SOAP服务上,您可能会得到一个麻烦的try / catch列表,以便能够记录不同类别(技术,业务,未处理)中的异常,并且您需要重复此逻辑以用于每种服务方法。 最重要的是,它将极大地污染代码,而不会增加任何商业价值。 这只是技术代码!

Take this example:

举个例子:

public void DoSomething()
{
    try
    {
        // do whatever you need to do
    }
    catch (BusinessException ex)
    {
        // log this with a lower severity
        // create the message to be logged
        // concat the stack trace or whatever good way to document the error
        // call your logging tool of choice /SemanticLogging, Log4Net, NLog, ...)
    }
    catch (TechnicalException ex)
    {
        // log this with a higher severity
        // create the message to be logged
        // concat the stack trace or whatever good way to document the error
        // call your logging tool of choice /SemanticLogging, Log4Net, NLog, ...)
    }
    catch (Exception ex)
    {
        // make all hell brake loose!
        // create the message to be logged
        // concat the stack trace or whatever good way to document the error
        // call your logging tool of choice /SemanticLogging, Log4Net, NLog, ...)
    }
}
image.gif
image.gifThis is just for one method... we need to repeat all of it for all the methods.

使其干燥 (Making it DRY)

DRY代表

Don't

Repeat

[R EPEAT

Yourself, and if you look at the above code, you already see a lot of repetition; adding more methods will only make it worse.

是的 ,如果您看一下上面的代码,您已经发现很多重复。 添加更多方法只会使情况变得更糟。

Wouldn't it be nice if you could simply write

如果您可以简单地写,那会不会很好

public void DoSomething()
{
  // do whatever you need to do
}
image.gif
image.gif and still be able to handle the exceptions in the same way but behind the scenes?


PostSharp进行救援 (
PostSharp to the rescue)

PostSharp是一个免费工具,可在.Net Framework上实现AOP。 “免费”是指免费,就像免费啤酒一样。 尽管它们具有商业版本,但Express版本具有完整的功能,受支持并且是其商业产品的基础。 您也可以将其用于商业目的等等。 我建议阅读他们的常见问题解答并比较他们的版本。

With PostSharp we can have something like:

借助PostSharp,我们可以提供以下内容:

[MyExceptionHandler]
public void DoSomething()
{
  // do whatever you need to do
}
image.gif
image.gif or even better, applied to all the methods within the class:
[MyExceptionHandler]
public class MyClass
{
  public void DoSomething()
  {
    // do whatever you need to do
  }
}
image.gif
image.gif
image.gif

()

But what is that

那是什么

MyExceptionHandler attribute? It's a custom attribute that looks like this: MyExceptionHandler属性? 这是一个自定义属性,如下所示:
[Serializable]
public class MyExceptionHandlerAttribute : OnExceptionAspect
{
  public MyExceptionHandlerAttribute (){ }

  public override void OnException(MethodExecutionArgs args)
  {
    if (args.Exception.GetType().Equals(typeof(BusinessException)))
    {
       if (args.Exception.InnerException == null)
         MyEventSource.Log.BusinessError(args.Exception.Message);
       else
       {
         var message = args.Exception.Message;
         var extraInfo = args.Exception.InnerException.ToString();

         MyEventSource.Log.BusinessError(message, extraInfo);
       }
    }
    else if (args.Exception.GetType().Equals(typeof(TechnicalException)))
    {
      var message = args.Exception.Message;
      var extraInfo = args.Exception.InnerException?.ToString();
      var stackTrace = args.Exception.StackTrace;

      MyEventSource.Log.TechnicalError(message, extraInfo, stackTrace);
    }
    else
    {
       var message = args.Exception.Message;
       var extraInfo = args.Exception.InnerException?.Message;

       MyEventSource.Log.UnhandledError(message, extraInfo);
    }


    /*
    USE THIS IF YOU DON'T WANT TO RETHROW THE EXCEPTION.
    LIKE THIS YOU LOG THE ERROR AND THE APPLICATION WON'T COMPLAIN.

    IF THIS IS FOR A WEB APP, YOU CAN CONSIDER NOTIFYING THE USER OR 
      REDIRECTING TO AN ERROR PAGE */
    args.FlowBehavior = FlowBehavior.Continue;
  }

}

OnExceptionAspect方面 (The OnExceptionAspect aspect)

OnExceptionAspect告诉PostSharp在幕后发挥其魔力,而且非常重要的是,

at compile time. PostSharp will wrap the contents of the method that has this attribute with a try/catch block, so this has nothing to do with runtime Reflection and won't impact the performance of your application.

在编译时 。 PostSharp将使用try / catch块包装具有此属性的方法的内容,因此与运行时反射无关,并且不会影响应用程序的性能。

OnExceptionAspect has only one method to override that is the OnException:

OnExceptionAspect只有一种方法可以重写,即OnException:

public override void OnException(MethodExecutionArgs args)
{
  // handle the exception
}

MethodExecutionArgs, has all the information you need in order to decide what to do with the exception. Have a look at the documentation for a complete reference.

MethodExecutionArgs,具有您需要的所有信息,以便决定如何处理异常。 请参阅文档以获取完整参考。

()

You might also wonder what's that

您可能还想知道那是什么

MyEventSource there, right? At that point, it really depends on what kind of logging mechanism you want to use. Personally, I like SemanticLogging, but Log4Net and NLog are also really good options. The logging tool implementation itself, as it can be anything you want, is out of the scope of this article. I might write about them in separate articles. MyEventSource在那里,对吗? 那时,它实际上取决于您要使用哪种日志记录机制。 就个人而言,我喜欢SemanticLogging,但是Log4Net和NLog也是非常好的选择。 日志工具实现本身(可能是您想要的任何东西)不在本文的讨论范围之内。 我可能会在单独的文章中写它们。

So my implementation, for SemanticLogging, is the following:

因此,对于SemanticLogging,我的实现如下:

[EventSource(Name = "MyApp")]
public class MyEventSource : EventSource
{
  public class Keywords
  {
    public const EventKeywords Page = (EventKeywords)1;
    public const EventKeywords DataBase = (EventKeywords)2;
    public const EventKeywords Diagnostic = (EventKeywords)4;
    public const EventKeywords Perf = (EventKeywords)8;
  }

  public class Tasks
  {
    public const EventTask Page = (EventTask)1;
    public const EventTask DBQuery = (EventTask)2;
  }

  private static MyEventSource _log = new MyEventSource();
  private MyEventSource() { }
  public static MyEventSource Log { get { return _log; } }

  [Event(500, Message = "Unhandled Error: {0}. Extra Info: {1}", Level = EventLevel.Critical, Keywords = Keywords.Diagnostic)]
  internal void UnhandledError(string message, string extraInfo)
  {
    if (this.IsEnabled())
      this.WriteEvent(500, message ?? "", extraInfo ?? "");
  }

  [Event(501, Message = "Application Technical Error: {0}. Extra Info: {1}. StackTrace: {2}", Level = EventLevel.Critical, Keywords = Keywords.Diagnostic)]
  internal void TechnicalError(string message, string extraInfo, string stackTrace)
  {
    if (this.IsEnabled())
      this.WriteEvent(501, message ?? "", extraInfo ?? "", stackTrace ?? "");
  }

  [Event(400, Message = "Application Business Error: {0}. Extra Info: {1}", Level = EventLevel.Critical, Keywords = Keywords.Diagnostic)]
  internal void BusinessError(string message, string extraInfo = null)
  {
    if (this.IsEnabled())
      this.WriteEvent(400, message ?? "", extraInfo ?? "");
  }

  [Event(200, Message = "{0}", Level = EventLevel.Informational)]
  public void Information(string message)
  {
    if (this.IsEnabled()) this.WriteEvent(200, message ?? "");
  }

} 

你还能做什么? (What else can you do?)

好的,到此为止您已经有了AOP的想法,OnExceptionAspect只是PostSharp支持的许多方面之一。 PostSharp文档所做的工作非常出色,不仅描述了PostSharp本身,而且还描​​述了整个AOP概念。

Make sure you have a good look at it: Documentation.

确保您对它有一个很好的了解:文档。

翻译自: https://www.experts-exchange.com/articles/24979/DRY-Exception-Handling-with-PostSharp.html

postsharp

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 .NET Framework 4.6.2 中,可以使用 AOP(面向切面编程)来实现日志记录。下面是一个简单的示例,演示了如何使用 PostSharp AOP 框架来实现日志记录: 1. 首先,需要在 Visual Studio 中安装 PostSharp AOP 框架。可以通过 NuGet 包管理器来安装。 2. 在项目中创建一个名为 `LoggingAspect` 的类,并实现 `OnEntry` 和 `OnExit` 方法。这两个方法分别在方法调用前和调用后被调用。在这两个方法中,可以编写日志记录的逻辑。 ```csharp using PostSharp.Aspects; using System; namespace MyProject { [Serializable] public class LoggingAspect : OnMethodBoundaryAspect { public override void OnEntry(MethodExecutionArgs args) { Console.WriteLine("Entering method {0}", args.Method.Name); } public override void OnExit(MethodExecutionArgs args) { Console.WriteLine("Exiting method {0}", args.Method.Name); } } } ``` 3. 在需要记录日志的方法上,添加 `LoggingAspect` 特性。这个特性将会在方法调用时自动地被触发。 ```csharp [LoggingAspect] public void MyMethod() { // some logic here } ``` 在上面的代码中,`MyMethod` 方法上添加了 `LoggingAspect` 特性,这意味着在执行 `MyMethod` 方法时,`LoggingAspect` 类中的 `OnEntry` 和 `OnExit` 方法将会被自动调用。 这样,当你调用 `MyMethod` 方法时,你将会看到类似下面的日志输出: ``` Entering method MyMethod // some logic here Exiting method MyMethod ``` 这就是一个简单的 AOP 日志记录的实现方式。当然,PostSharp AOP 框架还有很多其他的功能,如果你感兴趣的话,可以去官网了解更多信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值