其实关于IOC,DI已经有了很多的文章,但是自己在使用中还是有很多困惑,而且相信自己使用下,印象还是会比较深刻的
关于这段时间一直在学习.net core,但是这篇文章是比较重要的,也是我自己觉得学习的东西非常多的,也得到了大神的指教,在这里和大家分享下
什么是IOC?
  控制反转(Inversion of Control,英文缩写为IoC)把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup),上面的来源于百度
  在做程序设计时,考虑到程序的耦合性,高扩展等问题,还是尽量需要将程序抽象化,各层的业务不再有实际的依赖关系,全部依赖于抽象也就是接口,在这种设计的情况下,接口的具体实现的创建工作最好交由IOC框架来做,或者自己扩展一个Ioc架构,完成一个构建工厂的功能,其实ico的工作就是一个产生对象的工厂,依赖于反射的技术
  下面讲讲.net core,下面直接程序为core了,core框架内部包含自己的ioc框架,本文从两方面来讲,首先是自带的ioc,第二是第三方ioc(actofac),文章后面有源码
  一.自带的IOC
      1.定义接口以及实现           
/// <summary>
    /// 动物类
    /// </summary>
    public interface Animal
    {
        string Call();
    }

    /// <summary>
    /// 狗狗类
    /// </summary>
    public class Dog : Animal
    {
        public Dog()
        {
            this.Name = Guid.NewGuid().ToString();
        }
        public string Name { get; set; }

        public string Call()
        {
            return this.Name;
        }
    }
      2.注册到ioc中
 // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddTransient<Animal, Dog>();
            //services.AddScoped<Animal, Dog>();
            //services.AddSingleton<Animal, Dog>();
        }
  该方法在Startup.cs
  3.在api中注入,并使用   

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace CM.NetCoreIOC.Controllers
{
    public class HomeController : Controller
    {
        Animal animal1;
        Animal animal2;
        public HomeController(Animal animal1, Animal animal2)
        {
            this.animal1 = animal1;
            this.animal2 = animal2;
        }
        public string Index()
        {
            return $"Animal 1 Name:{animal1.Call()} Animal 2 Name:{animal2.Call()}";
        }
    }
}
 注意这里的需要提供构造函数,将需要注入的作为构造函数参数,访问接口得到结果,刷新下页面,然后两次结果不一样,而且每次的Animal1与Animal2不一样
 
 
 这里的两个Animal不一样,什么原因?是因为我们注册的选择方法决定的,services.AddTransient,那有没有其他选项呢?有,如下,我们一个个来做实验

用Singleton注册
services.AddMvc();
            //services.AddTransient<Animal, Dog>();
            services.AddScoped<Animal, Dog>();
            //services.AddSingleton<Animal, Dog>();
  结果:
 
  看出区别了吧,两次结果不一样,但是每次请求的Animal 1 与Animal2一样啊,是不是发现有了不同的应用场景,嘿嘿
  用AddSingleton注册  
  services.AddMvc();
            //services.AddTransient<Animal, Dog>();
            //services.AddScoped<Animal, Dog>();
            services.AddSingleton<Animal, Dog>();
    
   是不是有发现了点什么?单例模式,创建单例的方式更加简单了
   默认的使用其实很简单,也还比较方便
 
 二.第三方IOC(autofac)
   1.添加Nuget引用 Autofac ,Autofac.Extensions.DependencyInjection
     
     
   2.修改Startup.cs文件, ConfigureServices 方法,从void变为 IServiceProvider       
// This method gets called by the runtime. Use this method to add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            var builder = new ContainerBuilder();
            builder.RegisterType(typeof(Dog)).As(typeof(Animal))
                        .InstancePerLifetimeScope()
                        .PropertiesAutowired();
            builder.Populate(services);
            return new AutofacServiceProvider(builder.Build());
        }
  运行得到结果:
 
  两次不一样,每次的对象却是一样的,达到了我们的逾期效果,这里大家不知道有没有类似的疑问?为什么可以做到?
  官网的说明,想要获取依赖注入的对象实例,有两种方法,自己也做了实验,如下,修改Startup.cs,修改Configure方法  

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
            var animal1 = ActivatorUtilities.GetServiceOrCreateInstance(app.ApplicationServices, typeof(Animal));
            var animal2 = app.ApplicationServices.GetService(typeof(Animal));
        }

