依赖注入在 dotnet core 中实现与使用:1 基本概念


关于 Microsoft Extension: DependencyInjection 的介绍已经很多,但是多数偏重于实现原理和一些特定的实现场景。作为 dotnet core 的核心基石,这里准备全面介绍它的概念、原理和使用。

这里首先介绍概念部分。

1. 概念

该项目在 GitHub 的地址:https://github.com/aspnet/Extensions/tree/master/src/DependencyInjection

Microsoft.Extensions.DependencyInjection 是微软对依赖倒置原则的实现。作为 ASP.NET Core 的基石,DependencyInjection 贯穿了整个项目的方方面面,掌握它的使用方式和原理,不仅对理解 ASP.NET Core 有重要意义,也有助于将它运用到其它项目的开发中,帮助提供项目开发的效率和质量。

1.1 问题的场景

在软件开发中,项目通常有多个不同的模块组成,模块之间存在依赖关系。例如,我们考虑一个简化的场景,我们有 3 个关于用户的类:

  1. AccountController,提供用户交互界面

  2. UserService,提供用户管理的业务逻辑

  3. UserRepository,提供用户管理的数据访问

AccountController 内部需要使用 UserService 的实例 来管理用户,而 UserService 内部则需要基于 UserRepository 来提供数据访问。我们称它们之间存在依赖关系。或者表达为,AccountController 依赖于 UserService ,而 UserService 依赖于 UserRepository 。而依赖注入就是用来帮助我们实现依赖管理的有力工具。

1.2 依赖倒置原则 DIP

依赖倒置原则是广为人知的设计原则之一,该原则是实现软件项目中模块的解耦的理论基石。

原则的定义如下:

High level modules should not depend upon low level modules,Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstracts.

翻译过来为:

  • 高层模块不应该依赖低层模块,两者都应该依赖抽象

  • 抽象不应该依赖细节

  • 细节应该依赖抽象

在没有实现依赖倒置原则的时候,我们通过在 AccountController 类中自己通过 new 关键字来创建其依赖的 UserService 对象实例,

public class AccountController {

private readonly UserService _userService;
public AccountController() {
this._userService = new UserService();
}
}

这导致了两个类之间的紧耦合,AccountController 与 UserService 被绑定到一起, 在每次创建 AccountController 的时候,一定会创建一个 UserService 的对象实例,而如果我们需要测试 AccountController 的时候,也就不得不考虑 UserService,这样一级一级的依赖下来,UserService 又会依赖 UserRepository,就会发现项目中的类都被绑定在一起, 紧密耦合,难以分拆。

基于依赖倒置的原则,通常会考虑通过接口进行隔离。例如,我们可能会定义一个用户服务的接口:

public interface IUserService
{
}

而用户服务则会实现该接口

public class UserService : IUserService {
}

在 AccountController 类中,则改变成了基于接口来使用 UserService

public class AccountController {

private readonly IUserService _userService;
public AccountController() {
this._userService = new UserService();
}
}

虽然在 HomeController 内部,我们可以基于接口编程了,但是这样的作法并没有解决自己通过 new 来获取 UserService 对象实例的问题。

1.3 控制反转 IoC

IoC是一种著名的实现 DIP 的设计模式。

它的核心思想是:在需要对象实例的时候,不要总考虑自己通过 new 来创建对象,放下依赖对象的创建过程,而是把创建对象的工作交给别人来负责,这个别人我们通常称为 容器 (Container) 或者 服务提供者 (ServiceProvider), 我们后面使用这个 ServiceProvider 来指代它,

在需要对象实例的时候,从这个 ServiceProvider 中获取。

下面是一个广泛使用的示意图。拿总是要拿的,但是从 自己穿上 变成了 给你穿上

640?wx_fmt=other

在控制反转中,引入了一个 ServiceProvider 来帮助我们获得对象实例

1.4 依赖注入 DI (DependencyInjection)

DI 是 IoC 模式的一种实现。

《Expert one on one J2EE Development without EJB》第 6 章

IoC 的主要实现方式有两种:依赖查找,依赖注入 (p128)

依赖注入是一种更可取的方式。(p130)

Martin Fowler 的原文:

As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.

大意是:

已经存在某种模式,该模式被称为 IoC,但 IoC 太过广义,任何框架都 IoC,为了让表意更明确,决定采用 DI 来精确指称它。

