asp.net core 3.1和 .Net 5.0中使用AutoFac作为IoC容器组件

2021/7/10 14:45:54

本文主要是介绍asp.net core 3.1和 .Net 5.0中使用AutoFac作为IoC容器组件,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、为啥要使用第3方依赖注入框架 ?

1、微软官方提供的依赖注入框架已经很强大,一般情况无需第3方DI容器;

2、但是在一些特殊情况,需要第3方DI容器增强依赖注入功能,一般有如下几种情况:

(1) 基于名称的注入,基于Key的注入

    比如一个解决方案(一个webapi项目)同时作为多个MQ的消费者
(2)  属性注入
(3) 子容器
(4) 基于动态代理的 AOP

(5)整个应用程序级的生命周期;

二、普通的使用方法:

1、Nuget添加组件:Autofac.Extensions.DependencyInjection

2、Program里添加AutoFac:

UseServiceProviderFactory(new AutofacServiceProviderFactory())

using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

3、StartUp里添加一个方法

public void ConfigureContainer(ContainerBuilder builder)

4、与微软自带的几个常用的用法:

 public void ConfigureContainer(ContainerBuilder builder)
        {
            #region //1简单的使用--- 与默认DI容器相同的功能
                       //生命周期:默认,也就是瞬时模式==AddTransient
            // services.AddScoped<IStudent, Student>();  --这个是微软自带的写法
            builder.RegisterType<Student>().As<IStudent>();

            //生命周期:默认,也就是瞬时模式==AddTransient
            builder.RegisterType<Student>().As<IStudent>().InstancePerDependency();

            //生命周期:Scope模式==AddScoped 
            builder.RegisterType<Student>().As<IStudent>().InstancePerLifetimeScope();

            //生命周期:单例,AddSingleton
            builder.RegisterType<Student>().As<IStudent>().SingleInstance();

            
            #endregion

          


        }

注意,写法还有有差别的,RegisterType的是类,As的是接口。

builder.RegisterType<Student>().As<IStudent>();

获取实例的方法与微软自带的容器获取实例方法一致。

比如在构造函数或者方法FromService里获取:

 private readonly ILogger<HomeController> _logger;
        private readonly IHostEnvironment _hostEnvironment;
        private readonly IServiceProvider _services;
        public HomeController(ILogger<HomeController> logger, IHostEnvironment hostEnvironment, IServiceProvider services)
        {
            _logger = logger;
            _hostEnvironment = hostEnvironment;
            _services = services;
        }



        public IActionResult Index3([FromServices] IEnumerable<IStudent> services)
        {
            Console.WriteLine("开始。。。。");
            foreach (var s in services)
            {
                Console.WriteLine($"获取到的实例为:{s.ToString()}:{s.GetHashCode()}");
            }


            return View();
        }
        public IActionResult Index2([FromServices] IHostEnvironment hostEnvironment, [FromServices] IStudent stu)
        {
            //1、通过构造函数注入,获取值
            string path = _hostEnvironment.ContentRootPath;

            //2、通过方法的FromServices注入进来,获取值
            string path2 = hostEnvironment.ContentRootPath;

            //通过GetRequiredService来检索服务
            var hostEnvironment2 = HttpContext.RequestServices.GetRequiredService<IHostEnvironment>();
            string path3 = hostEnvironment2.ContentRootPath;

            string name = stu.Change();
            int hashcode = stu.GetHashCode();



            return View();
        }

三、一些特别的用法:

1、基于名称的注入

在StartUp的 ConfigureContainer(ContainerBuilder builder)里注入:

 //基于名称的注入
 builder.RegisterType<Student>().Named<IStudent>("muxue").SingleInstance();

获取实例的方法,有2种方法:

(1) IServiceProvider里获取AutoFac根容器再进行获取实例;

(2)使用AutoFac自带的ILifetimeScope获取实例;

代码如下:

 private readonly ILogger<HomeController> _logger;
        private readonly IHostEnvironment _hostEnvironment;
        private readonly IServiceProvider _services;
        public HomeController(ILogger<HomeController> logger, IHostEnvironment hostEnvironment, IServiceProvider services)
        {
            _logger = logger;
            _hostEnvironment = hostEnvironment;
            _services = services;
        }

        /// <summary>
        /// 基于名称的注入-的获取(沐雪原创)
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public IActionResult Index([FromServices] ILifetimeScope service)
        {
            Console.WriteLine("开始取对象。。。。");
            //使用IServiceProvider 的方法
            // var service= _services.GetAutofacRoot();
            var stu = service.ResolveNamed<IStudent>("myName");
            Console.WriteLine($"获取到的实例为:{stu.ToString()}:{stu.GetHashCode()}");
            return View();
        }

