在开始之前首先解释一下我认为的依赖注入和控制反转的意思。(新手理解,哪里说得不正确还请指正和见谅)

控制反转:我们向IOC容器发出获取一个对象实例的一个请求,IOC容器便把这个对象实例“注入”到我们的手中,在这个时候我们不是一个创建者,我们是以一个请求者的身份去请求容器给我们这个对象实例。我们所有的对象依赖于容器提供给你的资源,控制权落到了容器身上。在这里的身份转化或许就是控制反转的核心吧。 

依赖注入:我们向容器发出请求以后,获得这个对象实例的过程就叫依赖注入。也就是我们在使用对象前我们都需要先注入也就是这个意思吧。

今天学习了下AutoFac依赖注入这个插件,然后还有以前用过的Unity这个插件简单做个笔记整理。首先我分两个部分记录,第一部分一点有点的记录今天学习的AutoFac这个插件,最后一部分直接补上以前使用Unity插件的代码封装不做详细解释。因为本篇幅写完有点多就单独写一下UnIty。

Unity地址:【Unity】微软的一款依赖注入组件

AutoFac入门

还是放上官网给出的整合流程吧;

  • 按照 控制反转 (IoC) 的思想构建你的应用.
  • 添加Autofac引用.
  • 在应用的 startup 处...
  • 创建 ContainerBuilder.
  • 注册组件.
  • 创建容器,将其保存以备后续使用.
  • 应用执行阶段...
  • 从容器中创建一个生命周期.
  • 在此生命周期作用域内解析组件实例.

创建简单的例子

通过一个控制台简单清晰的介绍了如何使用AutoFac这个插件。

创建项目

创建一个控制台程序叫AutoFacDome。

这里就不做过多解释了,大家都会创建哈哈。

引用Autofac

使用我vs强大的nuget来进行添加引用:

直接在搜索栏输入Autofac直接就可以查找出来:

Nuget命令行:

Install-Package Autofac -Version 4.8.1

创建一个依赖关系类:

首先我们定义一个服务接口=>IService

    /// <summary>
/// 服务接口
/// 描述:为了方法的继承和扩展更好的演示下面的例子
/// </summary> public interface IService
{
//定义一个输出方法
void PrintWord();
}

然后我们在创建一个服务类去实现接口(IService)=>Service

/// <summary>
/// 服务类具体实现
/// </summary>
public class Service : IService
{
//输出方法的实现
public void PrintWord()
{
Console.WriteLine("我是service打印的Hello word");
}
}

好了现在我们有了一个服务接口和一个服务类 ,并且类下面实现了输出会打印:我是service打印的Hello word。常规我们想调用这个方法我们都是在mian函数中示例化该类进行调用,类似于这样

            IService service = new Service();
service.PrintWord();
//或者
Service service2 = new Service();
service2.PrintWord();

但是今天我们说的不是这些我们说的另外的方式。那我们看看 autofac是怎么调用的。

注册容器

其实万变不离其宗,不管是autofac,unity,spring.net等,其实都是这么一个套路就是先注册容器然后才能从容器取出,其实这个也非常好理解容器本身是没有东西的,你想用东西就要提前放进去,只有容器有了你请求才会给你。不同的插件只不过是各自的封装方法或者形式存在着差异。autofac的注册方式:

           // 创建容器
var builder = new ContainerBuilder();
//注册对象
builder.RegisterType<Service>().As<IService>();
Container = builder.Build();

这个时候我们就相当于把service类放入了容器,这样在后面你才可以取出来使用。

使用容器

这里我写了两个使用的方法根据不同情况使用把:

            //使用方法一
using (var ioc = Container.BeginLifetimeScope())
{
var service = ioc.Resolve<IService>();
service.PrintWord();
} //使用方法二
//var service = Container.Resolve<IService>();
//service.PrintWord();

运行

我们可以任意注释一个方法来检测一下结果:

这样我们就完成了autofac的简单运用。

AutoFac新手村

通过上面的例子我们已经知道autofac的基本运用。基本运用还不行我们还要知道一些知识。

多构造函数

第一种:就是单纯的有多个构造

