C#使用Autofac实现控制反转IoC和面向切面编程AOP
Autofac是一个.net下非常优秀,性能非常好的IOC容器(.net下效率最高的容器),加上AOP简直是如虎添翼。Autofac的AOP是通过Castle(也是一个容器)项目的核心部分实现的,名为Autofac.Extras.DynamicProxy,顾名思义,其实现方式为动态代理。
使用方式比较简单,先新建一个控制台项目,然后在Nuget上搜索Autofac.Aop并安装,如下顺序:

或者通过命令安装:
Install-Package Autofac.Aop
安装成功之后会项目会增加几个个引用,如下图:

1. 创建拦截器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//先在Nuget上搜索Autofac.Aop安装
using Castle.DynamicProxy; namespace AutofacDEMO
{
/// <summary>
/// 拦截器 需要实现 IInterceptor接口 Intercept方法
/// </summary>
public class LogInterceptor : IInterceptor
{
/// <summary>
/// 拦截方法 打印被拦截的方法执行前的名称、参数和方法执行后的 返回结果
/// </summary>
/// <param name="invocation">包含被拦截方法的信息</param>
public void Intercept(IInvocation invocation)
{
Console.WriteLine("方法执行前:拦截{0}类下的方法{1}的参数是{2}",
invocation.InvocationTarget.GetType(),
invocation.Method.Name, string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray())); //在被拦截的方法执行完毕后 继续执行
invocation.Proceed(); Console.WriteLine("方法执行完毕,返回结果:{0}", invocation.ReturnValue);
Console.WriteLine();
}
}
}
2. 创建拦截容器
var builder = new ContainerBuilder();
3. 注册拦截器到Autofac容器
拦截器必须注册到Aufofac容器中,可以通过拦截器类型或者命名注入,这两种方式会让使用拦截器的方法有所不同
// 命名注入
builder.Register(c => new LogInterceptor()).Named<IInterceptor>("log-calls"); //类型注入
builder.Register(c => new LogInterceptor());
//或者
builder.RegisterType<LogInterceptor>();
4. 启用拦截器
启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors()。
EnableInterfaceInterceptors方法会动态创建一个接口代理
EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法
注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法
//启用类代理拦截
//方式一:给类型上加特性Attribute
builder.RegisterType<Student>().EnableClassInterceptors();
//方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
builder.RegisterType<Teacher>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();
//启用接口代理拦截
//方式一:给类型上加特性Attribute
builder.RegisterType<Man>().As<IPerson>().EnableInterfaceInterceptors();
//方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
builder.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors();
5. 指明要拦截的类型
有两种方法:
第一种:给类型加上特性Attribute