DI 的实现有多种,我们这里介绍的是微软官方在 Microsoft Extension 中内置提供的 DependencyInjection。它是 IoC 中一种实现,ASP.NET Core 的整个核心基于它来实现。同时,我们也可以在其它项目中使用,以实现对依赖倒置原则的支持。

2. DependencyInjection 中的基本概念

2.1 服务描述集合 ServiceCollection

在微软的 DI 实现中,所有的服务需要首先注册到一个公共的服务描述集合中,该集合对于整个 DI 来说,只需要一个,服务只需要在此集合中注册一次,即可在以后通过 DI 提供给使用者。

该集合的接口定义为 IServiceCollection,可以看出来,它其实就是一个用来保存服务注册的集合。

public interface IServiceCollection : IList<ServiceDescriptor>, ICollection<ServiceDescriptor>, IEnumerable<ServiceDescriptor>, IEnumerable
{
}

系统默认已经实现了一个对 IServiceCollection 的实现,名为 ServiceCollection。在 ASP.NET Core 中,内部会创建该对象的实例,我们也可以在其它项目中,自己来创建它,很简单,直接 new 出来就可以使用了。

IServiceCollection services = new ServiceCollection ();

2.2 服务 Service

在 DI 语境中,服务特指通过 DI 容器管理的对象实例。这个服务并不一定被称为 **Service,而是可以是任何由 DI 所管理的对象,只是在 DI 这个语境下,我们将其统称为服务。

服务是我们自己定义的,例如前面提到的 AccountController 和 UserService 等等。

我们通过 DI 来获得服务对象实例,管理服务对象的生命周期,对于存在复杂依赖关系的对象, DI 还负责管理这些实例之间的依赖关系。

服务必须首先注册在 DI 中才能使用,但是,注册前需要首先考虑和决定服务的生命周期。

2.3 服务的生命周期

服务对象实例有着不同类型的生命周期。有些对象的生命周期与应用程序相同,在应用程序启动时创建,在应用程序退出时才需要释放。例如我们的数据访问对象实例。有些对象仅仅在当前方法中使用,在方法调用结束之后就应该销毁。服务的生命周期管理用来管理这些需求。

DI 支持三种类型的生命周期:

  1. Singleton,单例,在当前应用程序环境下只有一个实例。例如数据访问服务对象实例。

  2. Scoped,限定范围,一旦退出此范围,在此范围内的服务对象都需要销毁。例如 Web 开发中的请求对象实例。

  3. Transient,瞬态,一次性使用,每次从 DI 中获取,都返回一个新的实例。

Microsoft.Extensions.DependencyInjection.ServiceLifetime

public enum ServiceLifetime
{
Singleton,
Scoped,
Transient
}

服务的生命周期在注册服务的时候确定。在使用的时候,直接获取实例,不再指定服务的生命周期。微软提供了多种扩展方法来便于在注册服务时指定服务的生命周期。例如下面是通过泛型方式来指定单例模式的生命周期。

// 基于接口的注册
services.AddSingleton<IUserService, UserService>();

2.4 服务提供者 ServiceProvider

在需要使用服务对象实例的时候,不是从注册服务的集合中获取,而是需要通过服务提供者来获取,这个服务提供者显然需要来自注册服务的集合。服务提供者的接口定义为 IServiceProvider,它是 .net 的基础定义之一,不是在该 DI 框架中定义的。

public interface IServiceProvider
{
object GetService(Type serviceType);
}

DI 中的 ServiceCollectionContainerBuilderExtensions 扩展了 IServiceCollection,提供了获得这个服务提供者 ServiceProvider 的支持。

public static ServiceProvider BuildServiceProvider(this IServiceCollection services)
{
return BuildServiceProvider(services, ServiceProviderOptions.Default);
}

所以,我们通常使用该方法来获取并使用它。

// 创建注册服务的容器
IServiceCollection services = new ServiceCollection ();
// 注册服务,这里指定了单例
services.AddSingleton<IUserService, UserService>();
// 通过容器获得服务提供者
IServiceProvider provider = services.BuildServiceProvider ();

2.5 获取服务对象实例

通过服务提供者来手动获取服务对象实例。通过注册的服务类型,直接调用 GetService 方法即可。

例如,前面我们注册了服务类型 IUserService 的实现类型是 UserService ,那么,可以通过此类型来获取实际实现该接口的对象实例。