如果我们同一个类存在多个构造函数会给我们一个什么结果哪这个在有时候是非常重要的。

所以我们修改我们的service类:

 /// <summary>
/// 服务类具体实现
/// </summary>
public class Service : IService
{
//默认构造
public Service() {
Console.WriteLine("我是service的默认构造");
}
//一个参数的构造
public Service(int a)
{
Console.WriteLine("我是service的一个参数构造");
}
//两个参数的构造
public Service(int a,int b)
{
Console.WriteLine("我是service的两个参数构造");
}
//输出方法的实现
public void PrintWord()
{
Console.WriteLine("我是service打印的Hello word");
}
}

其他都不变运行代码:

这里就是执行了默认构造,所有在一个类有多个构造情况下默认的形式是返回给我们默认构造函数的类实例。

第二种:多构造参数类型并且参数类型也注册容器

这个什么意思哪就是说有两个类,其中一个类的构造函数参数是另一个类。并且参数类型也进行注册容器

我们增加一个ServiceTwo类:

 public class ServiceTwo :IService
{
//输出方法的实现
public void PrintWord()
{
Console.WriteLine("我是serviceTwo打印的Hello word");
}
}

修改service类中的一个参数构造为:

        //一个参数的构造
public Service(ServiceTwo two)
{
Console.WriteLine("我是service的一个参数构造");
}

main函数增加注册:

            //注册对象
builder.RegisterType<Service>().As<IService>();
builder.RegisterType<ServiceTwo>();
Container = builder.Build();

然后运行:

这里就和上面的结果不一样了,所有在使用时需要注意,autofac官方解释为:当使用基于反射的组件时, Autofac 自动为你的类从容器中寻找匹配拥有最多参数的构造方法。

说白了就是如果使用注册类并且注册类多构造函数,并且其构造参数为其他注册类时候,查找的构造函数包含注册类最多的构造函数返回。

指定构造函数

由容器掌握我们的构造函数总是不好的,所有我们要自己指定想创建谁创建谁=>UsingConstructor(参数类型)可以多个

在这里需要注意我们既然指定了构造函数就要为构造函数传参不然会抱错,参数可以是注册时候传也可以解析时候传,我写了一个解析时候传的:

            // 创建容器
var builder = new ContainerBuilder();
//注册对象
builder.RegisterType<Service>().As<IService>().UsingConstructor(typeof(int), typeof(int));
// builder.RegisterType<ServiceTwo>();
Container = builder.Build(); //使用方法一
using (var ioc= Container.BeginLifetimeScope())
{
var service = ioc.Resolve<IService>(new NamedParameter("a", ), new NamedParameter("b", ));
service.PrintWord();
}

运行结果:

类的覆盖

如果我两个类或者多个类同时实现一个接口并且注册的时候都与接口做了关联。

那么会存在覆盖现象。

下面我们把main函数改造让serviceTwo也注册与IService关联

            // 创建容器
var builder = new ContainerBuilder();
//注册对象
builder.RegisterType<Service>().As<IService>();
builder.RegisterType<ServiceTwo>().As<IService>();
Container = builder.Build(); //使用方法一
using (var ioc = Container.BeginLifetimeScope())
{
var service = ioc.Resolve<IService>();
service.PrintWord();
}

运行结果:

这个时候我们得到的是serviceTwo类的示例。如果改变Service和ServiceTwo的位置就会返回service实例。

当然我没也可以阻止这个行为使用PreserveExistingDefaults()方法:

            //注册对象
builder.RegisterType<Service>().As<IService>();
builder.RegisterType<ServiceTwo>().As<IService>().PreserveExistingDefaults();

再次运行就不会覆盖:

然后我们如何遍历所有的注册服务哪,使用循环:

  using (var ioc = Container.BeginLifetimeScope())
{
//var service = ioc.Resolve<IService>();
//service.PrintWord();
var serviceList = ioc.Resolve<IEnumerable<IService>>();
foreach (var item in serviceList) {
item.PrintWord();
} }

运行结果:

属性注入

WithProperty:绑定一个属性和他的值

我们给ServiceTwo类添加name属性并扩展一个打印方法:

 public string name { get; set; }

        public void PrintName()
{
Console.WriteLine($"name属性:{name}");
}