调试看看两个对象animal1与animal2

 两者内部还是依赖于IServiceProvider接口来实现的,autofac写了一个AutofacServiceProvider实现了IServiceProvider,从而替换掉内部默认的ServiceProvider,所以达到了效果
   一直没有提的是core下面的ioc不支持属性注入,只能通过构造函数注入,也就是说core默认的ioc,你要注入,就要把参数全部写在构造函数的参数中,但是autofac是支持属性注入的,PropertiesAutowired就是已属性方式注入,那我们来试试,把HomeController的构造函数干掉看看
  
  报错了,根本没有注入两个属性,怎么回事?.....不对我们根本还没注册Controller到autofac中,为什么会有对象自己生成啊,其实这里的情况是比较特殊的,如果我们这时候不是直接在Controller层做实验,其实已经完成了属性的注册了,因为这时候Controller的创建工作还不是autofac做的,从我没有注册就可以看出来,那是什么原因啊?我先注册看看  

// This method gets called by the runtime. Use this method to add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            var builder = new ContainerBuilder();
            builder.RegisterType(typeof(Dog)).As(typeof(Animal))
                        .InstancePerLifetimeScope()
                        .PropertiesAutowired();
            builder.RegisterType(typeof(HomeController))
                        .InstancePerLifetimeScope()
                        .PropertiesAutowired();
            builder.Populate(services);
            return new AutofacServiceProvider(builder.Build());
        }

还是一样报错,开始查资料了,不是说autofac可以属性注入吗?
查了资料之后发现需要在ConfigureServices 方法加入一句代码 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());这样才真正的替换为autufac,才支持属性注入
// This method gets called by the runtime. Use this method to add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
            services.AddMvc();
            var builder = new ContainerBuilder();
            builder.RegisterType(typeof(Dog)).As(typeof(Animal))
                        .InstancePerLifetimeScope()
                        .PropertiesAutowired();
            builder.RegisterType(typeof(HomeController))
                        .InstancePerLifetimeScope()
                        .PropertiesAutowired();
            builder.Populate(services);
            return new AutofacServiceProvider(builder.Build());
        }

运行效果:

 终于成功了,但是我的Controller也做了相应的修改的

public class HomeController : Controller
    {
        public Animal animal1 { get; set; }
        public Animal animal2 { get; set; }
        //public HomeController(Animal animal1, Animal animal2)
        //{
        //    this.animal1 = animal1;
        //    this.animal2 = animal2;
        //}
        public string Index()
        {
            return $"Animal 1 Name:{animal1.Call()} Animal 2 Name:{animal2.Call()}";
        }
    }
 属性必须提供get;set;方法,必须是public
 回到上面的问题,必须要添加 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>()) ,这里的替换方法其实来源于
 services.AddMvc().AddControllersAsServices();
 AddControllerAsServices 源码
public static IMvcBuilder AddControllersAsServices(this IMvcBuilder 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;
}
其实内部就是就是将IControllerAcivator替换为ServiceBasedControllerActivator,
通过查看源代码ASP.NET Core默认使用DefaultControllerActivator类对Controller进行创建工作;但是找到这个类的Create函数发布它其实调用的是ActivatorUtilities来创建对象的。前面也说过这个的话,在创建类型对象时,IServiceProvdier只负责对构造器中的参数进行查找注入,创建对象的操作还是由ActivatorUtilities来create出来的,这样也就没用利用上autofac替换的ServiceProvider,也就是说ActivatorUtilities并没有扩展点来使用我们提供的方法进行替换,所以才造成了无法注入的问题。
所以需要把Controller的创建权转接到autofac,把IControllerAcivator替换为ServiceBasedControllerActivator就可以了?下面是ServiceBasedControllerActivator的Create方法
public object Create(ControllerContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
var controllerType = actionContext.ActionDescriptor.ControllerTypeInfo.AsType();
return actionContext.HttpContext.RequestServices.GetRequiredService(controllerType);
}
这里的RequestServices就是IServiceProvider,所以到这里终于明白了,为什么一句代码就接管了controller的创建
至此,.net core ioc就写完了,但是autofac的使用以及ioc的内容还有很多东西要学习,将在其他文章来学习.
 