// 创建注册服务的容器
IServiceCollection services = new ServiceCollection ();
// 注册服务,这里指定了单例
services.AddSingleton<IUserService, UserService>();
// 通过容器获得服务提供者
IServiceProvider provider = services.BuildServiceProvider ();
// 通过接口获取服务对象实例
IUserService instance = provider.GetService<IUserService> ();

看起来,更加复杂了。在实际使用中,我们很少使用这样的方式来使用 DI,后面我们再深入讨论具体的使用过程。

原文链接:https://www.cnblogs.com/haogj/p/11370314.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314331.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LOJ#572】Misaka Network 与求和(莫比乌斯反演/杜教筛/min_25筛)

【LOJ#572】Misaka Network 与求和 https://www.cnblogs.com/cjyyb/p/10170630.html 看到次大质因子就可以想到是min_25筛了&#xff0c;然后只需要做莫比乌斯反演&#xff0c;然后预处理整除分块点的前缀和&#xff0c;然后再结合杜教筛即可。

软件设计的第一性原理:结构化抽象

软件设计的第一性原理&#xff0c;是结构化抽象。术生于道&#xff0c;技术生于原理。引语所谓的第一性原理&#xff0c;就是无论使用什么方法论&#xff0c;都无法绕过的那最最基础的部分。无论是 DDD 设计&#xff0c;还是面向模式的架构设计&#xff0c;或 微服务架构&#…

基于.NetCore结合docker-compose实践Gitlab-CI/CD 排坑指南

引言看过docker-compose真香的园友可能留意到当时是【把部署dll文件拷贝到生产机器】&#xff0c;即时打包成镜像并启动容器&#xff0c;并没有完成CI/CD。经过长时间实操验证&#xff0c;终于完成基于Gitlab的CI/CD实践&#xff0c;本次实践的坑位很多&#xff0c; 实操过程尽…

.NET Core很酷,你不得不知

我一直回想我的第一篇博文&#xff0c;那是关于多个服务的服务器平台的详细教程&#xff0c;它使用 GitLab CI 在 AWS 上&#xff0c;当时使用单个命令行进行部署&#xff0c; 至今回想&#xff0c;令人感觉很酷。前几天&#xff0c;我偶然听说一些软件公司的 HR 在招聘原则上拒…

程序员修神之路--高并发系统设计负载均衡架构

点击上方“蓝字”关注&#xff0c;酷爽一夏菜菜哥&#xff0c;上次你给我讲的分库分表策略对我帮助很大有帮助就好&#xff0c;上次请我的咖啡也很好喝~呵呵&#xff0c;不过随着访问量的不断加大&#xff0c;网站我又加了nginx做负载均衡好呀&#xff0c;看来要进阶高级工程师…

【学习笔记】Docker - 01. Docker是啥

我只是把之前的学习笔记整理一下&#xff0c;贴到这里&#xff0c;可能会显得比较凌乱。。。1.1 啥是Docker?Docker 是一个开源项目&#xff0c;它被用来做构建、打包和运行程序。它是一个命令行程序&#xff0c;一个后台进程&#xff0c;也是一组使用逻辑方法来解决常见软件问…

使用 .NET CORE 创建 项目模板,模板项目,Template

场景&#xff1a;日常工作中&#xff0c;你可能会碰到需要新建一个全新的解决方案的情况&#xff08;如公司新起了一个新项目&#xff0c;需要有全新配套的后台程序&#xff09;&#xff0c;如果公司内部基础框架较多、解决方案需要DDD模式等&#xff0c;那么从新起项目到各种依…

谈谈surging 微服务引擎 2.0的链路跟踪和其它新增功能

一、前言surging是基于.NET CORE 服务引擎。初始版本诞生于2017年6月份&#xff0c;经过NCC社区二年的孵化&#xff0c;2.0版本将在2019年08月28日进行发布&#xff0c;经历二年的发展&#xff0c;已经全部攘括了微服务架构的技术栈&#xff0c;覆盖了从服务注册、服务发现、中…

奇淫巧技-Flutter调用C#

前言众所周知&#xff0c;Xamarin应该是.net下的跨平台开发工具。2016年之前还处于收费状态&#xff0c;后被微软收购后开源。但似乎有个现象&#xff0c;开源后的Xamarin发展似乎有些停滞&#xff0c;而且维护Xamarin的团队又很固执不愿变通。社区多次建议UI层应该统一绘图引擎…

