dotNET Core 3.X 依赖注入

如果说在之前的 dotNET 版本中,依赖注入还是个比较新鲜的东西,那么在 dotNET Core 中已经是随处可见了,可以说整个 dotNET Core 的框架是构建在依赖注入框架之上。本文说说对 dotNET Core 中依赖注入的理解。

什么是依赖

在面向对象的语言中,所说的依赖通常指类与类之间的关系,比如有个用户类 User 和日志类 Log , 在 User 类中需要记录日志,就需要引入日志类 Log,这样 User 类就对 Log 类产生了依赖,代码如下:

public class User
{private Log _log=new Log();public string GetUserName(){_log.Write("获取用户名称");return "oec2003";}
}
public class Log
{public void Write(string message){Console.WriteLine(message);}
}

或者直接在类的方法中对其他类进行了依赖,如下:

public class Dept
{public string GetDeptNameByUserId(string userId){return "开发部";}
}
public string GetUserFullName(string userId)
{Dept dept=new Dept();return $"oec2003({dept.GetDeptNameByUserId(userId)})";
}

这样的类与类之间的直接依赖有如下几个问题:

  • 要换一种 Log 的实现方式,所有引用的地方都要进行修改;

  • 如果整个项目中到处都是这种类与类之间的强关联,代码维护会变得非常困难;

  • 对单元测试不友好。

要解决上面的问题,需要将依赖的类抽象成接口,不直接依赖具体的实现类类,而是依赖接口,这就是面向对象的六大原则中的依赖倒置原则:高层模块不应该依赖于底层模块,二者都应该依赖于抽象;抽象不应该依赖于实现细节,实现细节应该依赖于抽象。

User 类调整后的代码如下:

public interface ILog
{void Write(string message);
}
public class Log:ILog
{public void Write(string message){Console.WriteLine(message);}
}
public class User
{private ILog _log;public User(ILog log){_log = log;}public string GetUserName(){_log.Write("获取用户名称");return "oec2003";}
}
  • 创建了 ILog 接口;

  • User 类调整为对 ILog 的依赖;

  • 在 User 中类添加构造函数,在构造函数中传入接口 ILog 的实例。

那么构造函数中的实例什么时候创建呢?这时就需要用到注入了。

什么是注入?

在上面示例中,注入就是在某个时机,将 ILog 的实例传递到 User 类的构造函数中,而 User 类中根本就不关心 ILog 的实现。在 dotNET Core 中提供了一个内置的服务容器 IServiceProvider,然后在 Startup 类的 ConfigureServices  方法中进行注册,注册代码如下:

public void ConfigureServices(IServiceCollection services)
{services.AddSingleton<IUser, User>();services.AddSingleton<ILog, Log>();services.AddControllers();
}
  • 上面代码中是以单例的模式进行注册;

  • 将原来在 User 类中的对 Log 类的直接依赖,转移到了 ConfigureServices 方法中,这便是控制反转(IoC)了,Log 类采用什么实现,不在 User 类中来控制,而是转移到了框架层面。

借助框架的依赖注入,相比较我们自己在类中互相关联依赖地去创建对象有以下好处:

  • 方便管理类之间的依赖,对我们使用面向对象的设计原则有帮助;

  • 代码有更好的维护性和扩展性;

  • 可以方便管理各个对象的生命周期。

依赖注入核心类型

在 dotNET Core 中使用内置的依赖注入需要引入 using Microsoft.Extensions.DependencyInjection;i 命名空间。相关的几个核心类型如下:

  • IServiceCollection:利用此类的扩展方法进行服务的注册;

  • IServiceProvider:由 IServiceCollection 创建的依赖注入容器体现为,IServiceProvider 接口;

  • ServiceDescriptor:具体注册的服务的描述,IServiceProvider 就是通过这个描述来构建我们需要的服务实例;

  • ServiceLifetime:一个服务生命周期的枚举,有 Singleton、Scoped、Transient 三种类型。

服务注册的生命周期

服务注册的生命周期有三种:

  • Singleton:单例模式,创建在全局的 IServiceProvider 的根容器上;

  • Scoped:范围模式,用 Scope 注册的对象,在同一个 ServiceProvider 的 Scope 下相当于单例;

  • Transient:瞬时模式,每次从容器获取对象时都是得到的一个全新的对象。

下面用一个示例来看下这三种不同生命周期的区别

1、创建分别代表不同生命周期的接口和类,代码如下:

public interface ISingletonService{}
public interface IScopedService{}
public interface ITransientService{}public class SingletonService:ISingletonService{}
public class ScopedService:IScopedService{}
public class TransientService:ITransientService{} 

2、在 Controller 中创建接口方法:

