目录

什么是AOP

示例1:Automatic 控制器记录

拦截器

示例2:低代码查询实现

步骤1:我们想要的

步骤2:代理

步骤3:注释(Annotation)

步骤4:实际操作

带什么回家

参考文献


  • GitHub下载源代码

其原理是AOP(面向切面的编程)。该技术在Java中得到了广泛使用,并有助于轻松地保持高质量的标准。今天,我们将学习如何在.NET Core项目中轻松使用它。在简要的理论解释之后,您将找到两个示例(所有代码都在我的GitHub profile中)。

什么是AOP

让我们从Wikipedia定义开始:

引用:

在计算中,面向切面的编程(AOP)是一种编程范例,旨在通过允许跨领域关注点的分离来提高模块化。通过在不修改代码本身的情况下向现有代码添加其他行为(建议)来做到这一点[…]这允许将对业务逻辑不重要的行为(例如日志记录)添加到程序中,而这是功能的核心。 https://en.wikipedia.org/wiki/Aspect-oriented_programming

这个概念很简单,可以用一句话来概括。

                                                                           使事情发生而无需编写代码。

这适用于所需的所有代码,但不引入任何业务逻辑。

下面是一些有关AOP如何更改我们的代码的示例。第一个是关于日志记录。

public void SaveData(InputClass input)
{Stopwatch timer= new Stopwatch();timer.Start();logger.Info("enterd SaveData method");if(logger.LogLevel==LoggingLeve.Debug){logger.Debug(MyJsonTool.ConvertToJson(input);}dataRepositoryInstance.Save(input);timer.End();logger.Info($"enterd SaveData method in {timer.ElapsedMilliseconds}ms");
}

如果我告诉你所有这些代码仅通过编写就可以产生相同的输出怎么办?

public virtual void SaveData(InputClass input)
{dataRepositoryInstance.Save(input);
}

因此,所有工作都只需在方法中添加一个virtual关键字,那太好了!稍后我们将返回virtual关键字,以了解它与AOP的关系。

如果您不相信AOP的强大功能,请看看如何简化数据获取代码,如下所示:

[Fetch("SELECT * FROM customers WHERE name=?")]
public List<MyDTO> GetByName(string name)
{return new List<MyDTO>();
}

我希望您现在已经确信AOP可以在许多情况下提供帮助并且可以成为强大的盟友。让我们看看它是如何工作的以及如何将其集成到.NET Core应用程序中。

本文包含两个示例:

  1. 使用DinamyProxy和Autofact拦截日志的简单案例
  2. 一个非常好的AOP技术的深入介绍,展示了如何实现AOP引擎

示例1:Automatic 控制器记录

在此示例中,我们将配置一个拦截器来记录所有传入的请求。可以将其扩展到我们应用程序的所有其他层,仅作为概念证明。

拦截器

拦截器的解剖非常简单。在方法执行之前和之后记录它。在此示例中,我使用GUID一起引用事件日志,但是可以进行许多改进。

public class AutofacModule : Module{protected override void Load(ContainerBuilder builder){// Register the interceptorbuilder.Register(c => new CallLogger()).Named<IInterceptor>("log-calls");builder.Register(c => new ValuesService(c.Resolve<ILogger<ValuesService>>())).As<IValuesService>().InstancePerLifetimeScope()                .EnableInterfaceInterceptors();}}  public class CallLogger : IInterceptor{public void Intercept(IInvocation invocation){var executionId = Guid.NewGuid().ToString();Debug.WriteLine("{0} - Calling method {1} with parameters {2}... ", executionId,invocation.Method.Name,JsonConvert.SerializeObject(invocation.Arguments));invocation.Proceed();Debug.WriteLine("{0} - Done: result was {1}.", executionId, JsonConvert.SerializeObject( invocation.ReturnValue));}}

我们可以讨论直到明天为止的愚蠢行为,例如如何将数据愚蠢地转储到日志中,或者我们可以改进该系统以使用更好的日志记录系统,以及一种巧妙的方式来跟踪输入,时序和输出。

如您所见,方法的执行过程带有时序。开箱即用地在ASP.NET Web API应用程序的所有控制器上或业务逻辑上的每个服务方法中对其进行镜像。好吗?它节省了大量的代码行。

示例2:低代码查询实现

本示例说明如何通过添加一些注释将默认行为添加到方法。该示例从头开始实现,没有使用任何库,以突出显示它在后台的工作方式。

要创建的基类是DispatcherProxy。此类为通用类型实现代理,该通用类型拦截方法调用并返回自定义对象。这就是我们需要用有效的方法替换空方法的方法。

无论如何,要实现通用引擎,我们还需要更多。我创建了一个名为AOPAttribute的通用属性,带有很多幻想。继承此注释的每个注释都需要实现执行。使用此模式,所有实现都委托给该属性,并且我们的代理引擎与许多实现完全脱钩。

您可以在下面的代码段中检查代码的相关部分。仅使用几行代码,我们就能实现一个非常强大的引擎,但这只是一个例子。您可以想象可以为您解决多少个用例。

我告诉你太快了吗?只需逐步开始。

步骤1:我们想要的

首先,我们要实现一种机制,该机制允许自动实现方法。在C#中,我们不能在DispatcherProxy类上使用,而只能在接口上使用,因此我们将需要始终从具有所有方法声明的接口开始。无论如何,我们也想手动实现一些方法,因此我们还需要一个具体的类。现在有一个棘手的问题。如果我们让类从逻辑上的接口继承,我们将被迫实现所有方法,因为这是编译器所需要的。我采用的技巧是简单地忘记继承。类和接口之间的关系将在以后的DI中定义。

这是FruitRepository的片段。该接口包含将自动实现的方法和手动实现的InitDB方法。

public interface IFruitRepository
{[Query("SELECT * FROM fruits where family={0}")]List<Fruit> GetFruits(string tree);[Query("SELECT * FROM fruits where family='Citrus'")]List<Fruit> GetCitrus(string tree);public void InitDB();
}public  class FruitRepositoryImpl{public void InitDB(){using (var db = new FruitDB()){db.Database.EnsureCreated();var count = db.Fruits.Count();if (count == 0){db.Fruits.Add(new Fruit(){Name = "Lemon",Family = "Citrus"});//... all the fruit of the world heredb.SaveChanges();}}}}

步骤2:代理

现在,我们需要创建一个代理,该代理将维护接口和已实现的类之间的关系,并基于注释为方法提供服务。此代码非常简单,请参见下面的代码段:

public class ProxyFacotory<T> : DispatchProxy
{private T _decorated;protected override object Invoke(MethodInfo targetMethod, object[] args){        //Find an annotation on the interfacevar annotations = targetMethod.GetCustomAttributes(true);var aopAttr = annotations.FirstOrDefault(x => typeof(AOPAttribute).IsAssignableFrom(x.GetType())) as AOPAttribute;//in case the method has an AOP implementation, this is executedif (aopAttr != null){return aopAttr.Execute(targetMethod, args, annotations);}//otherwise, the manual implementation on class is triggeredvar inherithedMethod=interfaceMethods.FirstOrDefault(x => x.Name == targetMethod.Name);var result = inherithedMethod.Invoke(_decorated, args);return result;}public static T Create<T,TProxy>(TProxy instance) where T : class where TProxy:class{object proxy = Create<T, ProxyFacotory<TProxy>>();((ProxyFacotory<TProxy>)proxy).SetParameters(instance);return (T)proxy;}private void SetParameters(T decorated){_decorated = decorated;}
}

用法非常简单,并使用常规的.NET Core依赖项注入。

//the proxy instance return an instance based on the concrete implementation
var instance=ProxyFacotory<IFruitRepository>.Create<IFruitRepository,FruitRepositoryImpl>(new FruitRepositoryImpl());
var serviceProvider = new ServiceCollection().AddSingleton<IFruitRepository>(instance).BuildServiceProvider();

步骤3:注释(Annotation)

所有的基本注释是AOPAnnotation。这是一个包含替换了通常方法主体的Execute方法的abstract类。然后,我们获得了Query注释(annotation),在本例中,该批注使用了从开发人员传递来的查询模板来获取数据。

public abstract class AOPAttribute: Attribute{public abstract object Execute(MethodInfo targetMethod, object[] args, object[] annotations);}public class QueryAttribute : AOPAttribute{public string Template { get; set; }public   QueryAttribute(string template){this.Template = template;}public override object Execute(MethodInfo targetMethod, object[] args, object[] annotations){using (var data = new FruitDB()){return data.Fruits.FromSqlRaw<Fruit>(this.Template,args ).ToList(); //Dataset can be //taken by target field}}}

步骤4:实际操作

放在一起很简单。只需使用我们手动编写的存储库即可。

var fruitRepository = serviceProvider.GetService<IFruitRepository>();
//This calls the manual method and fill the database
fruitRepository.InitDB();
//This uses a dynamic definition
var fruits=fruitRepository.GetFruits("Citrus");

带什么回家

由于自动化的代码编写,AOP是一种非常有趣的模式。它非常强大,但是有两个缺点:

  1. 性能:深入使用反射和精心制作的其他步骤,可能会增加计算时间
  2. 失去控制:更多的系统为您服务,更多的您不知道如何解决

现代工具和框架无需使用代码即可减少代码,因此并非总是必要的。无论如何,在设计框架或大型基础架构时了解这一点非常重要,因为这可能是赢得战争的正确武器。例如,当我设计RawCMS(开源的无头CMS)的体系结构时,它是一个很好的联盟。

关于性能或稳定性,只需记住Java Spring Framework。它使用它作为一切的基础,如今已成为企业应用程序的最佳选择之一。

所有源代码都在我的GitHub profile

参考文献

  • AOP的用例[ https://github.com/arduosoft/RawCMS ]
  • 关于.NET AOP的精彩文章[ https://medium.com/@nik96a/using-di-with-dispatchproxy-based-decorators-in-c-net-core-ac02f02c5fe5 ]
  • 维基百科上的AOP定义[ https://en.wikipedia.org/wiki/Aspect-oriented_programming ]
  • 本文的源代码[ https://github.com/zeppaman/csharp-aop ]

如何使用AOP改进.NET应用程序相关推荐

  1. 整个改进jango最小程序

    修改应用的views.py 新增urls.py文件(全局路由文件) 增加对本地路由的引用 设置模板框架 [DIRS]路径 整个改进jango最小程序的相关步骤

  2. K均值聚类关于初始聚类中心选取的一种改进(python程序)

    本程序是K均值聚类关于初始聚类中心选取的一种改进,原理来自于周志华的机器学习,这里只是尝试用python实现下.刚开始学习python,可能有问题大家觉得有用就借鉴下,如果哪里有问题还望指正.关于K均 ...

  3. spring框架AOP的理解,程序高类聚的体现

    本文主要介绍AOP思想,而不是Spring,Spring在本文只做为理解AOP的工具和例子,所以也不打算介绍Spring的Aspect.Join point.Advice.AOP proxy等概念,那 ...

  4. (原创)C++11改进我们的程序之move和完美转发

    http://www.cnblogs.com/qicosmos/p/3376241.html 本次要讲的是右值引用相关的几个函数:std::move, std::forward和成员的emplace_ ...

  5. (原创)C++11改进我们的程序之右值引用

    http://www.cnblogs.com/qicosmos/p/3369940.html 本次主要讲c++11中的右值引用,后面还会讲到右值引用如何结合std::move优化我们的程序. c++1 ...

  6. 改进电子白板客户端程序

    侯经理安排了一个小活儿,给那个电子白板的PC端程序改成了多线程,接下来还要重构数据传输的算法.

  7. 使用Eclipse性能测试插件TPTP改进你的程序(一)

    程序在实际应用当中,大数据量时对系统本身的影响是一个不得不面对的问题. 最早在使用Jbuilder时,它有个相配套的工具叫Optimize Suite,可以在JBuilder中使用,也可独立使用,用它 ...

  8. Java程序员从笨鸟到菜鸟之(七十三)细谈Spring(五)spring之AOP底层大揭秘

    众所周知,Java是面向对象语言的有力代表,提到java我们就会立即想到面向对象,提到面向对象我们就会想到java.然而面向对象也并非完美无缺的,它更注重于对象层次结构方面的东西,对于如何更好的管理对 ...

  9. Guice Aop 与 Hasor Aop 原理及其实现

    为什么80%的码农都做不了架构师?>>>    这篇是承接<轻量级 Java 开发框架 设计>系列Blog文的后续文章,本文主要介绍 Hasor 中 AOP 方面的设计以 ...

最新文章

  1. .net 导出excel和word
  2. POSIX 串口编程指南
  3. 使用epoll+时间堆实现高性能定时器
  4. linux下编译C++程序无法链接Mysql的问题
  5. 深度学习与 Spark 和 TensorFlow
  6. Java web(2012/2/22)
  7. Visual Studio 2012 RC 发布
  8. 2.2大数据采集技术
  9. html怎么添加banner图,如何在wordpress首页中添加banner图片?
  10. MongoDB修改器使用
  11. CVF 6.6B 安装无反应(响应)及打开无反应(响应)问题(win10系统)
  12. 制作放射冲击星空粒子海报图片的PS教程
  13. 视频会议软件中的协同文档技术
  14. 广东c语言等级考试,2020广东计算机一级考试试题和答案
  15. java dispose事件_求助!!为什么我的dispose()不起作用
  16. 逆幂律模型_思维模型18 - 幂律分布是什么?
  17. 30多个WP博客推广的Wordpress插件 | 帕兰映像
  18. 我国常见的光伏电站分类
  19. 读赵凯华之《新概念物理教程.光学》
  20. 计算机辅助技术英语,计算机辅助跟踪技术,computer-aided tracking technology,音标,读音,翻译,英文例句,英语词典...

热门文章

  1. python super().__init__()_python——多继承使用super().__init__ 发生的状态
  2. oracle rds 运维服务_RDS oracle数据库运维
  3. android 禁用dlsym_一个绕过移动端系统限制的dlopen库: byOpen
  4. mysql滚动条不见了,11-JS处理滚动条
  5. android responsebody转json_SpringBoot 项目开发是如何返回 json 数据以及数据封装
  6. ajax div iframe,【转】用AJAX模仿IFRAME 在指定DIV打开页面
  7. iis php5.3套件,IIS下安装php5.3
  8. 电脑java语言有什么用_Java语言是什么?_Java语言有什么优点
  9. 值得收藏的品牌案例—到集设,灵感即到
  10. 弹窗实用素材模板|UI设计中的弹窗设计技巧,快get