Autofac 之 基于 Castle DynamicProxy2 的 Interceptor 功能

Autofac 结合 Castle DynamicProxy2 功能

 

     Autofac 不仅作为轻量级高效的 IoC 容器,而且还能很好的与 Castle.DynamicProxy2 结合起来,实现 AOP 功能。

     首先,我们需要定义拦截器,简单的定义可实现 Castle.DynamicProxy.IInterceptor 接口即可。

 

添加拦截器

 

     定义好了拦截器后,如何应用到相关对象呢?有两种方式:

     1)使用 Autofac.Extras.DynamicProxy2.InterceptAttribute 特性将拦截器添加到相关的类或接口上;

     2)使用 ContainerBuilder 的 InterceptedBy() 方法在注册对象的同时添加拦截器。

 

     如何启用拦截器呢?我们只需要在 IoC 注册启用即可。启用拦截器有三种方式,其中针对 WCF 比较特别,下面来具体分析这几种方式的应用场景:

 

基于接口的拦截器

 

     在注册对象的同时启用 EnableInterfaceInterceptors() 方法。

     使用接口的拦截器,在使用特性 [Attribute] 注册时,注册拦截器可注册到接口(Interface)上或其实现类(Implement)上。使用注册到接口上方式,所有的实现类都能应用到拦截器。

     对于以接口方式的注入,Autofac Interceptor 要求类的方法为 public 或 virtual 即可。

     

示例代码:

var builder = new ContainerBuilder();

builder.RegisterType<SomeType>()

       .As<ISomeInterface>()

       .EnableInterfaceInterceptors();

builder.Register(c => new CallLogger(Console.Out));

var container = builder.Build();

var willBeIntercepted = container.Resolve<ISomeInterface>();


于类的拦截器

 

     在注册对象的同时启用 EnableClassInterceptors() 方法。

     对于以类方式的注入,Autofac Interceptor 要求类的方法为必须为 virtual 方法。

     值得注意的是:对于 子类,重写(override)父类的虚方法时,能应用到拦截器。父类可在 IoC 中注册也可不需要注册,但子类必须在 IoC 中注册(对于类的拦截器,类都必须要注册,当然,拦截器也必须要注册)。

 

示例代码:

var builder = new ContainerBuilder();
builder.RegisterType<First>().EnableClassInterceptors();
builder.Register(c => new CallLogger(Console.Out));


基于 WCF 的拦截器

 

     WCF 是一种特殊情况。虽然 WCF Proxy 的服务对象也是一种接口,但是使用 EnableInterfaceInterceptors 不会起作用,因为 .NET 实际上是使用了  类似于接口行为的 System.Runtime.Remoting.TransparentProxy 。因此需要这里需要使用  InterceptTransparentProxy() 方法。

 

示例代码:

var cb = new ContainerBuilder();

cb.RegisterType<TestServiceInterceptor>();

cb.Register(c => CreateChannelFactory()).SingleInstance();

cb.Register(c => c.Resolve<ChannelFactory<ITestService>>().CreateChannel())

  .InterceptTransparentProxy(typeof(IClientChannel))

  .InterceptedBy(typeof(TestServiceInterceptor))

  .UseWcfSafeRelease();

实战一下

先看看基于接口的拦截器:

我们先定义一个借口,名为 ICalculater

using Autofac.Extras.DynamicProxy2;


namespace AOP.Interceptors

{

    //[Intercept(typeof(CalculaterInterceptor))]

    public interface ICalculater

    {

        int Add(int x, int y);


        int Sub(int x, int y);

    }

}

然后定义该接口的实现类 Calculater

using Autofac.Extras.DynamicProxy2;


namespace AOP.Interceptors

{

    //[Intercept(typeof(CalculaterInterceptor))]

    public class Calculater : ICalculater

    {

        public int Add(int x, int y)

        {

            return x + y;

        }


        public int Sub(int x, int y)

        {

            return x - y;

        }

    }

}

接下来,我们来定义拦截器。这里我们定义了两个连接器,通过这两个拦截器,我们将能很清晰的看到拦截器是如何工作的。

定义第一个拦截器 CalculaterInterceptor 

using System;

using Castle.DynamicProxy;


namespace AOP.Interceptors

{

    public class CalculaterInterceptor : IInterceptor

    {

        public void Intercept(IInvocation invocation)

