在C#中使用CastleDynamicProxy 实现AOP
原文链接:Aspect Oriented Programming (AOP) in C# using CastleDynamicProxy
本文主要展示在C#中如何使用Castle DynamicProxy来解耦logging体系
简介
在这篇文章中,我将带你在.NET环境中实现Aspect-Oriented Programming (AOP) ,演示如何使用Castle DynamicProxy创建一个切面。在开始之前,我简单的介绍下AOP and IoC,如果你已经熟悉这些概念,你可以直接跳过下面的步骤。
什么是AOP?
Aspect-oriented programming (AOP) 面向切面编程是一个编程范式,以允许增加模块化横切关注点的分离。An aspect (方面,AOP概念中的术语,为了不混淆,下文使用英文表示,不做中文翻译)是一种常见的功能,通常是分散在类和对象层次结构中的公用方法。这些行为看起来有结构,但使用传统的面向对象编程(OOP)无法找到一个方式来表达它。
aspect一个比较贴切的例子是本文中将要讨论的日志记录功能,通常你需要在代码中编写日志,但是日志功能通常并不属于领域对象的职责。
使用AOP方法,我们可以创建这些aspects的横切关注点,并使用多种技术将它们集中附加到领域对象。IL代码编织和拦截是广泛使用的方法。在本文中,我将带你使用Castel Windsor动态框架来处理aspects的创建和应用。
控制反转(Inversion of control=Ioc)/依赖注入容器(DI Container)
IoC容器是一个用来在需要时自动创建和依赖项注入的框架。DI容器可以帮助我们以简单和更有效的方式管理应用程序中的依赖项
大多数的主流的DI(依赖注入)容器具有拦截的内置支持。这是一项高级技术,使用它可以拦截方法调用并改变在运行时期间的域对象的行为。我们将利用此功能附加aspects到我们的域对象。我选择的DI框架是Castle Windsor ,它的 DynamicProxy ,是比较流行的应用aspects的方法之一。
在CodeProject有很多很好的文章和博客提供了关于(IoC)主题更详细的资料。对IoC更大范围的详细讨论不在本文的范围内。
使用Castle DynamicProxy进行拦截
Castle DynamicProxy是一个在运行时生成.NET代理的库。 它允许你动态地更改和扩展业务对象的行为。因为横切关注点与核心领域模型的彻底解耦使得你的域模型更容易维护。如果为任何组件指定拦截,Castle 会自动创建代理。可以使用拦截器注入特定行为到代理中。
你可能会好奇这整件事的内部如何工作。每当调用方请求业务对象(具体类),IoC容器在DynamicProxy的帮助下,解析并将其包装在一个包含指定的拦截器的代理对象中。然后容器返回代理对象到调用方。然后,调用方直接与代理进行交互。 代理截取每个针对业务对象的方法调用,并让请求按照流程通过拦截器传递
下图显示请求如何进入代理。您可以看到请求在实际执行方法之前和之后都要通过所有拦截器。
在项目中使用 Castle DynamicProxy的步骤
· 使用Nuget下载和安装 ‘Castle.Windsor’ 包.
· 实现 IInterceptor 接口. 这是要被 DynamicProxy的接口.
- 实现IRegistration 接口并且注册组件. 注册拦截器其次是业务组件。指定每个业务组件要使用的拦截器。
- 为Windsor创建静态实例容器(IWindsorContainer),用该组件注册信息初始化它。.
这几乎是Castle DynamicProxy需要的所有配置
开始编码
晴朗的一天在班加罗尔微风习习,这样的天气条件适合发射火箭!让我们开始我们的示例应用程序。 此应用程序包含业务对象'Rocket'我们使用一个控制台应用程序来模拟火箭的发射。
接口包含一个签名叫” Launch”的行为。
- public interface IRocket
- {
- void Launch(int delaySeconds);
- }
然后我们来实现接口中的”Launch”方法。
- public class Rocket : IRocket
- {
- public string Name { get; set; }
- public string Model { get; set; }
- public void Launch(int delaySeconds)
- {
- Console.WriteLine(string.Format(" {0} 秒收启动火箭发射", delaySeconds));
- Thread.Sleep(1000 * delaySeconds);
- Console.WriteLine("恭喜, 你的火箭发射成功");
- }
- }
是时候来创建我们第一个拦截器了.我们需要继承实现IInterceptor ,这个接口最终会被DynamicProxy使用.
正如你在下面看到的,我们在方法进入时进行日志记录,通过调用invocation.Proceed()来执行真正的业务行为,然后在方法执行成功后、发生异常和退出时分别进行了日志记录。我们不在需要在我们的业务模型中编写相关日志记录的代码。我们只需要将LoggingInterceptor附加到需要日志记录的组件上。
- internal class LoggingInterceptor : IInterceptor
- {
- public void Intercept(IInvocation invocation)
- {
- var methodName = invocation.Method.Name;
- try
- {
- Console.WriteLine(string.Format("执行方法:{0}, 参数: {1}", methodName, string.Join(",", invocation.Arguments)));
- invocation.Proceed();
- Console.WriteLine(string.Format("成功执行了方法:{0}", methodName));
- }
- catch (Exception e)
- {
- Console.WriteLine(string.Format("方法:{0}, 异常信息:{1}", methodName, e.Message));
- throw;
- }
- finally
- {
- Console.WriteLine(string.Format("退出方法:{0}", methodName));
- }
- }
- }
DynamicProxy 代理提供的对象是非常有用的。它使你可以访问当前方法的方法信息、参数、返回代码值和许多其他细节,如你下面看到的。.
- public interface IInvocation
- {
- object[] Arguments { get; }
- Type[] GenericArguments { get; }
- object InvocationTarget { get; }
- MethodInfo Method { get; }
- MethodInfo MethodInvocationTarget { get; }
- object Proxy { get; }
- object ReturnValue { get; set; }
- Type TargetType { get; }
- object GetArgumentValue(int index);
- MethodInfo GetConcreteMethod();
- MethodInfo GetConcreteMethodInvocationTarget();
- void Proceed();
- void SetArgumentValue(int index, object value);
- }
实现IRegistration 接口并注册组件. 注册拦截器其次是业务组件。指定每个业务组件要使用的拦截器。正如您可能已经注意到,LoggingInterceptor被附加到我们唯一的业务组件的Rocket中
- public class ComponentRegistration : IRegistration
- {
- public void Register(IKernelInternal kernel)
- {
- kernel.Register(
- Component.For<LoggingInterceptor>()
- .ImplementedBy<LoggingInterceptor>());
- kernel.Register(
- Component.For<IRocket>()
- .ImplementedBy<Rocket>()
- .Interceptors(InterceptorReference.ForType<LoggingInterceptor>()).Anywhere);
- }
- }
为 Windsor container (IWindsorContainer)创建静态实例, 使用组件注册信息对它进行初始化(ComponentRegistration)。
- public class DependencyResolver
- {
- private static IWindsorContainer _container;
- //Initialize the container
- public static void Initialize()
- {
- _container = new WindsorContainer();
- _container.Register(new ComponentRegistration());
- }
- //Resolve types
- public static T For<T>()
- {
- return _container.Resolve<T>();
- }
- }
在控制台应用中启动应用程序
- private static void Main(string[] args)
- {
- DependencyResolver.Initialize();
- //resolve the type:Rocket
- var rocket = DependencyResolver.For<IRocket>();
- //method call
- try
- {
- rocket.Launch(5);
- }
- catch (Exception ex)
- {
- }
- System.Console.ReadKey();
- }
让我们看一下控制台的输出。 不出所料,我们的LoggingInterceptor拦截方法调用并自动记录方法进入和退出。由于动态代理!. Thanks to DynamicProxy !
知识点
这是一个介绍性的文章,使初学者和中级开发人员理解使用 Castle Windsor DynamicProxy来理解AOP的基本概念。在未来的几天,我将不断更新这篇文章,以演示如何在一个Web Api项目中使用Log4net和动态代理在实现此日志记录解决方案
在C#中使用CastleDynamicProxy 实现AOP的更多相关文章
- Castle框架中的IOC和AOP机制
反转控制(IOC)和面向切面编程(AOP)技术作为当前比较流行的技术,其优势已受到广泛关注,但是这两项新技术在实际项目上的应用研究却很落后,而且在.NET平台下实现这两项技术没有形成可以广泛套用的框架 ...
- 理解Spring中的IOC和AOP
我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式 IOC就是典型的工厂模式,通过ses ...
- 详谈 Spring 中的 IOC 和 AOP
这篇文章主要讲 Spring 中的几个点,Spring 中的 IOC,AOP,下一篇说说 Spring 中的事务操作,注解和 XML 配置. Spring 简介 Spring 是一个开源的轻量级的企业 ...
- Spring中基于xml的AOP
1.Aop 全程是Aspect Oriented Programming 即面向切面编程,通过预编译方式和运行期动态代理实现程序功能的同一维护的一种技术.Aop是oop的延续,是软件开发中的 一个热点 ...
- .Net中的RealProxy实现AOP
序言 这个AOP要从我们公司的一个事故说起,前段时间公司的系统突然在乌云中出现,数据被泄露的一览无余,乌云上显示是SQL注入攻击.呵,多么贴近生活的一个露洞,可谓是人尽皆知啊.然而却华丽丽的给拉我们一 ...
- Spring中的IOC\DI\AOP等概念的简单学习
IoC(Inversion of Control,控制反转).这是spring的核心,贯穿始终, 所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系.Spr ...
- Spring AOP报错处理 Can not set field to $Proxy 在spring中使用事物或AOP遇到的错误
[转] 解决方法: http://forum.springsource.org/showthread.php?85016-IllegalArgumentException-with-Applicati ...
- SpringMVC中对Controller使用AOP
转自http://usherlight.iteye.com/blog/1306111 正确配置spring aop,在controller中使用AOP 在controller中使用AOP的问题主要在于 ...
- spring中依赖注入与aop讲解
一.依赖注入 这个属于IOC依赖注入,也叫控制反转,IOC是说类的实例由容器产生,而不是我们用new的方式创建实例,控制端发生了改变所以叫控制反转. 1 2 3 4 5 6 7 8 9 10 11 1 ...
随机推荐
- java中的io系统详解(转)
Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 U ...
- iOS 之 cocoapods安装与使用
我们都知道第三方库,一般使用cocoapods管理,cocoapods在我们IOS开发中有着很大的作用. 好了,现在看下它的安装步骤: 1.打开终端,输入 sudo gem install cocoa ...
- 总结前端JQ常用的一些操作手法(慢慢完善)
1.实例化Js一个object对象,把它当做类来用,事例是操作url的参数 function GetRequestCondition() { var url = window.location.hre ...
- (转) 新手入门:C/C++中的结构体
本文转载于 http://pcedu.pconline.com.cn/empolder/gj/c/0503/567930_all.html#content_page_1 所有程序经过本人验证,部分程序 ...
- android 常用颜色
reference: http://blog.csdn.net/leewenjin/article/details/17386265
- WSGI的理解
Python web开发中,服务端程序可分为2个部分: 服务器程序(用来接收.整理客户端发送的请求) 应用程序(处理服务器程序传递过来的请求) 在开发应用程序的时候,我们会把常用的功能封装起来,成为各 ...
- Jmeter的简单练习
一.安装Jmeter 1.下载Jmeter 下载地址:http://jmeter.apache.org/download_jmeter.cgi 目前最新版为2.9,其余文件如源代码等也可从如下官网下载 ...
- BZOJ 1065 奥运物流
http://www.lydsy.com/JudgeOnline/problem.php?id=1065 思路:由于n个点,有n条边,因此由根就会引出一个环,我们枚举环的长度,在那个长度断开,我们假设 ...
- T-SQL 运算符
运算符 1.算术运算符 算术运算符 说明 + 加法 - 减法 * 乘法 / 除法 % 取模,两个整数相除后的余数 2.位运算符 位运算符 说明 &(与.and) 按位逻辑与运算 |(或.OR) ...
- 【Xamarin挖墙脚系列:代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧(转)】
正愁如何选择构建项目中的视图呢,现在官方推荐画板 Storybord...但是好像 xib貌似更胜一筹.以前的老棒子总喜欢装吊,用代码写....用代码堆一个HTML页面不知道你们尝试过没有.等页面做出 ...