中国最大的网络公司排名,河南企业站seo,廊坊网站建设兼职,国家高新技术企业税收优惠政策第一章|理论基础实战控制台程序实现AutoFac注入第二章|AutoFac的常见使用套路第三章|实战Asp.Net Framework Web程序实现AutoFac注入第四章|实战Asp.Net Core自带DI实现依赖注入第五章|实战Asp.Net Core引入AutoFac的两种方式简介该系列共5篇文章#xff0c;旨在以实战模式实战控制台程序实现AutoFac注入第二章|AutoFac的常见使用套路第三章|实战Asp.Net Framework Web程序实现AutoFac注入第四章|实战Asp.Net Core自带DI实现依赖注入第五章|实战Asp.Net Core引入AutoFac的两种方式简介该系列共5篇文章旨在以实战模式在.net下的控制台程序Framework Mvc程序Framework WebApi程序Core Api程序分别实现依赖注入。其中.Net Framework框架主要以如何引入AutoFac作为容器以及如何运用AuotoFac为主.Net Core框架除了研究引入AutoFac的两种方式同时也运用反射技巧对其自带的DI框架进行了初步封装实现了相同的依赖注入效果。项目架构如下图Ray.EssayNotes.AutoFac.Infrastructure.CoreIocCore容器类库.NET Core 2.2Ray.EssayNotes.AutoFac.Infrastructure.IocFramework容器类库.NET Framework 4.5Ray.EssayNotes.AutoFac.Model实体层类库.NET Framework 4.5Ray.EssayNotes.AutoFac.Repository仓储层类库.NET Framework 4.5Ray.EssayNotes.AutoFac.Service业务逻辑层类库.NET Framework 4.5Ray.EssayNotes.AutoFac.ConsoleApp控制台主程序控制台项目.NET Framework 4.5Ray.EssayNotes.AutoFac.CoreApiCore WebApi主程序Core Api项目.NET Core 2.2Ray.EssayNotes.AutoFac.NetFrameworkApiFramework WebApi主程序Framework WebApi项目.NET Framework 4.5Ray.EssayNotes.AutoFac.NetFrameworkMvcFramework MVC主程序Framework MVC项目.NET Framework 4.5GitHub源码地址https://github.com/WangRui321/Ray.EssayNotes.AutoFacWelcome to fork me~(欢迎来叉我~)适用对象该项目主要实战为主理论部分我会结合例子和代码深入浅出地阐述如果你是从来没听过IoC、DI这些劳什子了解一些依赖注入的理论知识但是缺乏实战在.Net Framework下已熟练运用依赖注入但在.Net Core还比较陌生只要你花上半个小时认真读完每一句话我有信心这篇文章一定会对你有所帮助。如果你是那么也欢迎阅读虽然可能对你帮助并不大但是欢迎提供宝贵的意见有写的不好的地方可以互相交流~下面开始第一章《理论知识实战控制台程序实现AutoFac注入》依赖依赖简单说就是当一个类需要另一个类协作来完成工作的时候就产生了依赖。这也是耦合的一种形式。举个例子比如标准的三层架构模式界面层UI负责展示数据StudentController业务逻辑层BLL负责业务逻辑运算StudentService数据访问层DAL负责提供数据StudentRepository数据访问层DAL代码 public class StudentRepository { public string GetName(long id) { return 学生张三; } }业务层BLL代码 public class StudentService { private readonly StudentRepository _studentRepository; public StudentService() { _studentRepository new StudentRepository(); } public string GetStuName(long id) { var stu _studentRepository.Get(id); return stu.Name; } }其中StudentService的实现就必须要依赖于StudentRepository。而且这是一种紧耦合一旦StudentRepository有任何更改必然导致StudentService的代码同样也需要更改这种情况是程序员们不愿意看到的。接口驱动接口驱动是为了实现一个设计原则要依赖于抽象而不是具体的实现。还拿上面的例子说明现在我添加一个DAL的接口层IStudentRepository抽象出所需方法 public interface IStudentRepository { string GetName(long id); }然后让StudentRepository去实现这个接口 public class StudentRepository : IStudentRepository { public string GetName(long id) { return 学生张三; } }然后在StudentService里只依赖于IStudentRepository以后的增删改查都通过IStudentRepository这个抽象来做 public class StudentService { private readonly IStudentRepository _studentRepository; public StudentService() { _studentRepository new StudentRepository(); } public string GetStuName(long id) { var stu _studentRepository.Get(id); return stu.Name; } }这样做的好处有两个一个是低耦合一个是职责清晰。如果对此还有怀疑的话我们可以想象一个情景就是负责写StudentService的是程序员A负责写StudentRepository的是另一个程序员B那么针对程序员A我程序员A只需要关注业务逻辑层面如果我需要从仓储层拿数据库的数据比如我需要根据Id获取学生实体那么我只需要去IStudentRepository找Get(long id)函数就可以了至于实现它的仓储怎么实现这个方法我完全不用管你怎么从数据库拿数据不是我该关心的事情。针对程序员B我程序员B的工作就是实现IStudentRepository接口的所有方法就行了简单而明确至于谁来调用我我不用管。IStudentRepository里有根据Id获取学生姓名的方法我实现了就行至于业务逻辑层拿这个名字干啥那不是我要关心的事情。这样看的话是不是彼此的职责就清晰多了更进一步再举个极端的例子比如程序员B是个实习生整天划水摸鱼技术停留在上个世纪结果他写的仓储层读取数据库全部用的手写sql语句的方式极难维护后来被领导发现领了盒饭公司安排了另一个程序员C来重写仓储层C这时不需要动其他代码只需要新建一个仓储StudentNewRepository,然后实现之前的IStudentRepositoryC使用Dapper或者EF写完新的仓储层之后剩下的只需要在StudentService里改一个地方就行了 public StudentService() { _studentRepository new StudentNewRepository(); }是不是很清晰耦合不会像以前那么重。其实对于这个小例子来说接口驱动的优势还不太明显但是在系统层面优势就会被放大。比如上面换仓储的例子虽然职责是清晰了但是项目里有几个Service就需要改几个地方还是很麻烦。原因就是上面讲的这是一种依赖关系Service要依赖Repository有没有一种方法可以让这种控制关系反转过来呢当Service需要使用Repository有没有办法让我需要的Repository自己注入到我这里来当然有这就是我们将要实现的依赖注入。使用依赖注入后你会发现当C写完新的仓储后业务逻辑层StudentService是不需要改任何代码的所有的Service都不需要一个一个去改直接在注入的时候修改规则不要注入以前老的直接注入新的仓储就可以了。面向接口后的架构界面层UI负责展示数据StudentController业务逻辑抽象层InterfaceBLL业务逻辑运算抽象接口IStudentService业务逻辑层BLL负责业务逻辑运算StudentService数据访问抽象层InterfaceDAL数据访问抽象接口IStudentRepository数据访问层DAL负责提供数据StudentRepository什么是IoCIoC全称Inversion of Control即“控制反转”是一种设计原则最早由Martin Fowler提出因为其理论提出时间和成熟时间相对较晚所以并没有被包含在GoF的《设计模式》中。什么是DIDI全称Dependency Injection即依赖注入是实现IoC的其中一种设计方法。其特征是通过一些技巧将依赖的对象注入到调用者当中。比如把Repository注入到Service当中这里说的技巧目前主要指的就是引入容器先把所有会产生依赖的对象统一添加到容器当中比如StudentRepository和StudentService把分配权限交给容器当StudentService内部需要使用StudentRepository时这时不应该让它自己new出来一个而是通过容器把StudentRepository注入到StudentService当中。这就是名称“依赖注入”的由来。DI和IoC有什么区别这是个老生常谈的问题了而且这两个名字经常在各种大牛和伪大牛的吹逼现场频繁出现 听的新手云里雾里莫名感到神圣不可侵犯。那么DI和IoC是同一个东西吗如果不是它们又有什么区别呢回答很简单不是一个东西。区别也很简单一句话概括就是IoC是一种很宽泛的理念DI是实现了IoC的其中一种方法。说到这里我已经感觉到屏幕后的你性感地添了一下嘴唇囤积好口水准备开始喷我了。先别慌我有证据我们先来看下微软怎么说ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.地址https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?viewaspnetcore-2.2翻译过来就是“ASP.NET Core支持依赖注入DI的软件设计模式该模式是一种在类和它依赖的对象之间实现了控制反转IoC的技术”。如果有人觉得辣鸡微软不够权威那我们去看下IoC以及DI这两个概念的发明人——Martin Fowler怎么说几位轻量级容器的作者曾骄傲地对我说这些容器非常有用因为它们实现了控制反转。这样的说辞让我深感迷惑控制反转是框架所共有的特征如果仅仅因为使用了控制反转就认为这些轻量级容器与众不同就好象在说我的轿车是与众不同的因为它有四个轮子。因此我想我们需要给这个模式起一个更能说明其特点的名字——”控制反转”这个名字太泛了常常让人有些迷惑。经与多位IoC 爱好者讨论之后我们决定将这个模式叫做”依赖注入”Dependency Injection。地址http://insights.thoughtworkers.org/injection/Martin Fowler说的比较委婉其实说白了就是建议我们不要乱用IoC装逼IoC是一种设计理念很宽泛你把程序里的一个写死的变量改成从配置文件里读取也是一种控制反转由程序控制反转为由框架控制你把这个配置改成用户UI界面的一个输入文本框由用户输入也是一种控制反转由框架控制反转为由用户自己控制。所以如果确定讨论的模式是DI那么就表述为DI还是尽量少用IoC这种宽泛的表达。AutoFacAutoFac是一个开源的轻量级的DI容器也是.net下最受大家欢迎的实现依赖注入的工具之一通过AutoFac我们可以很方便的实现一些DI的骚操作。目标很简单就是控制台程序启动后将学生姓名打印出来。程序启动流程是控制台主程序调用Service层Service层调用Repository层获取数据示例项目的仓储层没有连接数据库只是直接造个假数据返回。没有依赖注入的情况下肯定是主程序会new一个StudentServiceStudentService里会new一个StudentRepository现在引入依赖注入后就不应该这么new出来了而是通过容器注入也就是容器会把StudentRepository自动注入到StudentService当中。架构实体层学生实体类StudentEntitynamespace Ray.EssayNotes.AutoFac.Model{ public class StudentEntity { public long Id { get; set; } public string Name { get; set; } public int Grade { get; set; } }}仓储层IStudentRepository接口using Ray.EssayNotes.AutoFac.Model;namespace Ray.EssayNotes.AutoFac.Repository.IRepository{ public interface IStudentRepository { string GetName(long id); }}StudentRepository仓储类using Ray.EssayNotes.AutoFac.Model;using Ray.EssayNotes.AutoFac.Repository.IRepository;namespace Ray.EssayNotes.AutoFac.Repository.Repository{ public class StudentRepository : IStudentRepository { public string GetName(long id) { return 学生张三; } }}Service层IStudentService接口namespace Ray.EssayNotes.AutoFac.Service.IService{ public interface IStudentService { string GetStuName(long id); }}StudentService类:using Ray.EssayNotes.AutoFac.Repository.IRepository;using Ray.EssayNotes.AutoFac.Repository.Repository;using Ray.EssayNotes.AutoFac.Service.IService;namespace Ray.EssayNotes.AutoFac.Service.Service{ public class StudentService : IStudentService { private readonly IStudentRepository _studentRepository; public StudentService(IStudentRepository studentRepository) { _studentRepository studentRepository; } public string GetStuName(long id) { var stu _studentRepository.Get(id); return stu.Name; } }}其中构造函数是一个有参的函数参数是学生仓储这个后面依赖注入时会用。AutoFac容器需要先通过Nuget导入Autofac包using System;using System.Reflection;using Autofac;using Autofac.Core;using Ray.EssayNotes.AutoFac.Repository.IRepository;using Ray.EssayNotes.AutoFac.Repository.Repository;using Ray.EssayNotes.AutoFac.Service.IService;using Ray.EssayNotes.AutoFac.Service.Service;namespace Ray.EssayNotes.AutoFac.Infrastructure.Ioc{ public static class Container { public static IContainer Instance; public static void Init() { var builder new ContainerBuilder(); MyBuild(builder); Instance builder.Build(); } public static void MyBuild(ContainerBuilder builder) { builder.RegisterTypeStudentRepository().AsIStudentRepository(); builder.RegisterTypeStudentService().AsIStudentService(); } }}其中public static IContainer Instance为单例容器Init()方法用于初始化容器即往容器中添加对象我们把这个添加的过程称为注册Register。ContainerBuilder为AutoFac定义的容器构造器我们通过使用它往容器内注册对象。MyBuild(ContainerBuilder builder)方法我们具体注册的实现函数。RegisterType是AutoFac封装的一种最基本的注册方法传入的泛型StudentService就是我们欲添加到容器的对象As函数负责绑定注册对象的暴露类型一般是以其实现的接口类型暴露这个暴露类型是我们后面去容器内查找对象时使用的搜索标识我们从容器外部只有通过暴露类型才能找到容器内的对象。主程序需要先Nuget导入AutoFac程序包using System;using Autofac;using Ray.EssayNotes.AutoFac.Infrastructure.Ioc;using Ray.EssayNotes.AutoFac.Service.IService;namespace Ray.EssayNotes.AutoFac.ConsoleApp{ class Program { static void Main(string[] args) { Container.Init(); PrintStudentName(10001); Console.ReadKey(); } public static void PrintStudentName(long id) { IStudentService stuService Container.Instance.ResolveIStudentService(); string name stuService.GetStuName(id); Console.WriteLine(name); } } }进入Main函数先调用容器的初始化函数该函数执行成功后StudentRepository和StudentService就被注册到容器中了。然后调用打印学生姓名的函数其中Resolve()方法是AutoFac封装的容器的解析方法传入的泛型就是之前注册时的暴露类型下面可以详细看下这一步到底发生了哪些事情容器根据暴露类型解析对象也就是容器会根据暴露类型IStudentService去容器内部找到其对应类即StudentService找到后会试图实例化一个对象出来。实例化StudentServiceAutoFac容器在解析StudentService的时候会调用StudentService的构造函数进行实例化。构造注入AutoFac容器发现StudentService的构造函数需要一个IStudnetRepository类型的参数于是会自动去容器内寻找根据这个暴露类型找到对应的StudnetRepository后自动将其注入到了StudentService当中经过这几步一个简单的基于依赖注入的程序就完成了。结果我们将控制台程序设置为启动项目点击运行如图调用成功如果把调试断点加在容器初始化函数里可以很清晰的看到哪些对象被注册到了容器里使用控制台程序本来是为了突出容器的概念但是容易造成一些误解DI的最终形态可以参考源码里的Api项目和MVC项目本来想循序渐进先第一章控制台引入容器的概念然后第二章讲批量注册、注入泛型、生命周期域管理第三章讲Api和MVC项目最后两章讲下.net core的DI但是这里还是先说下吧误解1每次添加Service和Repository都要去注册不是更麻烦其实是不需要一个一个注册的运用批量注册后容器内部的代码是这样的可以直接批量注册所有的 public static class MvcContainer { public static IContainer Instance; public static void Init(FuncContainerBuilder, ContainerBuilder func null) { var builder new ContainerBuilder(); MyBuild(builder); func?.Invoke(builder); Instance builder.Build(); System.Web.Mvc.DependencyResolver.SetResolver(new AutofacDependencyResolver(Instance)); } public static void MyBuild(ContainerBuilder builder) { Assembly[] assemblies Helpers.ReflectionHelper.GetAllAssembliesWeb(); builder.RegisterAssemblyTypes(assemblies) .Where(cc cc.Name.EndsWith(Repository) | cc.Name.EndsWith(Service)) .PublicOnly() .Where(cc cc.IsClass) .AsImplementedInterfaces(); builder.RegisterGeneric(typeof(BaseRepository)).As(typeof(IBaseRepository)); Assembly mvcAssembly assemblies.FirstOrDefault(x x.FullName.Contains(.NetFrameworkMvc)); builder.RegisterControllers(mvcAssembly); } }误解2每次使用都要解析下还不如直接new好吧其实也是不需要自己去解析的最终形态的Controller入口是这样的直接在构造函数里写就行了 public class StudentController : Controller { private readonly IStudentService _studentService; public StudentController(IStudentService studentService) { _studentService studentService; } public string GetStuNameById(long id) { return _studentService.GetStuName(id); } }就是直接在构造函数里注入就可以了。误解3依赖注入是不是过度设计首先DI是一个设计模式design pattern其本身完全不存在过不过度的问题这完全取决于用的人和怎么用。另外在.NET Core中DI被提到了一个很重要的地位如果想要了解.NET Core理解DI是必不可少的。原文地址https://www.cnblogs.com/RayWang/p/11128554.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com