1、什么是Autofac

**Autofac 是一个流行的开源的 .NET IoC(Inversion of Control)容器,用于实现依赖注入(DI)和控制反转(IoC)模式。**它是一个轻量级、灵活且功能强大的库,用于管理 .NET 应用程序中的对象和它们之间的依赖关系。

**Autofac 提供了丰富的特性,包括构造函数注入、属性注入、生命周期管理、模块化组件注册等,**使得它成为 .NET 应用程序中依赖注入的首选解决方案之一。

2、向容器注册
2.1 RegisterType

给定类和对应的接口

container.RegisterType<EmailTest>().As<IEmailTest>();
  • 1.

或给定类,由Autofac自动查找对应的接口

container.RegisterType<EmailTest>().AsImplementedInterfaces();
  • 1.

调用

public DefaultConsulProviderService(IHttpContextAccessor httpContextAccessor, IEmailTest emailTest)
{
    this.httpContextAccessor = httpContextAccessor;
    this.emailTest = emailTest;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

由RegisterType仅注册类型,不注册接口

container.RegisterType<EmailTest>();
  • 1.
2.2 RegisterInstance
container.RegisterInstance(new EmailTest()).As<IEmailTest>();  //注入IEmailTest
  • 1.

container.RegisterInstance(new EmailTest());     //注入EmailTest
  • 1.
2.3 RegisterAssemblyTypes

注册其他层

containerBuilder.RegisterAssemblyTypes(Assembly.Load("Hotel.Repositories")).AsImplementedInterfaces()
  • 1.

注册控制器

containerBuilder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).PropertiesAutowired();
  • 1.
2.4 RegisterGeneric
containerBuilder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerDependency();
  • 1.
2.5 RegisterModule

(1)先定义模块类,继承自Autofac.Module,并重写基类的Load方法

public class AutoFacModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            //这里写正常的注册代码
            builder.RegisterType<EmailTest>().As<IEmailTest>();
            base.Load(builder);
        }
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

(2)在Program.cs里进行注册

container.RegisterModule<AutoFacModule>();
  • 1.
3 属性注入

属性注入需要用到PropertiesAutowired()方法,注意这个方法用在要进行注入属性的类型或程序集上,比如要在A类中注入public Ixxx xxx{get;set;}接口,就在A类向容器注册的时候添加PropertiesAutowired()方法。

3.1 在普通类中进行属性注入

如下代码,在DefaultConsulProviderService.cs中添加属性注入IEmailTest,核心代码如下:

Program.cs

builder.Host.ConfigureContainer<ContainerBuilder>((context, container) => {    
//只此一行即可实现Employees.Application层的DefaultConsulProviderService中属性注入
container.RegisterAssemblyTypes(Assembly.Load("Employees.Application")).AsImplementedInterfaces().PropertiesAutowired();
});
  • 1.
  • 2.
  • 3.
  • 4.

DefaultConsulProviderService.cs

public class DefaultConsulProviderService : IDefaultConsulProviderService
{
    private readonly IHttpContextAccessor httpContextAccessor;
    
    //这里进行属性注入
    public IEmailTest emailTest { get; set; }

    public DefaultConsulProviderService(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }

