本节学习利用第三方框架Autofac来增强容器能力,并引入面向切面(AOP)编程的概念。
那么,先来了解一下
什么时候需要引入第三方容器组件呢?
- 基于名称的注入
- 属性注入
- 子容器
- 基于动态代理的AOP
核心扩展点
public interface IServiceProviderFactory<TContainerBuilder>
第三方的扩展框架都是基于这个接口做扩展的
Autofac扩展包
- Autofac.Extensions.DependencyInjection
- Autofac.Extras.DynamicProxy
下面,我们就通过代码来演示如何使用Autofac以及使用Autofac来实现上述几种情况。
代码演示
首先说一下,代码架构,这里主要是定义了一个接口,然后定义了2个实现该接口的类,其中第二个类包含一个属性,用于验证属性注入。类的代码如下
public interface IMyService { void show(); } public class MyService : IMyService { public void show() { Console.WriteLine($"this is MyService.show,{GetHashCode()}"); } } public class MyServiceV2 : IMyService { public MyNameService myNameService { get; set; } public void show() { Console.WriteLine($"this is MyServiceV2.show,{GetHashCode()},MyNameService是否为空:{myNameService==null}"); } } public class MyNameService { }
Autofac使用步骤
1.注册第三方组件入口
在使用第三方组件时,我们需要先通过配置来启用第三方组件,如下,我们在CreateHostBuilder中添加如下语句。
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
2.服务注册入口
组件入口注册后,我们需要定义第三方组件自己的服务注册入口,我们可以在startup里新增一个ConfigureContainer方法来实现,方法入参是Autofac.ContainerBuilder,其实,这里我们的服务注册进默认的容器后,会被Autofac接替,然后执行ConfigureContainer.
public void ConfigureContainer(ContainerBuilder containerBuilder) { //... }
3.接收Autofac的容器
之后,我们需要创建一个作用域,用于在根容器内接收Autofac的容器对象。
public ILifetimeScope AutofacContainer { get; private set; }
//根容器获取 this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
到这里,我们就完成了所有的准备步骤,可以开始上述几种场景的演示了。
常规注入
在这之前,我们先了解一下常规注入方式以及获取方式,这里注意一下,Autofac的注入方式是先注入服务在指定其类型。如下
//常规注册 containerBuilder.RegisterType<MyService>();//未指定类型,通过IMyService不能获取 containerBuilder.RegisterType<MyService>().As<IMyService>(); containerBuilder.RegisterType<MyServiceV2>().As<IMyService>();
获取方式如下
var service = this.AutofacContainer.Resolve<IMyService>();
Autofac的服务获取方式是一组以Resolve...开头的方法,比如,下面要说的命名服务的获取方式可通过ResolveNamed方法获取。
基于名称的注入及获取
//注册 containerBuilder.RegisterType<MyService>().Named<IMyService>("myService");
//获取 IMyService myService = this.AutofacContainer.ResolveNamed<IMyService>("myService");
属性注入
属性注通过PropertiesAutowired来开启属性注入,在属性注入前要先注册要注入的服务
//注入要注入的服务 containerBuilder.RegisterType<MyNameService>(); //开启属性注入 containerBuilder.RegisterType<MyServiceV2>().As<IMyService>().PropertiesAutowired();
AOP编程
Autofac提供了一个IInterceptor的接口,用于提供AOP的能力,我们可以通过实现该接口,将一些特定的逻辑嵌入到方法的切面中,并控制是否执行原有代码逻辑,一般,我们称该类为拦截器,如下,是一个拦截器示例
public class Interceptor : IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine($"{invocation.Method.Name}执行前"); //不调用该方法,可禁用原有逻辑 invocation.Proceed(); Console.WriteLine($"{invocation.Method.Name}执行后"); } }
那么,如何开启拦截器呢?主要有以下几步
- 注入拦截器
- 通过InterceptedBy来定义允许的类型
- 开启拦截器开关,分为类拦截器和接口拦截器(常用)
代码如下:
//注入拦截器 containerBuilder.RegisterType<Interceptor>(); //定义允许的类型并开启拦截器 containerBuilder.RegisterType<MyService>().As<IMyService>().InterceptedBy(typeof(Interceptor)).EnableInterfaceInterceptors();
子容器
我们知道,通过Scope可以创建子容器,在Autofac中,可以通过InstancePerMatchingLifetimeScope来创建特定名称的子容器,一般使用在期望某一服务不在根容器创建,但又希望它在一定的范围内是单例的情况下。
containerBuilder.RegisterType<MyServiceV2>().InstancePerMatchingLifetimeScope("myscope");
也可以通过如下代码来验证容器是否是单例
using (var myscope = AutofacContainer.BeginLifetimeScope("myscope")) { var service0 = myscope.Resolve<MyServiceV2>(); using (var scope = myscope.BeginLifetimeScope()) { var service1 = myscope.Resolve<MyServiceV2>(); var service2 = myscope.Resolve<MyServiceV2>(); Console.WriteLine($"service1==service2?{service1 == service2}"); Console.WriteLine($"service0==service1?{service0 == service1}"); } }
本节到此就要结束了,从下节将开始配置框架的学习。
源码可访问
https://github.com/IronMarmot/Samples/tree/master/CoreSamples