core控制器属性注入的用处_理解 ASP.NET Core 依赖注入
DI在.NET Core里面被提到了一个非常重要的位置,介绍一下.NET Core的DI实现以及对实例生命周期的管理,在控制台以及Mvc下如何使用DI,以及如何把默认的Service Container 替换成Autofac
一、什么是依赖注入(Denpendency Injection)
这也是个老身常谈的问题,到底依赖注入是什么? 为什么要用它? 初学者特别容易对控制反转IOC(Iversion of Control),DI等概念搞晕。
1.1依赖
当一个类需要另一个类协作来完成工作的时候就产生了依赖。比如我们在AccountController这个控制器需要完成和用户相关的注册、登录 等事情。其中的登录我们由EF结合Idnetity来完成,所以我们封装了一个EFLoginService。这里AccountController就有一个ILoginService的依赖。
这里有一个设计原则:依赖于抽象,而不是具体的实现。所以我们给EFLoginService定义了一个接口,抽象了LoginService的行为。
1.2 什么是注入
注入体现的是一个IOC(控制反转的的思想)。在反转之前 ,我们先看看正转。
AccountController自己来实例化需要的依赖。
大师说,这样不好。你不应该自己创建它,而是应该由你的调用者给你。于是你通过构造函数让外界把这两个依赖传给你。
把依赖的创建丢给其它人,自己只负责使用,其它人丢给你依赖的这个过程理解为注入。
1.3 为什么要反转?
为了在业务变化的时候尽少改动代码可能造成的问题。
比如我们现在要把从EF中去验证登录改为从Redis去读,于是我们加了一个 RedisLoginService。这个时候我们只需要在原来注入的地方改一下就可以了。
// 用Redis来替换原来的EF登录 var controller = new AccountController(new RedisLoginService()); controller.Login(userName, password);
1.4 何为容器
上面我们在使用AccountController的时候,我们自己通过代码创建了一个ILoggingServce的实例。想象一下,一个系统中如果有100个这样的地方,我们是不是要在100个地方做这样的事情? 控制是反转了,依赖的创建也移交到了外部。现在的问题是依赖太多,我们需要一个地方统一管理系统中所有的依赖,容器诞生了。
容器负责两件事情:
绑定服务与实例之间的关系
获取实例,并对实例进行管理(创建与销毁)
二、.NET Core DI
2.1 实例的注册
前面讲清楚DI和Ioc的关键概念之后,我们先来看看在控制台中对.NET Core DI的应用。在.NET Core中DI的核心分为两个组件:IServiceCollection和 IServiceProvider。
IServiceCollection 负责注册
IServiceProvider 负责提供实例
通过默认的 ServiceCollection(在Microsoft.Extensions.DependencyInjection命名空间下)有三个方法:
这三个方法都是将我们的实例注册进去,只不过实例的生命周期不一样。什么时候生命周期我们下一节接着讲。
ServiceCollection的默认实现是提供一个ServiceDescriptor的List
我们上面的AddTransient、AddSignletone和Scoped方法是IServiceCollection的扩展方法, 都是往这个List里面添加ServiceDescriptor。
2.2 实例的生命周期之单例
我们上面看到了,.NET Core DI 为我们提供的实例生命周其包括三种:
Transient: 每一次GetService都会创建一个新的实例
Scoped: 在同一个Scope内只初始化一个实例 ,可以理解为( 每一个request级别只创建一个实例,同一个http request会在一个 scope内)
Singleton :整个应用程序生命周期以内只创建一个实例
对应了Microsoft.Extensions.DependencyInjection.ServiceLifetime的三个枚举值
为了大家能够更好的理解这个生命周期的概念我们做一个测试:
定义一个最基本的IOperation里面有一个 OperationId的属性,IOperationSingleton也是一样,只不过是另外一个接口。
我们的 Operation实现很简单,可以在构造函数中传入一个Guid进行赋值,如果没有的话则自已New一个 Guid。
在程序内我们可以多次调用ServiceProvider的GetService方法,获取到的都是同一个实例。
我们对IOperationSingleton注册了三次,最后获取两次,大家要注意到我们获取到的始终都是我们最后一次注册的那个给了一个Guid的实例,前面的会被覆盖。
2.3 实例生命周期之Tranisent
这次我们获取到的IOperationTransient为两个不同的实例。
2.4 实例生命周期之Scoped
.NET Core人IServiceProvider提供CreateScope产生一个新的ServiceProvider范围,在这个范围下的Scope标注的实例将只会是同一个实例。换句话来说:用Scope注册的对象,在同一个ServiceProvider的 Scope下相当于单例。
同样我们先分别注册IOperationScoped、IOperationTransient和IOperationSingletone 这三个实例,用对应的Scoped、Transient、和Singleton生命周期。
接下来我们用ServiceProvider.CreateScope方法创建一个Scope
接下来
scope1: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient1: fb35f570-713e-43fc-854c-972eed2fae52,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient2: 2766a1ee-766f-4116-8a48-3e569de54259,
singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
如果再创建一个新的Scope运行,
scope1: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient1: 035d8bfc-c516-44a7-94a5-3720bd39ce57,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient2: 74c37151-6497-4223-b558-a4ffc1897d57,
singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
大家注意到上面我们一共得到了 4个Transient实例,2个Scope实例,1个Singleton实例。
这有什么用?
如果在Mvc中用过Autofac的InstancePerRequest的同学就知道,有一些对象在一个请求跨越多个Action或者多个Service、Repository的时候,比如最常用的DBContext它可以是一个实例。即能减少实例初始化的消耗,还能实现跨Service事务的功能。(注:在ASP.NET Core中所有用到EF的Service 都需要注册成Scoped )
而实现这种功能的方法就是在整个reqeust请求的生命周期以内共用了一个Scope。
三、DI在ASP.NET Core中的应用
3.1在Startup类中初始化
ASP.NET Core可以在Startup.cs的 ConfigureService中配置DI,大家看到 IServiceCollection这个参数应该就比较熟悉了。
ASP.NET Core的一些组件已经提供了一些实例的绑定,像AddMvc就是Mvc Middleware在 IServiceCollection上添加的扩展方法。
3.2 Controller中使用
一般可以通过构造函数或者属性来实现注入,但是官方推荐是通过构造函数。这也是所谓的显式依赖。
我们只要在控制器的构造函数里面写了这个参数,ServiceProvider就会帮我们注入进来。这一步是在Mvc初始化控制器的时候完成的,我们后面再介绍到Mvc的时候会往细里讲。
3.3 View中使用
在View中需要用@inject 再声明一下,起一个别名。
3.4 通过 HttpContext来获取实例
HttpContext下有一个RequestedService同样可以用来获取实例对象,不过这种方法一般不推荐。同时要注意GetService<>这是个范型方法,默认如果没有添加Microsoft.Extension.DependencyInjection的using,是不用调用这个方法的。
四、如何替换其它的Ioc容器
Autofac也是不错的选择,但我们首先要搞清楚为什么要替换掉默认的 DI容器?,替换之后有什么影响?.NET Core默认的实现对于一些小型的项目完全够用,甚至大型项目麻烦点也能用,但是会有些麻烦,原因在于只提供了最基本的AddXXXX方法来绑定实例关系,需要一个一个的添加。如果项目可能要添加好几百行这样的方法。
如果熟悉Autofac的同学可能会这下面这样的代码有映象。
这会给我们的初始化带来一些便利性,我们来看看如何替换Autofac到ASP.NET Core。我们只需要把Startup类里面的 ConfigureService的 返回值从 void改为 IServiceProvider即可。而返回的则是一个AutoServiceProvider。
4.1 有何变化
其中很大的一个变化在于,Autofac 原来的一个生命周期InstancePerRequest,将不再有效。正如我们前面所说的,整个request的生命周期被ASP.NET Core管理了,所以Autofac的这个将不再有效。我们可以使用 InstancePerLifetimeScope ,同样是有用的,对应了我们ASP.NET Core DI 里面的Scoped。
core控制器属性注入的用处_理解 ASP.NET Core 依赖注入相关推荐
- core控制器属性注入的用处_了解ASP.NET Core 依赖注入,看这篇就够了
DI在.NET Core里面被提到了一个非常重要的位置, 这篇文章主要再给大家普及一下关于依赖注入的概念,身边有工作六七年的同事还个东西搞不清楚.另外再介绍一下.NET Core的DI实现以及对实例 ...
- asp绑定gridview属性_理解ASP.NET Core中的模型验证
当MVC执行模型绑定后,为了验证绑定为参数提供的值是否符合预期,还需要进行模型验证. 一.理解模型验证 模型验证是指模型绑定后对Action参数进行验证的过程.它会根据事先定义的规则对参数的值进行验证 ...
- 如何理解控制反转和依赖注入
如何理解控制反转和依赖注入 文章目录 如何理解控制反转和依赖注入 前言 一.什么是控制反转 1.何为依赖关系 2.进行控制反转的前的一些准备 3.控制反转的简单实现 2.1:实现代码 二.什么是依赖注 ...
- asp编程工具_使用ASP.NET Core构建RESTful API的技术指南
译者荐语:利用周末的时间,本人拜读了长沙.NET技术社区翻译的技术文章<微软RESTFul API指南>,打算按照步骤写一个完整的教程,后来无意中看到了这篇文章,与我要写的主题有不少相似之 ...
- 转: 理解AngularJS中的依赖注入
理解AngularJS中的依赖注入 AngularJS中的依赖注入非常的有用,它同时也是我们能够轻松对组件进行测试的关键所在.在本文中我们将会解释AngularJS依赖注入系统是如何运行的. Prov ...
- 理解AngularJS中的依赖注入
作者 CraftsCoder 冷月无声 - 博客频道 - CSDN.NET http://blog.csdn.net/jaytalent/article/details/50986402 本文结合一些 ...
- asp向不同的用户发送信息_【asp.net core 系列】 1 带你了解一下asp.net core
0. 前言 这是一个新的系列,名字是<http://ASP.NET Core 入门到实战>.这个系列主讲http://ASP.NET Core MVC,辅助一些前端的基础知识(能用来实现我 ...
- 2022年8月10日:使用 ASP.NET Core 为初学者构建 Web 应用程序--使用 ASP.NET Core 创建 Web UI(没看懂需要再看一遍)
ASP.NET Core 支持使用名为 Razor 的本地模板化引擎创建网页. 本模块介绍了如何使用 Razor 和 ASP.NET Core 创建网页. 简介 通过在首选终端中运行以下命令,确保已安 ...
- ASP.NET Core 2.0 Web API项目升级到ASP.NET Core 3.0概要笔记
本文结构 先决条件 升级目标框架(Target Framework)的版本 过时的IHostingEnvironment与IApplicationLifetime对象 Endpoint Routing ...
最新文章
- SQL SERVER 架构管理
- 深度丨深度强化学习研究的短期悲观与长期乐观(长文)
- [javaSE] 网络编程(URLConnection)
- 企业网络推广中关键词“出镜率”高会影响企业网络推广吗?
- Chapter4 Java流程控制之选择结构
- ajax实现两个aspx跳转,请问ajax执行成功后可以跳转到另一个页面吗?
- 容器编排技术 -- Kubernetes StatefulSets
- 记一次newCachedThreadPool造成的导入导出事故
- samba 服务器手动挂载自动挂载
- WebView无法放大缩小解决方案
- matlab 可视化(specifier)
- 微信小程序“淘淘猜成语”开发教程(该成语接龙已上线,功能齐全)
- 江苏大学计算机学院换届,关于计算机学院各支部选举结果的批复
- 计算机系微电子专业大学排名,2021年微电子科学与工程专业大学排名
- Web安全研究(一)
- 高中数学联赛二试怎么准备
- [深度学习] 使用LSTM实现股票预测
- python爬取b站搜索结果_Python爬虫实例:爬取猫眼电影——破解字体反爬,Python爬虫实例:爬取B站《工作细胞》短评——异步加载信息的爬取,Python爬虫实例:爬取豆瓣Top250...
- 238. 银河英雄传说(并查集,扩展域)
- c/c++下取消结构体字节对齐方法
热门文章
- 六逻辑层次 职业规划案例_我如何在六个月内改变职业并找到了一名开发人员...
- 使用Minions解释JavaScript回调
- C++ 学习笔记---零散的基础知识
- Python监听键盘和鼠标事件,并发送内容至邮箱!
- 给人工智能新手,两份不同阶段的资料
- Oracle数据库启动以及说明
- C# JsonHelper
- gridview 实现排序 (在不是使用sqlDataSource控件,而在后台编码绑定gridview时,指定那个字段排序时使用。本例用了单层结构,可修改后应用于多层)
- Python《第一次爬虫遭遇反盗链(上)》
- 《Pytorch - RNN模型》