0、引言
如果你已经开发了一个中型或者大型的 .NET / .NET Framework 项目但还没有为其添加日志系统。那么,你可能需要重新回顾大量的业务逻辑代码,并在其中找到合适的位置,编写合适的日志输出语句进行插入🙁。
显然,这是一个非常耗时且麻烦的工作,并且会对业务逻辑代码产生大量改动,造成代码的可读性变差。好在,我们可以利用面向切面编程(AOP)这一编程范式😀。在不修改现有代码的基础上,通过添加行为(Advice
)来解决横切关注点;将通用功能(比如日志记录)从业务逻辑中抽离出来,使得我们能够专注于业务逻辑本身。
如果您不是很了解 AOP,那么以下的链接将会很有帮助:
- Aspect-oriented programming
- 细说Spring——AOP详解(AOP概览)
- Spring AOP(一) AOP基本概念
- 面向对象困境之 —— 横切关注点
- Aspect Oriented Programming
- What is Aspect-Oriented Programming (AOP)?
- AOP简单介绍
1、.NET 平台下的 AOP 实现
有非常多的编程语言都实现了 AOP,您可以在这里查看比较详细的列表。但我们的项目是基于 .NET / .NET Framework 的,使用的日志框架也是 log4net,所以我们重点关注 .NET 平台下的 AOP 框架:
名称 | logo | 描述 |
---|---|---|
PostSharp.il | PostSharp 旗下商业产品,一个基于 MSIL 的 .NET 下的面向切面框架,拥有功能受限的免费版本。 | |
Metalama | PostSharp 旗下商业产品,一个 C# 中用于简洁代码的框架,拥有功能受限的免费版本。(MSDN 上提供了 Metalama 的教程) | |
Castle DynamicProxy | 一个用于在运行时动态生成轻量级 .NET 代理的库。代理对象允许在不修改类代码的情况下拦截对对象成员的调用。类和接口都可以被代理,但是只有虚成员可以被拦截。许多其他框架(如 Spring.NET、AspectCore-Framework 等)都内部使用了 Castle DynamicProxy 来提供 AOP 功能。 | |
Spring.NET | 一个全功能的 .NET 应用程序框架,不仅提供了依赖注入和面向切面编程(AOP),还提供了数据访问抽象、ASP.NET 集成等功能(更多详细介绍)。 | |
AspectCore-Framework | AspectCore 是一个面向 .NET Core 和 .NET Framework 的基于 AOP 的跨平台框架。Core 支持切面拦截器、依赖注入集成、Web 应用程序、数据验证等。 |
以上都是最近仍有更新的项目;如果您想要了解还有哪些更多 .NET 平台下的 AOP 框架仍然是活跃的,可以参考如下回答:
- What is the best implementation for AOP in .Net?
- What Aspect-Oriented Programming (AOP) libraries for .NET are still actively developed?
2、实践
对于上面介绍的几个 .NET 平台下的 AOP 实现,笔者只用过 PostSharp.il(尽管它是一个商业产品)。一是其使用门槛不高,很容易上手;二是 PostSharp 还是提供了功能受限的免费版本 —— PostSharp [Essentials] 的,而且即便功能受限,完成日志记录这一简单需求还是绰绰有余的。
此外,PostSharp Technologies 为学生、教室、开源项目、MVP、博客作者、流媒体主播、用户组领导者以及黑客马拉松等提供了免费的 Metalama 和 PostSharp 许可证。如果您需要,完全可以在他们的官方网站上申请免费许可证,以体验完整版(PostSharp [Ultimate])的所有功能。
PostSharp [Ultimate] 包括以下所有单独的 PostSharp 产品:
- PostSharp [Framework]:构建您自己的切面,并开始从您的 .NET 代码库中消除样板代码。
- PostSharp [Logging]:在对源代码没有任何影响的情况下为您的 .NET 项目添加高度详细的日志记录。
- PostSharp [MVVM]:消除
INotifyPropertyChanged
样板代码等。 - PostSharp [Threading]:在 .NET 中编写可验证的线程安全代码,而不用绞尽脑汁。
- PostSharp [Caching]:通过一个简单的自定义属性来提高您的 .NET 应用程序性能。
到这里已经很明显了:如果我们只是想为现有的应用程序添加日志记录的功能。那么单独的 PostSharp [Logging] 产品就可以满足需求了。
以下是配置 PostSharp [Logging] 的简略步骤:
📌 为什么只有简略步骤?
因为所有步骤都非常简单,按照简略步骤中的外部链接提示操作即可。
- 首先创建一个简单的应用程序(比如:使用 .NET 创建 Windows 窗体应用)
- 有关如何开始使用 PostSharp.il 的介绍参考官方网站的 Get started 即可。
- 如何将 PostSharp [Logging] 添加到我们的代码库,参考官方文档的 Getting Started with PostSharp Logging 即可。
- 如何将 PostSharp [Logging] 连接到 log4net 目标日志框架,参考官方文档的 Writing PostSharp Logging events to log4Net 即可。
- 如何配置日志信息的详细程度,参考官方文档的 Adjusting Logging Verbosity 即可(可选步骤)。
- 下图展示了一个日志文件的生成位置及内容示例:
- 完整源码请参考
WinFormsApp4DotNet
。
结果
最终我们(在对源代码没有任何影响的情况下)将日志记录添加到项目方法中。我们将获得程序执行的超详细日志,包括参数值和返回值。可以添加、删除或重命名方法或其参数;无需担心,日志条目将与每个更改保持同步。将日志记录添加到代码库并维护它成为一项非常简单的任务。
📜 笔记
除了用于记录日志,面向切面编程(AOP)还有几种常见的应用场景:
- 监控方法运行时间:通过 AOP 可以方便地统计方法的运行时间,从而进行性能分析;
- 权限控制:通过 AOP 可以在方法执行前进行权限验证,从而实现统一的权限控制;
- 缓存优化:例如,第一次调用查询数据库,将查询结果放入内存对象,第二次调用时,直接从内存对象返回,不需要查询数据库;
- 事务处理:可以在方法执行前后进行事务的开启和提交,实现统一的事务管理;
- 异常处理:可以在方法抛出异常后进行统一的异常处理;
- 资源池管理:可以在方法执行前后进行资源的获取和释放,实现统一的资源管理;
- …
总之,只要有大量重复的样板代码,或者有一些公共功能需要在多个地方使用,就可以考虑使用 AOP。
3、外部链接:
- C#进阶系列——AOP?AOP!
- 如何优雅地记录操作日志?
- SpringBoot AOP 详解和多种使用场景
- Spring AOP在项目中的典型应用场景