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

控制反转:我们向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. 20175324王陈峤宇 《Java程序设计》第六周学习总结

    教材学习内容总结 第七章 一.内部类与外部类的关系 1.内部类可以使用外嵌类的成员变量和方法.2.类体中不可以声明类变量和类方法,外部类可以用内部类声明对象.3.内部类仅供外嵌类使用.4.类声明可以使 ...

  2. 最新版Navicat Premium12 中文破解版 安装激活

    对于PHPer 来说 Navicat Premium  简直就是神器有木有,反正我是这样觉得的,昨天刚更新了最新版本 Navicat Premium 12 ,官网是免费试用14 天的,肿么能行呢,我们 ...

  3. mui项目实时更新

    var wgtVer=null; function plusReady(){ // ...... // 获取本地应用资源版本号 plus.runtime.getProperty(plus.runtim ...

  4. 链表加bfs求补图联通块

    https://oj.neu.edu.cn/problem/1387 给一个点数N <= 100000, 边 <= 1000000的无向图,求补图的联通块数,以及每个块包含的点数 由于点数 ...

  5. iOS依赖库管理工具之Carthage

    在iOS开发中,我们常会用CocoaPods来进行依赖库的管理.CoaoaPods 是一套整体解决方案,我们在 Podfile 中指定好我们需要的第三方库,然后 CocoaPods 就会进行下载,集成 ...

  6. 在 Ubuntu 中使用 Visual Studio Code

    前言 我一直在 Linux 桌面系统下的探索寻找各种界面美观.使用舒适的软件工具.对于Linux下的开发人员来讲,这几年最大的福利就是 MicroSoft 推出的 Visual Studio Code ...

  7. rem布局完成响应式开发,通俗且详细的原理解析和代码实现

    一.rem布局基本原理 原理:rem可以理解为一个长度单位,单位rem的值等于网页font-size的值.如果网页的字体大小为默认值16px,那么1rem就等于16px,0.5rem等于8px. 根据 ...

  8. 【计算机篇】目前最好用的 PPT 神器 — iSlide! 一键完成 PPT 设计!

    谈到工作中的难题,PPT 这个不起眼的软件,绝对算一个.不同于 Word.Excel,PPT 既要传递信息,还要讲求设计.这很容易使大部分人感觉素材不够,设计不专业或者效率不高.以往为了解决 PPT ...

  9. [Swift]LeetCode15. 三数之和 | 3Sum

    Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find ...

  10. [Swift]LeetCode282. 给表达式添加运算符 | Expression Add Operators

    Given a string that contains only digits 0-9 and a target value, return all possibilities to add bin ...