        {

            // 在下个拦截器或目前方法处理之前处理

            var args = invocation.Arguments;


            Console.WriteLine($"Before: x={args[0]}, y={args[1]}");

            Console.WriteLine($"Before: Method={invocation.Method.Name}");


            invocation.SetArgumentValue(0, 5);


            // handle

            invocation.Proceed();  // 调用下一个拦截器,直到最终的目标方法。


            // Post

            Console.WriteLine($"After: TargetType={invocation.TargetType}");

            Console.WriteLine($"After: ReturnValue={invocation.ReturnValue}");


            invocation.ReturnValue = (int)invocation.ReturnValue - 2;

        }

    }

}

定义第二个拦截器 CalculaterInterceptor2 :

using System;

using Castle.DynamicProxy;


namespace AOP.Interceptors

{

    public class CalculaterInterceptor2 : IInterceptor

    {

        public void Intercept(IInvocation invocation)

        {

            var args = invocation.Arguments;


            Console.WriteLine($"Before2: x={args[0]}, y={args[1]}");

            Console.WriteLine($"Before2: Method={invocation.Method.Name}");


            invocation.Proceed();


            Console.WriteLine($"After2: TargetType={invocation.TargetType}");

            Console.WriteLine($"After2: ReturnValue={invocation.ReturnValue}");


            invocation.ReturnValue = (int)invocation.ReturnValue - 1;  // 将结果值减去 2

        }

    }

}

在 控制台 Main 函数输入我们的结果:

static void Main(string[] args)

        {

            var builder = new ContainerBuilder();

            builder.RegisterType<Calculater>()

                .As<ICalculater>()

                .EnableInterfaceInterceptors()

                .InterceptedBy(typeof(CalculaterInterceptor), typeof(CalculaterInterceptor2));  // 这里定义了两个拦截器,注意它们的顺序


            builder.RegisterType<CalculaterInterceptor>();  // 注册拦截器

            builder.RegisterType<CalculaterInterceptor2>();  // 注册拦截器2


            var ioc = builder.Build();


            var calculater = ioc.Resolve<ICalculater>();

            var addResult = calculater.Add(2, 3);


            Console.WriteLine($"add result: {addResult}");


            Console.WriteLine("-------------------");

            Console.ReadLine();

        }

我们看看输出结果:

 

这里我们可以看出,执行顺序为 CalculaterInterceptor  --> CalculaterInterceptor2 --> Target Method --> CalculaterInterceptor2 --> CalculaterInterceptor。拦截器中 invocation.Proceed() 方法用于调用下一个拦截器(若存在),直到最终的目标方法(Target Method)。不过 invocation.Proceed() 并不是一定要调用的,例如,对于有返回值的目标方法,我们在拦截器中设置 invocation.ReturnValue 值就可正确执行,这样便不会执行目标方法。在有些场景中,如身份验证、缓存读取等还是特别有用的。

当然,在 Main() 方法中 Ioc 注册 Caliculater 类型时我们注册了两个拦截器,".InterceptedBy(typeof(CalculaterInterceptor), typeof(CalculaterInterceptor2))"。我们也可以直接在 Calculater 类型 或 ICalculater 接口上以特性的形式注册,如上面代码中注释掉的那部分。若是既有在类型上注册,也有在 Autofac 的 Builder 中注册,那么这个拦截器会重复执行。

 

基于类的拦截器:

我们定义两个类 Flight 和其 子类 FlightOfSH:

public class Flight

    {

        public virtual void Fly(DateTime time)

        {

            Console.WriteLine($"Flight: {time}");

        }

    }



public class FlightOfSH : Flight

    {

        public override void Fly(DateTime time)

        {

            Console.WriteLine($"FlightOfSH: Fly={time}");

        }


        public void Arrive(DateTime time)

        {

            Console.WriteLine($"FlightOfSH: Arrive={time}");

        }

    }

这两个类的拦截器:


internal class FlightInterceptor : IInterceptor

    {

        public void Intercept(IInvocation invocation)

        {

            Console.WriteLine("Before Fly");


            invocation.Proceed();


            Console.WriteLine("After Fly");

        }

    }

在 Main 函数中定义代码:


var builder = new ContainerBuilder();


            builder.RegisterType<Flight>()

               .EnableClassInterceptors().InterceptedBy(typeof(FlightInterceptor));

            builder.RegisterType<FlightOfSH>()

                .EnableClassInterceptors().InterceptedBy(typeof(FlightInterceptor));


            builder.RegisterType<FlightInterceptor>();


            var ioc = builder.Build();


            var flight = ioc.Resolve<Flight>();

            flight.Fly(DateTime.Now);


            var flightOfSH = ioc.Resolve<FlightOfSH>();

            flightOfSH.Fly(DateTime.Now);

            flightOfSH.Arrive(DateTime.Now);