然后main函数改为

            builder.RegisterType<Service>().As<IService>();
builder.RegisterType<ServiceTwo>().WithProperty("name", "张三");
Container = builder.Build(); //使用方法一
using (var ioc = Container.BeginLifetimeScope())
{
var service = ioc.Resolve<ServiceTwo>();
service.PrintName();
}

运行结果:

方法注入

OnActivating:方法注入

我们在ServiceTwo类添加设置名称方法

  public void setName()
{
name = "李四";
}

然后main函数改为:

builder.RegisterType<ServiceTwo>().OnActivating(e=> {
e.Instance.setName();
});

运行结果:

AutoFac集成-MVC

首先创建mvc项目就不过多解释了。

引用dll:

这里需要引用两个dll文件: Autofac.Mvc5和 Autofac。注意这里我的是mvc5所以我安装的Autofac.Mvc5 这个要根据mvc版本做对应不然会报错。

通过nuget安装就可以了。

相关类

还是我们的Service类和IService类来做示例演示:

    /// <summary>
/// 服务接口
/// 描述:为了方法的继承和扩展更好的演示下面的例子
/// </summary> public interface IService
{
//定义一个输出方法
void PrintWord();
} /// <summary>
/// 服务类具体实现
/// </summary>
public class Service : IService
{
//默认构造
public Service()
{
Console.WriteLine("我是service的默认构造");
}
//输出方法的实现
public void PrintWord()
{
System.Diagnostics.Debug.WriteLine("调起了service中的方法");
}
}

配置文件

配置Global文件,来注入控制器。下面我只做构造函数注入和属性注入

protected void Application_Start()
{ var builder = new ContainerBuilder(); // 通过程序集注册所有控制器和属性注入
//builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired(); builder.RegisterType<Service>().As<IService>();
// 将依赖性分解器设置为AutoFac。
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}

控制器如何使用:

打开home控制器:

  public class HomeController : Controller
{ /// <summary>
/// 构造函数注入
/// </summary>
/// <param name="serviceClient"></param>
public HomeController(IService serviceClient)
{
this.Service = serviceClient;
}
public IService Service; /// <summary>
/// 属性注入
/// </summary>
/// <returns></returns>
// public IService Service2 { get; set; }
public ActionResult Index()
{
//使用方法一
Service.PrintWord();
//Service2.PrintWord(); return View();
} }

运行看效果:

自动注册所有控制器(补充)

一个一个的去注册控制是很繁琐的事情,最怕的就是后期修改代码增加了业务却没有及时添加相应的注册而出错,所以我们会全部一次注册,当然这不是必须的只是一种懒人操作。

RegisterAssemblyTypes方法:它会去扫描所有的dll并把每个类注册为它所实现的接口。

我们首先要创建一个接口基类什么都不做只做为注册的类型检测:

    /// <summary>
/// 注册基类
/// </summary>
public interface IDependency
{
}

然后所以需要注册的接口都继承此类即可:

    /// <summary>
/// 基类接口
/// </summary>
public interface IBaseService:IDependency
{
/// <summary>
/// 插入错误日志数据
/// </summary>
/// <returns></returns>
int AddErrirLog();
/// <summary>
/// 插入登录日志
/// </summary>
/// <returns></returns>
int AddLoginLog();
}

最后修改Global文件:

            var builder = new ContainerBuilder();

            // 通过程序集注册所有控制器和属性注入
//builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
//单个控制器注入
// builder.RegisterType<BaseService>().As<IBaseService>(); //集体自动注入
var baseType = typeof(IDependency);
var assbembly = AppDomain.CurrentDomain.GetAssemblies().ToList();
builder.RegisterAssemblyTypes(assbembly.ToArray())
.Where(t => baseType.IsAssignableFrom(t) && t != baseType)
.AsImplementedInterfaces().InstancePerLifetimeScope(); // 将依赖性分解器设置为AutoFac。
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

主要是红色部分