[HttpGet]
public void GetService([FromServices]ISingletonService singleton1,[FromServices]ISingletonService singleton2,[FromServices]IScopedService scoped1,[FromServices]IScopedService scoped2,[FromServices]ITransientService transient1,[FromServices]ITransientService transient2)
{System.Console.WriteLine($"singleton1:{singleton1.GetHashCode()}");System.Console.WriteLine($"singleton2:{singleton2.GetHashCode()}");System.Console.WriteLine($"scoped1:{scoped1.GetHashCode()}");System.Console.WriteLine($"scoped2:{scoped2.GetHashCode()}");System.Console.WriteLine($"transient1:{transient1.GetHashCode()}");System.Console.WriteLine($"transient2:{transient2.GetHashCode()}");
}

3、连续调用两次该接口,输入如下图:

测试示例中每个不同生命周期的对象都通过 FromServices 的方式注入了两次,分析结果如下:

  • Singleton:两次请求的四个对象都相同;

  • Scoped:相同请求的两个对象是一致,重新请求会生成新的对象;

  • Transient:两次请求的四个对象都不相同,每次都构建新的对象。

总结

  • 依赖注入的目的是为了解耦;

  • 不依赖于具体类,而是依赖抽象类或者接口,这叫依赖倒置;

  • 把服务的注册和实例化的工作交给 dotNET Core 框架,而不是在具体实现类中处理,这个叫控制反转即IoC (Inversion of Control)

就先写到这儿了,dotNET Core 框架本身的依赖注入功能已经比较强大,但还是有些功能不能满足,需要引入第三方的注入框架,关于如何引入第三方依赖注入框架以及为什么要用第三方依赖注入框架,后面单独开篇写。

示例代码:https://github.com/oec2003/DotNetCoreThreeAPIDemo/tree/master/InjectDemo

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

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

相关文章

创建型模式——抽象工厂模式

一、 实验目的与要求 1.练习使用工厂模式。设计相关的模拟场景并进行实施&#xff0c;验证模式特性&#xff0c;掌握其优缺点。 2.实验结束后&#xff0c;对相关内容进行总结。 二、实验内容 1.模式应用场景说明 手机CPU生产工厂&#xff1a;在一个工厂里面&#xff0c;有A…

[JavaWeb-MySQL]多表查询概述

多表查询&#xff1a; * 查询语法&#xff1a;select列名列表from表名列表where.... * 准备sql# 创建部门表CREATE TABLE dept(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20));INSERT INTO dept (NAME) VALUES (开发部),(市场部),(财务部);# 创建员工表CREATE TABLE em…

【壹刊】Azure AD(三)Azure资源的托管标识

一&#xff0c;引言来个惯例&#xff0c;吹水&#xff01;????????????????????前一周因为考试&#xff0c;还有个人的私事&#xff0c;一下子差点颓废了。想了想&#xff0c;写博客这种的东西还是得坚持&#xff0c;再忙&#xff0c;也要检查。要养成一种…

[JavaWeb-JDBC]JDBC概念

JDBC&#xff1a; 1. 概念&#xff1a;Java DataBase Connectivity Java 数据库连接&#xff0c; Java语言操作数据库JDBC本质&#xff1a;其实是官方&#xff08;sun公司&#xff09;定义的一套操作所有关系型数据库的规则&#xff0c;即接口。各个数据库厂商去实现这套接口…

创建型模式——建造者模式

一、 实验目的与要求 1.练习使用工厂模式。设计相关的模拟场景并进行实施&#xff0c;验证模式特性&#xff0c;掌握其优缺点。 2.实验结束后&#xff0c;对相关内容进行总结。 二、实验内容 1.模式应用场景说明 Decis创建一个获取多套餐信息&#xff0c;包含A套餐&#xf…

android studio模拟器的安装与使用

来回弄了好几遍&#xff0c;网上也都搜过下载过很多版本&#xff0c;其中夜神模拟器是真的方便&#xff0c;也好用&#xff0c;棒极了&#xff01;那么我就来分享一下&#xff1a; 第一&#xff0c;肯定是下载啦 下载链接&#xff1a;夜神模拟器官方 接着就是连接了&#xff0c…

如何训练解决问题的能力?

作为程序员&#xff0c;技术能力固然很重要&#xff0c;但平时除了提升技术能力也别忽略了其它方面的能力。你可以写一辈子代码&#xff0c;但你不能一辈子只写代码。当你的技术能力足以使你在公司站稳脚跟时&#xff0c;你可以停下来锻炼自己的管理能力&#xff0c;比如职场中…

PS照片换底色

因为写简历嘛&#xff0c;手边没有白色底的照片&#xff0c;就用ps换了个底色&#xff0c;记录一下&#xff0c;下次可能还要用。这里我用幂幂的照片来代替。 打开ps&#xff0c;点击文件&#xff0c;点击打开&#xff0c;找到你需要处理的照片。 -点击旁边的对象选择工具&…

