ASP.NET Core依赖注入解读及使用Autofac替代实现
1. 前言
关于ioc模式(控制反转)和di技术(依赖注入),我们已经见过很多的探讨,这里就不再赘述了。比如说必看的martin fowler《ioc 容器和 dependency injection 模式》,相关资料链接都附于文章末尾。其中我非常赞同artech的说法"控制更多地体现为一种流程的控制",而依赖注入技术让我们的应用程序实现了松散耦合。
asp.net core本身已经集成了一个轻量级的ioc容器,开发者只需要定义好接口后,在startup.cs的configureservices方法里使用对应生命周期的绑定方法即可,常见方法如下
services.addtransient services.addscoped services.addsingleton
对于上述的三种di注入方式,官方也给出了详细的解释,我来简单翻译一下
transienttransient 服务在每次请求时被创建,它最好被用于轻量级无状态服务(如我们的repository和applicationservice服务) scoped
scoped 服务在每次请求时被创建,生命周期横贯整次请求 singleton
顾名思义,singleton(单例) 服务在第一次请求时被创建(或者当我们在configureservices中指定创建某一实例并运行方法),其后的每次请求将沿用已创建服务。如果开发者的应用需要单例服务情景,请设计成允许服务容器来对服务生命周期进行操作,而不是手动实现单例设计模式然后由开发者在自定义类中进行操作。
在这之后,我们便可以将服务通过构造函数注入或者是属性注入的方式注入到controller,view(通过使用@inject),甚至是filter中(以前使用unity将依赖注入到filter真是一种痛苦)。话不多说,先来体验一把
tips:startup.cs是什么,详见asp.net core 介绍和项目解读
aspnet-core-中的di方式">2. asp.net core 中的di方式
大多项目举例依赖注入的生命周期演示时,都会采取可变guid来作为返回显示,此次示例也会这样处理。我们先定义一个iguidappservice接口,里面定义基接口和三种注入模式的接口
public interface iguidappservice { guid guiditem(); } public interface iguidtransientappservice : iguidappservice { } public interface iguidscopedappservice : iguidappservice { } public interface iguidsingletonappservice : iguidappservice { }
同样的,在guidappservice中定义其实现类。这里为了直观显示每次请求的返回值,采取如下代码
public class guidappservicebase : iguidappservice { private readonly guid _item; public guidappservicebase() { _item = guid.newguid(); } public guid guiditem() { return _item; } } public class guidtransientappservice : guidappservicebase, iguidtransientappservice { } public class guidscopedappservice : guidappservicebase, iguidscopedappservice { } public class guidsingletonappservice : guidappservicebase, iguidsingletonappservice { }
最后是controller和view视图的代码
# controller public class homecontroller : controller { private readonly iguidtransientappservice _guidtransientappservice; //#构造函数注入 //private iguidtransientappservice _guidtransientappservice { get; } #属性注入 private readonly iguidscopedappservice _guidscopedappservice; private readonly iguidsingletonappservice _guidsingletonappservice; public homecontroller(iguidtransientappservice guidtransientappservice, iguidscopedappservice guidscopedappservice, iguidsingletonappservice guidsingletonappservice) { _guidtransientappservice = guidtransientappservice; _guidscopedappservice = guidscopedappservice; _guidsingletonappservice = guidsingletonappservice; } public iactionresult index() { viewbag.transientitem = _guidtransientappservice.guiditem(); viewbag.scopeditem = _guidscopedappservice.guiditem(); viewbag.singletonitem = _guidsingletonappservice.guiditem(); return view(); } } # index view guiditem shows transientitem: @viewbag.transientitem scopeditem: @viewbag.scopeditem singletonitem: @viewbag.singletonitem
之后我们打开两个浏览器,分别刷新数次,也只会发现“transientitem”和“scopeditem”的数值不断变化,“singletonitem”栏的数值是不会有任何变化的,这就体现出单例模式的作用了,示例图如下
但是这好像还不够,要知道我们的scoped的解读是“生命周期横贯整次请求”,但是现在演示起来和transient好像没有什么区别(因为两个页面每次浏览器请求仍然是独立的,并不包含于一次中),所以我们采用以下代码来演示下(同一请求源)
# 新建guiditempartial.cshtml视图,复制如下代码,使用@inject注入依赖 @using dependencyinjection.iapplicationservice @inject iguidtransientappservice transientappservice @inject iguidscopedappservice guidscopedappservic @inject iguidsingletonappservice guidsingletonappservice guiditem shows transientitem: @transientappservice.guiditem() scopeditem: @guidscopedappservic.guiditem() singletonitem: @guidsingletonappservice.guiditem() # 原先的index视图 @{ viewdata["title"] = "home page"; } @html.partial("guiditempartial") @html.partial("guiditempartial")
依然是 ctrl+f5 调试运行,可以发现“scopeditem”在同一请求源中是不会发生变化的,但是“transientitem”依然不断变化,理论仍然是支持的
3. autofac实现和自定义实现扩展方法
除了asp.netcore自带的ioc容器外,我们还可以使用其他成熟的di框架,如autofac,structuremap等(笔者只用过unity,ninject和castle,castle也是使用abp时自带的)。
3.1 安装autofac
首先在project.json的dependency节点中加入autofac.extensions.dependencyinjection引用,目前最新版本是4.0.0-rc3-309
3.2 创建容器并注册依赖
在startup.cs中创建一个public icontainer applicationcontainer { get; private set; }对象,并把configureservices返回类型改为iserviceprovider,然后复制以下代码进去,也可以实现相关功能
var builder = new containerbuilder(); //注意以下写法 builder.registertype().as(); builder.registertype().as().instanceperlifetimescope(); builder.registertype().as().singleinstance(); builder.populate(services); this.applicationcontainer = builder.build(); return new autofacserviceprovider(this.applicationcontainer);
创建autofac容器时不要忘了将configureservices的返回值修改为iserviceprovider 对应asp.net core提及的不同的生命周期,autofac也定义了对应的扩展方法,如instanceperlifetimescope等,默认为transient模式,包括entityframwork等context也是该种模式 autofac core不支持从view中注入,但是可以和asp.net core自带ioc容器配合使用 autofac core版本和传统的asp.net mvc项目版本的区别值得注意的几点:
上一篇: api.js总是冲突怎么办?
下一篇: SQLServer存储过程实现单条件分页
推荐阅读
-
ASP.NET Core依赖注入解读及使用Autofac替代实现
-
ASP.NET Core Web 应用程序系列(二)- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)
-
使用AutoFac在ASP.NET Web API上实现依赖注入
-
ASP.NET Core 2.0使用Autofac实现IOC依赖注入竟然能如此的优雅简便
-
ASP.NET Core Web 应用程序系列(三)- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)
-
ASP.NET Core Web 应用程序系列(二)- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)
-
ASP.NET Core依赖注入解读及使用Autofac替代实现
-
使用AutoFac在ASP.NET Web API上实现依赖注入
-
ASP.NET Core 2.0使用Autofac实现IOC依赖注入竟然能如此的优雅简便