我们看看输出结果:

 

 

从输出结果中可以发现一个有趣的现在, 子类 FlightOfSH 重写了 Flight 的 Fly 方法,却也调用才拦截器。Arrive() 方法因为是非虚方法,所有拦截器不会在该方法中调用。

当然,我们这里都是直接在 Autofac 的 Ioc 注册类型时设定的,也可以同上面一样使用 InterceptAttribute 特性来注入。

对于基于 WCF 的拦截器,大家可以自己试验下。

 

总结

这里简单的介绍了 Autofac 与 Castle 动态代理功能结合来实现 AOP 功能,当然,Castle 本身也是个很强大的开源框架,也有很强大的 IoC 功能,不过我还是比较喜欢 Autofac 的 IoC 功能。

相关文章:

  • 使用 Autofac 进行依赖注入

  • ASP.NET Core依赖注入解读&使用Autofac替代实现


原文链接:http://www.cnblogs.com/god--love-you/p/5699632.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

类和对象运行时在内存里是怎么样的?各种变量、方法在运行时是怎么交互的?

转载自 类和对象运行时在内存里是怎么样的&#xff1f;各种变量、方法在运行时是怎么交互的&#xff1f;在回答这个问题之前先了解一下Java的一些基础知识。我们知道Java程序运行在虚拟机环境里&#xff0c;那我们先看一下虚拟机的大致内存结构。如下图所示&#xff0c;虚线框…

java通过commons-fileupload实现多张图片的上传(jsp页面)

<div id"middle"><div id"form"><form action"ProductInfoServlet?tagadd" method"post" enctype"multipart/form-data" ><h2>三只松鼠--新增</h2><table align"center">&l…

系统架构师7

2017年11月11日 软件系统架构师考试经验分享 置顶 2017年11月13日 15:25:53 凌飞安 阅读数 7812 版权声明&#xff1a;原创作品&#xff0c;转载请注明出处&#xff01;个人主页 http://www.lingfeian.com https://blog.csdn.net/lingfeian/article/details/78520808 系统架构…

工业利用计算机实现生产自动化属于,自动化考试试题(含答案)

第一类&#xff1a;填空题一&#xff0e;填空题1&#xff0e;自动化控制系统按被控量的时间特性分为(连续量)和(离散量)。2&#xff0e;PLC 全称为(可编程序逻辑控制器)&#xff0c;DCS全称为( 集散控制系统)。3&#xff0e;输入输出单元是(PLC)与工业过程控制现场之间的连接部…

保定有国家承认的计算机学校吗,河北省122所大学名单,不在名单内的都是国家不承认的野鸡学校...

原标题&#xff1a;河北省122所大学名单&#xff0c;不在名单内的都是国家不承认的野鸡学校据教育部官网信息显示&#xff0c;截至2019年6月15日&#xff0c;河北省共有普通高等学校122所&#xff0c;其中本科院校61所&#xff0c;专科院校61所。在名单中虽然有一所211院校&…

从Java类到对象的创建过程都做了些啥?内存中的对象是啥样的?

转载自 从Java类到对象的创建过程都做了些啥&#xff1f;内存中的对象是啥样的&#xff1f;先回顾一下Java程序执行的过程&#xff1a;Java程序执行时&#xff0c;第一步系统创建虚拟机进程&#xff0c;然后虚拟器用类加载器Class Loader加载java程序类文件到方法区。方法区放…

ASP.NET Core MVC TagHelper实践HighchartsNET快速图表控件

ASP.NET Core MVC TagHelper最佳实践HighchartsNET快速图表控件支持ASP.NET Core。 曾经在WebForms上写过 HighchartsNET快速图表控件-开源 Highcharts的ASP.NET Web自定义控件。 今天我就来改造它&#xff0c;将其使用最新的TagHelper 来实践&#xff0c;学习TagHelper 的使用…

架构师6

系统架构师考试总结 2019年06月11日 10:48:47 devillyd2018 阅读数 103 2011年11月12日&#xff0c;在这个百年一遇的大单身节的第二天&#xff0c;我怀着无比紧张的心情走进了系统架构师的考场。 虽然暂时还不知道我的成绩&#xff0c;无所谓啦&#xff0c;虽然答的一般&…

计算机视觉论文doc,嘉炬-计算机视觉论文资料.doc

成 绩评卷人姓 名嘉炬学 号华 中 师 范 大 学研 究 生 课 程 论 文论文题目 计算机视觉技术在教育领域的应用完成时间 2015年1月15日课程名称 计算机视觉专 业 通信与信息系统年 级 2014级注&#xff1a;研究生须在规定期限内完成课程论文&#xff0c;并用A4页面打印&#xff0…