2、基于Key的注入:跟基于名称的注入类似,我们在使用RabbitMQ,一个项目有多个消费者的情况使用的demo 

            builder.Register((c, p) => RabbitHutch.CreateBus(c.Resolve<IConfiguration>().GetConnectionString("MQ1")))
                   .Keyed<IBus>("MQ1")
                   .SingleInstance();
            builder.Register((c, p) => RabbitHutch.CreateBus(c.Resolve<IConfiguration>().GetConnectionString("MQ2")))
                  .Keyed<IBus>("MQ2")
                  .SingleInstance();

获取实例的方法:

var bus = _services.GetAutofacRoot().ResolveKeyed<IBus>("MQ1");

3、基于属性的注入(这个在微软自带的IOC好像也有类似的写法,比如,类里需要一个Configuration的一个节点值,可以先注册该节点值,然后就可以在类里直接使用了。)

也就是一个类A里有一个属性类B,代码如下:

    public class StudentService: IStudentService
    {
        public AddressService addrService { get; set; }

        public void ShowCode()
        {
            Console.WriteLine($"StudentService.ShowCode:{GetHashCode()},addrService 是否为空:{addrService == null}");
        }
    }


    public class AddressService
    { 
        
    }

addrService是StudentService的一个属性值;

注册的时候,需要先将addrService注册,在使用属性注册的方式注册StudentService;

   #region 属性注册
            builder.RegisterType<AddressService>();
            builder.RegisterType<StudentService>().As<IStudentService>().PropertiesAutowired();
            #endregion

四、AutoFac的切面编程--拦截器AOP的使用

第一眼看到拦截器AOP功能,我还以为是个鸡肋,.NetCore都已经有了那么强大的Filter作为AOP拦截器,为啥AutoFac还有这个玩意?

        后来才发现,是自己想错了。AutoFac的拦截器,拦截的是注册在容器里的服务的实例里的方法。有点绕,简单说,他拦截的是方法,是一个实例的方法,是依赖注入注册在容器里的服务对应的实例。  而Filter则是对控制器Controller/Action的AOP的实现。两者拦截的对象不同。

AutoFac的拦截器是基于大名鼎鼎的Castle.Core来完成的。也就是Castle.Core里的一个动态代理DynamicProxy。

我们现在看下代码的实现!

1、Nuget新增加一个组件

Autofac.Extras.DynamicProxy

2、搞一个自定义的拦截器

using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication1
{
    /// <summary>
    /// 沐雪-自定义一个拦截器
    /// </summary>
    public class MyInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("----- 拦截器开始啦 -------");
            //方法的真正执行
            invocation.Proceed();
            Console.WriteLine("----- 拦截器结束啦 -------\r\n");
        }
    }
}

该拦截器继承自IInterceptor接口,我们要显示实现该接口的方法Intercept,注意里面的一句代码

  invocation.Proceed();

这是调用真实方法。

3、开始注册了,将我们自定义的拦截器,以及要拦截的服务(接口和对象)都注册进来。

在ConfigureContainer 方法里写:

 public void ConfigureContainer(ContainerBuilder builder)
        {
            

            //拦截器
            builder.RegisterType<MyInterceptor>();
            //IStudent需要这个拦截器
            builder.RegisterType<Student>().As<IStudent>().InterceptedBy(typeof(MyInterceptor)).EnableInterfaceInterceptors();


        }

我们再看下IStudent里的部分代码(demo代码):

 public interface IStudent
    {

       string   Change();
        string Change2();

    }
    public class Student : IStudent
    {
        public string name { get; set; } = "小王";
        public Student()
        {


        }

        public Student(string initName)
        { 
            name = initName;
        }

        public string Change()
        {
            Console.WriteLine("在change方法里");
            name += "002";
            return name;
        }
        public string Change2()
        {
            Console.WriteLine("在change2方法里");
            name += "007";
            return name;
        }
    }

4、最后一步,获取该实例,并且执行该实例的相应方法:

        /// <summary>
        /// 测试AutoFac拦截器
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public IActionResult Index([FromServices] IStudent services)
        {
            Console.WriteLine("\r\n沐雪大神爱吃鱼--Start。。。。\r\n"); 
            Console.WriteLine($"获取到的实例为:{services.ToString()}:{services.GetHashCode()}\r\n");
            services.Change();
            Console.WriteLine("沐雪大神爱吃鱼--已经吃了一条。。。。\r\n");
            services.Change2();

            Console.WriteLine("沐雪大神爱吃鱼--吃完啦。。。。");
            return View();
        }

直接结果如下图:



这篇关于asp.net core 3.1和 .Net 5.0中使用AutoFac作为IoC容器组件的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程