第二种:在注册类型到容器的时候动态注入拦截器
//动态注入拦截器
builder.RegisterType<Student>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();
6. 测试效果如下
第一种:类代理拦截
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autofac.Extras.DynamicProxy2; namespace AutofacDEMO
{
/// <summary>
/// 继承接口,并实现方法,给类型加上特性Attribute
/// </summary>
[Intercept(typeof(LogInterceptor))]
public class Student
{
public string Name; public Teacher Teacher; public Subject Subject; /// <summary>
/// 必须是虚方法
/// </summary>
public virtual void Say()
{
Console.WriteLine("你正在调用Say方法!学生姓名:" + Name);
}
} [Intercept(typeof(LogInterceptor))]
public class Teacher
{
/// <summary>
/// 必须是虚方法
/// </summary>
public virtual void Show()
{
Console.WriteLine("I am Teacher's class !");
}
} public class Subject
{
/// <summary>
/// 必须是虚方法
/// </summary>
public virtual void Show()
{
Console.WriteLine("I am Subject's class !" );
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extras.DynamicProxy2; namespace AutofacDEMO
{
class Program
{
static void Main(string[] args)
{
//启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors()
//EnableInterfaceInterceptors方法会动态创建一个接口代理
//EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法
//注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法
#region 启用类代理拦截
//创建拦截容器
var builder = new ContainerBuilder();
//注册拦截器到容器
builder.RegisterType<LogInterceptor>();
//方式一:给类型上加特性Attribute
builder.RegisterType<Student>().EnableClassInterceptors();
builder.RegisterType<Teacher>().EnableClassInterceptors();
//方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
//builder.RegisterType<Teacher>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();
//builder.RegisterType<Student>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();
//属性注入
builder.Register(c => new Student { Teacher = c.Resolve<Teacher>(), Subject = new Subject(), Name = "张三" });
using (var container = builder.Build())
{
//从容器获取对象
var Student = container.Resolve<Student>();
Student.Say();
Student.Subject.Show();
Student.Teacher.Show();
}
Console.ReadLine();
#endregion
}
}
}

第二种:接口代理拦截
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace AutofacDEMO
{
/// <summary>
/// 定义一个接口
/// </summary>
public interface IPerson
{
void Say(string Name);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autofac.Extras.DynamicProxy2; namespace AutofacDEMO
{
/// <summary>
/// 继承接口,并实现方法,给类型加上特性Attribute
/// </summary>
[Intercept(typeof(LogInterceptor))]
public class Man: IPerson
{
public string Age; public void Say(string Name)
{
Console.WriteLine("男人调用Say方法!姓名:" + Name + ",年龄:" + Age);
}
} /// <summary>
/// 继承接口,并实现方法,给类型加上特性Attribute
/// </summary>
[Intercept(typeof(LogInterceptor))]
public class Woman : IPerson
{
public void Say(string Name)
{
Console.WriteLine("女人调用Say方法!姓名:" + Name);
}
} /// <summary>
/// 管理类
/// </summary>
public class PersonManager
{
IPerson _Person; /// <summary>
/// 根据传入的类型动态创建对象
/// </summary>
/// <param name="ds"></param>
public PersonManager(IPerson Person)
{
_Person = Person;
} public void Say(string Name)
{
_Person.Say(Name);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extras.DynamicProxy2; namespace AutofacDEMO
{
class Program
{
static void Main(string[] args)
{
//启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors()
//EnableInterfaceInterceptors方法会动态创建一个接口代理
//EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法
//注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法
#region 启用接口代理拦截(推荐用这种方式)
//创建拦截容器
var builder2 = new ContainerBuilder();
//注册拦截器到容器
builder2.RegisterType<LogInterceptor>();
//构造函数注入(只要调用者传入实现该接口的对象,就实现了对象创建,下面两种方式)
builder2.RegisterType<PersonManager>();
//方式一:给类型上加特性Attribute
//属性注入
builder2.Register<Man>(c => new Man { Age = "" }).As<IPerson>().EnableInterfaceInterceptors();
//builder2.RegisterType<Man>().As<IPerson>().EnableInterfaceInterceptors();
builder2.RegisterType<Woman>().Named<IPerson>("Woman").EnableInterfaceInterceptors();
//方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
//builder2.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors();
//builder2.RegisterType<Woman>().Named<IPerson>("Woman").InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors();
using (var container = builder2.Build())
{
//从容器获取对象
var Manager = container.Resolve<PersonManager>();
Manager.Say("管理员");
var Person = container.Resolve<IPerson>();
Person.Say("张三");
var Woman = container.ResolveNamed<IPerson>("Woman");
Woman.Say("王萌");
}
Console.ReadLine();
#endregion
}
}
}

Autofac三种生命周期:InstancePerLifetimeScope、SingleInstance、InstancePerDependency
InstancePerLifetimeScope:同一个Lifetime生成的对象是同一个实例
SingleInstance:单例模式,每次调用,都会使用同一个实例化的对象;每次都用同一个对象;
InstancePerDependency:默认模式,每次调用,都会重新实例化对象;每次请求都创建一个新的对象
//方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
builder.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).InstancePerLifetimeScope().EnableInterfaceInterceptors();
看下面运行结果图
1、InstancePerLifetimeScope

2、SingleInstance

3、InstancePerDependency

AsImplementedInterfaces() 是以接口方式进行注入,注入这些类的所有的公共接口作为服务(除了释放资源)
builder.RegisterAssemblyTypes 注册程序集中符合条件的类型
Assembly assembly = Assembly.Load(assemblyName);
//Assembly assembly = this.GetType().GetTypeInfo().Assembly;
builder.RegisterAssemblyTypes(assembly).Where(type => !type.IsInterface && !type.IsSealed && !type.IsAbstract
&& type.Name.EndsWith("BLL", StringComparison.OrdinalIgnoreCase))
.AsImplementedInterfaces()
.InstancePerLifetimeScope()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(LogInterceptor));
每个RegisterAssemblyTypes()调用将仅应用一组规则 - 如果要注册多个不同组的组件,则需要多次调用RegisterAssemblyTypes()
C#使用Autofac实现控制反转IoC和面向切面编程AOP的更多相关文章
- Spring之控制反转——IoC、面向切面编程——AOP
控制反转——IoC 提出IoC的目的 为了解决对象之间的耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦. 什么是IoC IoC是Inversion of Control的缩写,译为控制 ...
- 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制
spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...
- Spring框架使用(控制反转,依赖注入,面向切面AOP)
参见:http://blog.csdn.net/fei641327936/article/details/52015121 Mybatis: 实现IOC的轻量级的一个Bean的容器 Inversion ...
- 程序员笔记|Spring IoC、面向切面编程、事务管理等Spring基本概念详解
一.Spring IoC 1.1 重要概念 1)控制反转(Inversion of control) 控制反转是一种通过描述(在java中通过xml或者注解)并通过第三方去产生或获取特定对象的方式. ...
- Spring框架系列(3) - 深入浅出Spring核心之控制反转(IOC)
在Spring基础 - Spring简单例子引入Spring的核心中向你展示了IoC的基础含义,同时以此发散了一些IoC相关知识点; 本节将在此基础上进一步解读IOC的含义以及IOC的使用方式.@pd ...
- ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下
先简单了解一这个几个 名词的意思. 控制反转(IOC) 依赖注入(DI) 并不是某种技术. 而是一种思想.一种面向对象编程法则 什么是控制反转(IOC)? 什么是依赖注入(DI) 可以点击下面链接 ...
- ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下
ADO.NET 一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data → DataTable, ...
- C#依赖注入控制反转IOC实现详解
原文:C#依赖注入控制反转IOC实现详解 IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些联系在一起. ...
- 控制反转IoC简介
控制反转IoC简介 在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度.通常的业务对象之间都是互相依赖的,业务对象与业务对象.业务对象与持久层.业务对象与各种资源之间都存在这样或 ...
随机推荐
- error: 'for' loop initial declaration used outside C99 mode的解决方法
for(int i = 0;i<10;i++)这样写循环时可能会出现如题编译错误,解决方法有两种,如下:1 将文件后缀名由".c"改为".cpp"2 in ...
- java基础之 clone
参考文档:深拷贝&浅拷贝:http://blog.csdn.net/cws1214/article/details/52193341 克隆的分类: (1)浅克隆(shallow clone) ...
- 2018-2019-2 20175217 实验四《Android开发基础》实验报告
一.实验报告封面 课程:Java程序设计 班级:1752班 姓名:吴一凡 学号:20175217 指导教师:娄嘉鹏 实验日期:2019年5月16日 实验时间:--- 实验序号:实验四 实验名称:And ...
- C# RSA 无 长度限制 加密解密 示例
RSA 是一种非对称加密算法.由于算法特性,加密和解密过程用不同密钥,即公钥和私钥,而被广泛应用于数字证书的安全管理. 在具体应用中,公钥用加密而私钥用于解密,或 私钥用于数字签名而公钥用于签名验证. ...
- Xamarin.FormsShell基础教程(3)Shell项目构成
Xamarin.FormsShell基础教程(3)Shell项目构成 在创建的ShellDemo解决方案中,有3个子项目,分别为ShellDemo.ShellDemo.Android和ShellDem ...
- JavaScript 工厂模式
//工厂 function FruitMaker() { //function 后不带方法名,这里cococola未定义,make return时,返回 FruitMaker.cococola thi ...
- Linux远程连接ssh工具(FinalShell)xshell替代神器
对对对 FinalShell SSH工具,服务器管理,远程桌面加速软件,支持Windows,macOS,Linux,版本2.9.8,更新时间2019.6.19 wntr 2017-01-17 11:0 ...
- LeetCode 104. Maximum Depth of Binary Tree(二叉树深度)
Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...
- JavaScript 图片与Base64数据互相转换脚本
JavaScript 图片与Base64数据互相转换脚本 注: 转换过程中注意跨域问题.测试页是否支持相关标签创建.dom结构. 方法一:非Html 5使用FileReader 使用XMLHttpRe ...
- PHP $$符号的作用与使用方法
php中$$符号的定义与作用 在PHP中单个美元符号变量($str),表示一个名为str的普通变量,它可以存储字符串.整数.数组.布尔等任何类型的值. 双美元符号的变量($$str):表示一个可变变量 ...