Oracle数据库基本概念理解(1)

--函数 数字转换为字符 --0 强制位数&#xff0c;9位数不够不显示 $美元 SELECT TO_CHAR(124.3456,0000.00) FROM dual ; SELECT TO_CHAR(124.3456,9999.99) FROM dual ; SELECT TO_CHAR(124.3456,$9999.99) FROM dual ; --日期 日期转换为字符 SELECT TO_CHAR(SYSDATE,YY…

关于Heap Dump

转载自 关于Heap DumpHeap Dump是什么&#xff1f; Heap Dump也叫堆转储文件&#xff0c;是一个Java进程在某个时间点上的内存快照。Heap Dump是有着多种类型的。不过总体上heap dump在触发快照的时候都保存了java对象和类的信息。通常在写heap dump文件前会触发一次FullGC&a…

使用StyleCop 进行代码评审

使用StyleCop对原代码进行审查&#xff0c;看编写的代码是否遵循设计规范、.Net约定和一些贯用法等。保证代码的一致性&#xff0c;可读性等等。 在此之前&#xff0c;先简单介绍下FxCop&#xff08;起初只是微软内部使用的工具&#xff09;,一个分析托管程序集&#xff0c;检测…

系统架构师5 ***********那就给个合格分了。111

https://download.csdn.net/download/sun_lq/11109495 https://download.csdn.net/download/u011669055/10736374 https://download.csdn.net/download/robertsoft/10747039 十年IT从业背景&#xff0c;一次考试通过系统分析师(通过系统分析师的学习 ... [复制链接] 发表于 …

2012三年大专计算机试题医学,计算机原理2012年4月真题(02384)

计算机原理2012年4月真题及答案解析(02384)计算机原理2012年4月真题及答案解析(02384)&#xff0c;该试卷为计算机原理自考历年真题试卷&#xff0c;包含答案及详细解析。一、单项选择题(本大题共15小题&#xff0c;每小题2分&#xff0c;共30分)在每小题列出的四个备选项中只有…

JVM内存管理------JAVA语言的内存管理概述

转载自 JVM内存管理------JAVA语言的内存管理概述引言 内存管理一直是JAVA语言自豪与骄傲的资本&#xff0c;它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节&#xff0c;只专注于业务逻辑。不过世界上不存在十全十美的好事&#xff0c;在带来了便利的同时&#xf…

微软市值今天涨了 250 亿,这家离我们越来越远的公司,为什么生意反倒越来越好了?

纳德拉上台两年半&#xff0c;微软市值已经涨了 50% 今天早上&#xff0c;微软发布了今年第三季度的财报。受云计算和 Office 业务推动&#xff0c;财报后的盘后交易里&#xff0c;微软股价上涨 5.9%、市值涨了超过 250 亿美元——收购 LinkedIn 的钱差不多就回来了。 财报发布…

系统架构设计师考试 重要的部分

系统架构师考试比较的难&#xff0c;属于软件工程师考试中的高级考试&#xff0c;有选择题&#xff0c;分析题&#xff0c;论文&#xff0c;请坚持。 这是高产似母猪啊。 1.每天2小时&#xff0c;坚持了4年考过了软件设计师&#xff0c;系统架构师&#xff0c; 四年时间花了大…

计算机文化基础分析总结,《计算机文化基础实训》教学方案设计与课题分析总结.doc...

《计算机文化基础实训》教学方案设计与课题分析总结.doc《计算机文化基础一实训》教学方案设计与课题分析总结袁良风&#xff3b; 】我院自开展木课题研宄工作以来&#xff0c;紧紧围绕“项目教学法”教学的应 用问题&#xff0c;积极主动地开展专题研究和教改实验&#xff0c;…

Oracle数据库基本概念理解(2)

--删除用户 drop user sz cascade; --创建表空间 create tablespace worktablsp datafile C:\app\lenovo\oradata\orcl\EMPTB.dbf SIZE 5MAUTOEXTEND ON; --修改表空间 ALTER tablespace worktablsp ADD datafile C:\app\lenovo\oradata\orcl\EMPTB.dbf SIZE 5M;--扩展数据文件…

Java中关于String类型的10个问题

转载自 Java中关于String类型的10个问题1. 如何比较两个字符串&#xff1f;用“”还是equals 简单来说&#xff0c;“”是用来检测俩引用是不是指向内存中的同一个对象&#xff0c;而equals()方法则检测的是两个对象的值是否相等。只要你想检测俩字符串是不是相等的&#xff…