    public void GetLog()
    {
        emailTest.Send();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

入口点ValuesController.cs,控制器本身支持构造函数注入,不需要特殊处理

public class ValuesController : ControllerBase
{
    private readonly IDefaultConsulProviderService defaultConsulProviderService;

    public ValuesController(IDefaultConsulProviderService defaultConsulProviderService)
    {
        this.defaultConsulProviderService = defaultConsulProviderService;
    }

    [HttpGet]
    public IActionResult Test()
    {
        defaultConsulProviderService.GetLog();
        return Ok();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
3.2 在控制器中实现属性注入

控制器要实现属性注入,需要以下两点:

(1)向Autofac容器注入启动项的程序集,并添加PropertiesAutowired();

container.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).PropertiesAutowired();
  • 1.

(2)向Autofac注册IControllerActivator接口及实现类ServiceBasedControllerActivator

container.RegisterType<ServiceBasedControllerActivator>().As<IControllerActivator>();
  • 1.

或者采用替换方法

builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
  • 1.

(3)向容器注册要注入的属性接口

container.RegisterType<EmailTest>().As<IEmailTest>(); //或者程序集注册,总之要向容器注册
  • 1.

Program.cs中的核心代码:

builder.Host.ConfigureContainer<ContainerBuilder>((context, container) => {
    container.RegisterType<EmailTest>().As<IEmailTest>();
    container.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).PropertiesAutowired();
    container.RegisterType<ServiceBasedControllerActivator>().As<IControllerActivator>();
});
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

控制器代码:

public class ValuesController : ControllerBase
{
    public IEmailTest  emailTest { get; set; }
    [HttpGet]
    public IActionResult Test()
    {
        emailTest.Send();
        return Ok();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
3.3 动态WebApi接口IDynamicWebApi的属性注入
builder.Host.ConfigureContainer<ContainerBuilder>((context, container) => {   
    container.RegisterAssemblyTypes(typeof(Program).Assembly).PropertiesAutowired();
    container.RegisterType<ServiceBasedControllerActivator>().As<IControllerActivator>();
    container.RegisterType<EmailTest>().As<IEmailTest>();
    container.RegisterType<DefaultConsulProviderService>().PropertiesAutowired();
});
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

总结:

1、要在哪个类中使用属性注入(进行属性注入),就将这个类注册,并添加PropertiesAutowired()方法

2、保证属性注入对应的接口也在容器中注册

4 AOP实现
4.1 什么是AOP 呢?

AOP全称Aspect Oriented Programming意为面向切面编程,也叫做面向方法编程,是通过预编译方式和运行期动态代理的方式实现不修改源代码的情况下给程序动态统一添加功能的技术。

AOP技术利用一种称为“横切”的技术,剖解开封装对象的内部,将影响多个类的公共行为封装到一个可重用的模块中,并将其命名为Aspect切面。所谓的切面,简单来说就是与业务无关,却为业务模块所共同调用的逻辑,将其封装起来便于减少系统的重复代码,降低模块的耦合度,有利用未来的可操作性和可维护性。

利用AOP可以对业务逻辑各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。

AOP的使用场景主要包括日志记录、性能统计、安全控制、事务处理、异常处理等。


图片来源: https://www.cnblogs.com/chenwolong/p/filter.html

4.2基于Autofac的AOP实现

(1)安装Autofac.Extras.DynamicProxy

<PackageReference Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
  • 1.

(2)定义拦截器

public class LogInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        invocation.Proceed();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

(3)全局启用拦截器

核心代码:

builder.Host.ConfigureContainer<ContainerBuilder>((context, container) => {
    //向容器注册拦截器
    container.RegisterType<LogInterceptor>();
    container.RegisterAssemblyTypes(Assembly.Load("Employees.Application")).AsImplementedInterfaces()
    //启用拦截器
    .EnableInterfaceInterceptors().InterceptedBy(typeof (LogInterceptor));
    container.RegisterAssemblyTypes(typeof(Program).Assembly).PropertiesAutowired();
    container.RegisterType<ServiceBasedControllerActivator>().As<IControllerActivator>();
    container.RegisterType<DefaultConsulProviderService>().PropertiesAutowired();
});
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

(4)也可以局部注册拦截器,不需要在Program中进行配置,只在要启用拦截器的类上增加 [Intercept(typeof(LogInterceptor))]特性即可。

[Intercept(typeof(LogInterceptor))]
    public class LogService : ILogService
    {
        public string GetGuid()
        {
            return Guid.NewGuid().ToString();
        }
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
5、 Autofac和.net core自带容器有什么区别?

Autofac 是一个第三方依赖注入容器,支持属性注入、支持程序集方式、模块方式注册,通过安装Autofac.Extras.DynamicProxy包,可以实现AOP功能。

.net core自带的容器不支持属性注入和程序集方式的注册;