【AutoFac】依赖注入和控制反转的使用的更多相关文章

  1. ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下

    ADO.NET   一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data  → DataTable, ...

  2. ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下

    先简单了解一这个几个 名词的意思. 控制反转(IOC) 依赖注入(DI) 并不是某种技术. 而是一种思想.一种面向对象编程法则 什么是控制反转(IOC)?  什么是依赖注入(DI) 可以点击下面链接 ...

  3. ASP.NET中IOC容器Autofac(依赖注入DI 控制反转IOC)

    IOC的一个重点是在程序运行中,动态的向某个对象提供它所需要的其他对象.这一点是通过DI来实现的.Autofac则是比较流行的一款IOC容器. IoC和DI有什么关系呢?其实它们是同一个概念的不同角度 ...

  4. Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用

    一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...

  5. 浅谈(IOC)依赖注入与控制反转(DI)

    前言:参考了百度文献和https://www.cnblogs.com/liuqifeng/p/11077592.html以及http://www.cnblogs.com/leoo2sk/archive ...

  6. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->Spring Framework的依赖注入和控制反转

    Dependency Injection and Inversion of Control 1.概述: 1.1相关概念 bean:由IoC容器所管理的对象,也即各个类实例化所得对象都叫做bean 控制 ...

  7. 简单解析依赖注入(控制反转)在Spring中的应用

    IoC——Inversion of Control  控制反转DI——Dependency Injection   依赖注入 大家都知道,依赖注入是Spring中非常重要的一种设计模式.可能很多初学者 ...

  8. 谈谈php依赖注入和控制反转

    要想理解php依赖注入和控制反转两个概念,就必须搞清楚如下的问题: DI--Dependency Injection   依赖注入 IoC--Inversion of Control  控制反转 1. ...

  9. Java的依赖注入(控制反转)

    两个主角"依赖注入"和"控制反转": 1.二都说的都是同一件事,只是叫法不同.是一个重要的面向对象编程的法则,也是一种设计模式: 2.英文原称:依赖注入,Dep ...

随机推荐

  1. 1.SSM整合_单表的增删改查

    目标:增删改查 环境:Maven+Eclipse+Tomcat7+JDK7 思维导图: 表结构 目录结构 依赖 <dependencies> <dependency> < ...

  2. mybatis逆向工程的注意事项,以及数据库表

    1.选择性更新,如果有新参数就更换成新参数,如果参数是null就不更新,还是原来的参数 2.mybatis使用逆向工程,数据库建表的字段user_id必须用下滑线隔开,这样生成的对象private L ...

  3. SQL插入数据--数据中的某一列来自本表中的数据

    背景: 项目初期使用的配置库和业务库两种数据库并行,所有配置数据位于配置库,所有业务数据根据不同省份位于不同数据库.由于使用省份越来越多,各省的配置数据也越来越多导致配置库的数据量过于庞大,各省共用一 ...

  4. 《JavaScript DOM编程艺术》学习笔记(三)

    终于要完成这最后一部分了,距离第二部分已经过去五天了,一直想早点写的,但还是拖到今天了………… 34.position属性的和法制:static是position属性的默认值,意思是有关元素将按照它们 ...

  5. Mesos源码分析(4) Mesos Master的启动之三

    3. ModuleManager::load(flags.modules.get())如果有参数--modules或者--modules_dir=dirpath,则会将路径中的so文件load进来   ...

  6. #Java学习之路——第一部分总结

    今天主要是Java的入门以及idea的安装说实话,没有什么有技术含量的东西,发的也全是皮毛,但是在数组部分有很多细节需要注意,在JDK环境变量配置的地方不光光只有windows 的环境配置,还要掌握补 ...

  7. [Swift]LeetCode58. 最后一个单词的长度 | Length of Last Word

    Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the l ...

  8. JS异步解析

    同步和异步 举个

  9. Linux 设置自启动服务

     0 为停机,机器关闭.(千万不要把initdefault设置为0 )    1 为单用户模式,就像Win9x下的安全模式类似.    2 为多用户模式,但是没有NFS支持.    3 为完整的多用户 ...

  10. 【Spark篇】---Spark中Action算子

    一.前述 Action类算子也是一类算子(函数)叫做行动算子,如foreach,collect,count等.Transformations类算子是延迟执行,Action类算子是触发执行.一个appl ...