.NET World——gPRC概览

官方的定义&#xff1a;gRPC is a modern open source high performance RPC framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authen…

推荐高质量的公众号,值得跟进学习!

为大家推荐几个高质量的公众号&#xff1a;当你迷茫的时候刷刷这些大公司的牛人所运营的公众号&#xff0c;就可以知道自己的不足&#xff0c;不是仅仅局限于.NET技术之下&#xff0c;通过他们扩展我们的知识宽度&#xff0c;我们可以一起来学习。人工智能爱好者社区专注人工智…

.net core redis的全套操作

Redis支持五种数据类型&#xff1a;string&#xff08;字符串&#xff09;&#xff0c;hash&#xff08;哈希&#xff09;&#xff0c;list&#xff08;列表&#xff09;&#xff0c;set&#xff08;集合&#xff09;及zset(sorted set&#xff1a;有序集合)。Redis支持主从同步…

Stack Overflow引入CROKAGE,搜问题不用再东拼西凑

许多开发者使用 Stack Overflow 搜索开发中遇到的问题&#xff0c;有时候需要查询的结果中有通俗的讲解&#xff0c;而且最好还能够带上代码 demo&#xff0c;但是两者同时很完美地满足要求还是比较困难的。不过最近 Stack Overflow 官方博客上介绍了一种智能化的技术&#xff…

使用Kubectl部署应用

目录 使用Kubectl部署应用 Kubectl部署流程 部署一个简单的Demo网站 使用Kubectl部署应用一旦运行了Kubernetes集群&#xff0c;就可以在其上部署容器化应用程序。因此在开始之前&#xff0c;我们需要先确保集群已经准备就绪&#xff0c;无论是使用Minikube还是kubeadm创建的集…

Docker系列之.NET Core入门(三)

在Docker生态系统中除了上一节所讲解的基本概念&#xff0c;还有其他专业术语&#xff0c;本文我们将一笔带过&#xff0c;同时会开始陆续进入到在.NET Core中使用Docker。专业术语Docker Engine&#xff08;Docker引擎&#xff09;&#xff1a;客户端 - 服务器应用程序。Docke…

通过Blazor使用C#开发SPA单页面应用程序(4) - Ant Design

通过Blazor使用C#开发SPA单页面应用程序(1)通过Blazor使用C#开发SPA单页面应用程序(2)通过Blazor使用C#开发SPA单页面应用程序(3)前面学习了Blazor的特点、环境搭建及基础知识&#xff0c;现在我们尝试的做个实际的组件。Ant Design是蚂蚁金服是基于Ant Design设计体系的 UI 组…

Mercurial黄昏,Bitbucket宣布全面转向Git

源代码托管平台 Bitbucket 宣布将逐步放弃对版本控制系统 Mercurial 的支持。Bitbucket 推出于 2008 年&#xff0c;当时集中式版本控制是比较普遍的&#xff0c;Mercurial 是其中的典型代表&#xff0c;但是当前 Git 才是主流&#xff0c;它已经成为了大部分开源项目的首选版本…

使用 Azure DevTest Lab 搭建云端开发测试环境

点击上方蓝字关注“汪宇杰博客”导语程序员和测试工程师经常需要自己搭环境用于开发和测试目的&#xff0c;这些机器可能只会使用很短一段时间。通常我们会在本机使用 Hyper-V、VMWare 之类的虚拟机产品&#xff0c;或者使用企业IT管理员分配的虚拟机去完成这项工作。然而安装配…

dotNET Core WebAPI 统一处理(返回值、参数验证、异常)

现在 Web 开发比较流行前后端分离现在 Web 开发比较流行前后端分离&#xff0c;我们的产品也是一样&#xff0c;前端使用Vue&#xff0c;后端使用 dotNet Core WebAPI &#xff0c;在写 API 的过程中有很多地方需要统一处理文档参数验证返回值异常处理本文就说说 API 的统一处理…

.net测试篇之单元测试/集成测试神器Autofixture

autofixture简介有了单元测试框架加上Moq(后面我们会用单独章节来介绍moq),可以说测试问题基上都能搞定了.然而有了AutoFixture对单元测试来说可以说是如虎添翼,AutoFixture并且它能与moq,rhinomock等框架结合,对单元测试带来的便捷性,可维护性和扩展性更是难以言表,只有用用了…