• ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)


    前言

    本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期.

    这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度.

    目录

    ASP.NET Core中使用IOC三部曲(一.使用ASP.NET Core自带的IOC容器)

    ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)

    ASP.NET Core中使用IOC三部曲(三.采用替换后的Autofac来实现AOP拦截)

    正文

    上一篇我们说过ASP.NET Core中自带的IOC容器是属于轻量级的,功能并不是很多,只是提供了基础功能而已..

    所以今天我们主要讲讲如何采用Autofac来替换IOC容器,并实现属性注入

    注意:本文需要读者理解DI IOC并使用过相关框架.

    1.将默认的IOC容器替换为Autofac

     首先,我们需要从nuget引用相关的包.

    Autofac

    Autofac.Extensions.DependencyInjection(这个包扩展了一些微软提供服务的类.来方便替换autofac)

    然后,我们修改Startup中的ConfigureServices代码如下:

            public IServiceProvider ConfigureServices(IServiceCollection services)
            {
                services.AddMvc();
                services.AddDbContext<BloggingContext>();
                services.AddDirectoryBrowser();
                var containerBuilder = new ContainerBuilder();
                containerBuilder.RegisterModule<DefaultModule>();
                containerBuilder.Populate(services);
                var container = containerBuilder.Build();
                return new AutofacServiceProvider(container);
            }

    这里我们使用了AutoFac的功能之一,模块化注入.也就是RegisterModule 这里, DefaultModule是我们的注入模块,代码很简单,如下:

        public class DefaultModule : Module
        {
            protected override void Load(ContainerBuilder builder)
            {
    
                //注入测试服务
                builder.RegisterType<TestService>().As<ITestService>();
                
            }
        }

    解释一下,在上面的代码中,我们配置IServiceProvider从Autofac容器中解析(设置一个有效的Autofac服务适配器)。

    然后在整个框架中使用它来解析控制器的依赖关系,并在HttpContext上公开所有其他用例的服务定位。

    这样我们就完成了初步的Autofac容器替换.下面我们创建控制器来看看效果.代码如下:

     public class AutoDIController : Controller
        {
    
            private readonly ITestService _testService;
    
            public AutoDIController(ITestService testService)
            {
                _testService = testService;
            }
            
            // GET: AutoDI
            public ActionResult Index()
            {
                ViewBag.date = _testService.GetList("Name");
                return View();
            }
    }

    当框架(通过一个命名为DefaultControllerActivator的服务)要创建一个控制器的实例时,它会解析IServiceProvider的所有构造函数依赖项.在上面的代码中,它会使用Autofac容器来解析产生类。

    这样就能初步的达到我们替换IOC容器的的效果了..

    但是,这个操作过程与asp.net MVC的不同之处在于.控制器本身不会从容器中解析出来,所以服务只能从它的构造器参数中解析出来。

    所以.这个过程,让我们无法使用Autofac的一些更高级功能.比如属性注入(关于属性注入的好坏..属于仁者见仁智者见智的东西,这里我们不讨论它是好还是坏.)

    2.如何使用Autofac的高级功能,属性注入.

    我们回到Autofac设置代码,并设置属性注入如下:

     var containerBuilder = new ContainerBuilder();
     //模块化注入
      containerBuilder.RegisterModule<DefaultModule>();
      //属性注入控制器
      containerBuilder.RegisterType<AutoDIController>().PropertiesAutowired();
      containerBuilder.Populate(services);

    注入模块的代码修改如下:

    //属性注入
    builder.RegisterType<TestService>().As<ITestService>().PropertiesAutowired();

    然后修改我们的控制器代码如下:

     public class AutoDIController : BaseController
     {
    
            public  ITestService _testService { get; set; }
            
            // GET: AutoDI
            public ActionResult Index()
            {
                ViewBag.date = _testService.GetList("Name");
                return View();
            }
    }

    这里我们剔除了控制器的构造函数.

    我们运行代码,会发现_testService 为null,所以根本没有注入成功.失败的原因上面我们已经解释过了...但是还是强调一下吧..

    虽然控制器的构造函数依赖性将由MVC从IServiceProvider解决(也就是我们之前构造函数注入的例子),

    但是控制器本身的实例(以及它的处理)却是由框架创建和拥有的,而不是由容器所有。

    那么我们该如何改变控制器本身的创建和所有者呢?

    我们会在Microsoft.Extensions.DependencyInjection中找到一个方法.叫做AddControllersAsServices

    它的注释翻译过来为:将控制器的寄宿器转为注册的服务(也就是我们替换的autofac).

    但是,注意..这里虽然是将控制的所有者改成了autofac,但是我们还是不能使用相关的属性注入方法.

    所以,我们到GITHUB上来看看这个方法源码如下.(这就是开源的好处...):

    public static IMvcBuilder AddControllersAsServices(this IMvcBuilder builder)
            {
                if (builder == null)
                {
                    throw new ArgumentNullException(nameof(builder));
                }
    
                var feature = new ControllerFeature();
                builder.PartManager.PopulateFeature(feature);
    
                foreach (var controller in feature.Controllers.Select(c => c.AsType()))
                {
                    builder.Services.TryAddTransient(controller, controller);
                }
    
                builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
    
                return builder;
            }

    我们会发现最后一句..

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

    意思是用ServiceBasedControllerActivator替换DefaultControllerActivator(意味着框架现在会尝试从IServiceProvider中解析控制器实例

    ..这下终于真相大白了..

    我们只需要修改配置服务的代码如下:

         public IServiceProvider ConfigureServices(IServiceCollection services)
            {
                //替换控制器所有者
                services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
                services.AddMvc();
                services.AddDbContext<BloggingContext>();
                services.AddDirectoryBrowser();
                var containerBuilder = new ContainerBuilder();
                containerBuilder.RegisterModule<DefaultModule>();
                //采用属性注入控制器
                containerBuilder.RegisterType<AutoDIController>().PropertiesAutowired();
                // containerBuilder.RegisterTypes(feature.Controllers.Select(ti => ti.AsType()).ToArray()).PropertiesAutowired();
                containerBuilder.Populate(services);
    
                var container = containerBuilder.Build();
                return new AutofacServiceProvider(container);
            }

    注意,替换的方法一定要在addMVC之前..

    然后我们运行我们的控制器代码.效果如图:

    如图所示,_testService已经被实例化了.说明我们的属性注入就成功了~

    写在最后

    本篇到此就结束了,下篇我们讲解,如何使用Autofac的高级功能来实现我们的切面编程(AOP)

    喜欢的请点个推荐和关注,~有问题也希望各位批评指正~.

  • 相关阅读:
    《需求规格说明书》的工作流程、组员分工和组员工作量比例
    电子公文传输系统 需求分析
    电子公文传输系统 团队展示
    团队作业(三)
    2.3.1测试
    缓冲区溢出漏洞实验
    cat userlist
    ls的功能
    团队作业(二)——需求分析
    C语言中的函数、数组与指针
  • 原文地址:https://www.cnblogs.com/GuZhenYin/p/8301500.html
Copyright © 2020-2023  润新知