小心 HttpClient 中的 FormUrlEncodeContent 的 bug

小心 HttpClient 中的 FormUrlEncodeContent 的 bugIntro最近发现活动室预约项目里的上传图片有时候会有问题&#xff0c;周末找时间测试了一下&#xff0c;发现小图片的上传没问题&#xff0c;大图片上传会有问题&#xff0c;而且异常信息还很奇怪&#xff0c;System.UriForma…

IDEA导入MySQL的jdbc驱动出现“java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver”

目录 一、一般的解决思路 1、JDBC下载链接 2、选择下载内容&#xff0c;并进行下载 3、将驱动导入java项目 二、依然导入驱动失败怎么办 当我们在idea中使用java操作mysql数据库时会出现&#xff1a; Exception in thread "main" java.lang.ClassNotFoundExce…

Android程序设计基础-设计布局之伪今日头条主界面

一、 实验目的 &#xff08;1&#xff09; 掌握Andriod Studio的基本使用方法&#xff1b; &#xff08;2&#xff09; 掌握Andriod Studio中常用的控件及其使用方法&#xff1b; 二、实验内容 &#xff08;1&#xff09;使用Android Studio编写任意一个Android程序并运行&a…

基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一)

系列文章使用 abp cli 搭建项目给项目瘦身&#xff0c;让它跑起来完善与美化&#xff0c;Swagger登场数据访问和代码优先自定义仓储之增删改查统一规范API&#xff0c;包装返回模型再说Swagger&#xff0c;分组、描述、小绿锁接入GitHub&#xff0c;用JWT保护你的API异常处理和…

MySql轻松入门系列——第一站 从源码角度轻松认识mysql整体框架图

一&#xff1a;背景1. 讲故事最近看各大技术社区&#xff0c;不管是知乎&#xff0c;掘金&#xff0c;博客园&#xff0c;csdn基本上看不到有小伙伴分享sqlserver类的文章&#xff0c;看样子这些年sqlserver没落了&#xff0c;已经后继无人了&#xff0c;再写sqlserver是不可能…

嫌弃俄罗斯的火箭报价太黑!马斯克自己造火箭!SpaceX首次载人发射任务成功!太牛了!...

当你仰望天空&#xff0c;可曾想象到&#xff0c;距地8公里的平流层每分钟有65架飞机在天空穿梭&#xff0c;距地20公里有太阳能激光通信无人机展翅翱翔、高空通信热气球悠闲的漂荡&#xff0c;再往上有世界各大企业的低轨宽带卫星&#xff0c;在往上是各国的若干低轨道、中轨道…

ASP.NET Core 3.x API版本控制

前言一般来说需要更改我们API的时候才考虑版本控制&#xff0c;但是我觉得我们不应该等到那时候来实现它&#xff0c;我们应该有一个版本策略从我们应用程序开发时就开始制定好我们的策略&#xff0c;我们一直遵循着这个策略进行开发。我们其实可以通过多种方式进行实现我们API…

[JavaWeb-HTML]HTML标签_文本标签_练习

案列效果: 文本素材: "中关村黑马程序员训练营"是由传智播客联合中关村软件园、CSDN&#xff0c; 并委托传智播客进行教学实施的软件开发高端培训机构&#xff0c;致力于服务各大软件企业&#xff0c;解决当前软件开发技术飞速发展&#xff0c; 而企业招不到优秀人才…

在 WSL2.0 的 Ubuntu 18 里使用 Docker

近日&#xff0c;随着Windows 10 2004版本的发布&#xff0c;WSL 2经过了近一年的insider测试&#xff0c;现在也正式上线了。Windows 10 2004中引入了一个真实的Linux kernel&#xff0c;使得系统全部的系统调用更加兼容。这也是首次&#xff0c;Linux kernel安装在Windows系统…

基本程序单元Activity—Activity生命周期之数据传递小程序

一、 实验目的 &#xff08;1&#xff09; 掌握Andriod Studio的基本使用方法&#xff1b; &#xff08;2&#xff09; 掌握Andriod Studio中常用的控件及其使用方法&#xff1b; 二、 实验内容 题目&#xff1a; 编写一个数据传递的小程序&#xff0c;要求在第一个界面输入…

Asp.Net Core+Dapper开发直播平台!

现在直播大热&#xff0c;从游戏直播到直播带货&#xff0c;这几年都是最热门的了。教育直播、视频会议、云点播等各种基于直播构建的业务模式&#xff0c;让众多企业也都开始配备自己的直播平台。14年在公司带队做了个游戏直播平台&#xff0c;疫情期间在家重构了下项目&#…