asp.net core 四 IOC&DI Autofac的更多相关文章

  1. ASP.NET Core修改IOC为Autofac

    如下是我为了了解如何更换ASP.NET Core中的IOC而查找的文章,如果大家英文OK的,可以直接前往阅读,同时也已经有简单的github例子供大家参考. 参考文章: ASP.NET Core文档: ...

  2. 浅谈ASP.NET Core中的DI

    DI的一些事 传送门马丁大叔的文章 什么是依赖注入(DI: Dependency Injection)?     依赖注入(DI)是一种面向对象的软件设计模式,主要是帮助开发人员开发出松耦合的应用程序 ...

  3. ASP.Net Core 3.1 With Autofac ConfigureServices returning an System.IServiceProvider isn't supported.

    ASP.Net Core 3.1 With Autofac ConfigureServices returning an System.IServiceProvider isn't supported ...

  4. 浅谈ASP.NET Core中IOC与DI的理解和使用

    说起IOC和DI,使用过ASP.NET Core的人对这两个概念一定不陌生,早前,自己也有尝试过去了解这两个东西,但是一直觉得有点很难去理解,总觉得对其还是模糊不清,所以,趁着今天有空,就去把两个概念 ...

  5. Asp.net Core依赖注入(Autofac替换IOC容器)

    ASP.NET Core ASP.NET Core (previously ASP.NET 5) 改变了以前依赖注入框架集成进ASP.NET的方法. 以前, 每个功能 - MVC, Web API, ...

  6. ASP.NET Core 依赖注入(DI)

    ASP.NET Core的底层设计支持和使用依赖注入.ASP.NET Core 应用程序可以利用内置的框架服务将服务注入到启动类的方法中,并且应用程序服务也可以配置注入.由ASP.NET Core 提 ...

  7. ASP.NET Core依赖注入(DI)

    ASP.NET Core允许我们指定注册服务的生存期.服务实例将根据指定的生存时间自动处理.因此,我们无需担心清理此依赖关系,他将由ASP.NET Core框架处理.有如下三种类型的生命周期. 关于依 ...

  8. ASP.NET Core 四种释放 IDisposable 对象的方法

    本文翻译自<Four ways to dispose IDisposables in ASP.NET Core>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! IDispos ...

  9. ASP.NET Core 四种方式绑定枚举值

    前言 本节我们来讲讲在ASP.NET Core MVC又为我们提供了哪些方便,之前我们探讨过在ASP.NET MVC中下拉框绑定方式,这节我们来再来重点看看枚举绑定的方式,充分实现你所能想到的场景,满 ...

随机推荐

  1. typeof操作符 返回值

    Type操作符 返回值 : 1undefined   这个未定义 2.boolean    这个为boolean类型 3.string      这个是字符串 4.number    这个就是数值 5 ...

  2. 高并发WEB网站优化方案

    一.什么是高并发在互联网时代,所讲的并发.高并发,通常是指并发访问,也就是在某个时间点,有多少个访问同时到来.比如,百度首页同时有1000个人访问,那么也就是并发为1000.通常一个系统的日PV在千万 ...

  3. 关于HTTP,你知道哪些?

    HTTP简介 HTTP 的全称是 Hypertext Transfer Protocol,超文本传输协议 规定客户端和服务器之间的数据传输格式 让客户端和服务器能有效地进行数据沟通 HTTP 协议是网 ...

  4. Yii高级模板的安装

    1,如果你使用composer来安装的话,执行下边两条命令. composer global require "fxp/composer-asset-plugin:^1.2.0" ...

  5. WPF 照片墙的实现

    主要参照了DevExpress的PhotoGallery实例的实现. 效果如下: 照片墙核心代码如下: PhotoGallery.xaml <local:CarouselDemoModule x ...

  6. 合唱团 (线性dp)

    题意:有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积 ...

  7. 使用phpstorm提交svn代码版本管理系统遇到的问题解决办法

    1.当自己提交代码的时候显示out of date的时候,表示我们本地的代码过时啦,需要更新一下再提交. 即:更新一下再提交即可. 2.当自己的代码和服务器上的冲突的时候,我们右键点击冲突的文件,选择 ...

  8. 4.1 PCIe总线的基础知识

    与PCI总线不同,PCIe总线使用端到端的连接方式,在一条PCIe链路的两端只能各连接一个设备,这两个设备互为是数据发送端和数据接收端.PCIe总线除了总线链路外,还具有多个层次,发送端发送数据时将通 ...

  9. Android内核解读-应用的安装过程

    前言 我们知道,在android手机上安装一个apk很简单,只要打开apk文件,默认就会弹出安装界面,然后点击确定,经过若干秒后,apk就安装成功了,可是你知道apk的安装过程是什么吗?你知道andr ...

  10. SSH2三大框架SQL查询

    /** * 查询省份名称 * @author YHD * @return * @see */ @SuppressWarnings("unchecked") @Override pu ...