.net core的依赖注入学习
依赖注入(Dependency Injection,DI),简称DI,它可以降低各模块之间的耦合
首先需要安装两个Nuget包:
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.DependencyInjection.Abstractions
安装完之后要在主程序里面引用第一个包
using Microsoft.Extensions.DependencyInjection
提前准备好一个接口和两个实现类
public interface ITestService
{
public string Name { get; set; }
public void SayHi();
}
public class TestServiceImpl : ITestService
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine($"Hi, I'm {Name}");
}
}
public class TestServiceImpl2 : ITestService
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine($"你好,我是{Name}");
}
}
然后在主程序中调用,以下是一个服务从注册到被使用的代码
//首先声明一个容器服务的对象,将其命名为services
//然后将需要被注册服务的对象TestServiceImpl添加放入容器服务对象services中
//添加方式有三种
//services.AddTransient
//services.AddSingleton
//services.AddScoped
//添加完服务之后使用services.BuildServiceProvider()方法构造出服务容器sp
//使用sp.GetService<TestServiceImpl>()即可使用刚刚添加进去的TestServiceImpl,如果没有对象被添加进服务,则是Null;
//sp.GetRequiredService,如果没有对象被添加进服务则会抛异常
//如果注册了多个服务,使用的是GetService,那么实际上选择的是最后一个服务(此处未体现)
ServiceCollection services = new ServiceCollection();
//services.AddTransient<TestServiceImpl>();
//services.AddSingleton<TestServiceImpl>();
services.AddScoped<TestServiceImpl>();
using (ServiceProvider sp = services.BuildServiceProvider())
{
TestServiceImpl t1 = sp.GetService<TestServiceImpl>();
testService.Name = "tom";
testService.SayHi();
}
关于三种添加方式AddTransient(瞬态),AddSingleton(单例),AddScoped(范围);
使用AddTransient添加到服务的对象,每一次获取服务sp.GetService都是新的
而使用AddSingleton添加到服务的对象,每一次获取服务sp.GetService都是原来的
ServiceCollection services = new ServiceCollection();
services.AddTransient<TestServiceImpl>();
services.AddSingleton<TestServiceImpl2>();
using (ServiceProvider sp = services.BuildServiceProvider())
{
//使用AddTransient添加的
/*输出结果:
Hi, I'm xiaoli
False
Hi, I'm dali
Hi, I'm xiaoli
*/
TestServiceImpl t1 = sp.GetService<TestServiceImpl>();
t1.Name = "xiaoli";
t1.SayHi();
TestServiceImpl t2 = sp.GetService<TestServiceImpl>();
Console.WriteLine(object.ReferenceEquals(t1,t2));
t2.Name = "dali";
t2.SayHi();
t1.SayHi();
//使用AddSingleton添加的
/*输出结果:
你好,我是xiaoli
True
你好,我是dali
你好,我是dali*/
TestServiceImpl2 tt1 = sp.GetService<TestServiceImpl2>();
tt1.Name = "xiaoli";
tt1.SayHi();
TestServiceImpl2 tt2 = sp.GetService<TestServiceImpl2>();
Console.WriteLine(object.ReferenceEquals(tt1, tt2));
tt2.Name = "dali";
tt2.SayHi();
tt1.SayHi();
}
如果使用的是AddScoped,并且还限定了范围,那么在同一个范围内每次获取到的对象都是一样的
ServiceCollection services = new ServiceCollection();
services.AddScoped<TestServiceImpl>();
using (ServiceProvider sp = services.BuildServiceProvider())
{
TestServiceImpl tt1;
//在iss中获取Scope相关对象,iss1.ServiceProvider,而不是sp
using (IServiceScope iss1 = sp.CreateScope())
{
TestServiceImpl t1 = iss1.ServiceProvider.GetService<TestServiceImpl>();
t1.Name = "xiaoli";
t1.SayHi();
TestServiceImpl t2 = iss1.ServiceProvider.GetService<TestServiceImpl>();
Console.WriteLine(object.ReferenceEquals(t1, t2));
Console.WriteLine(t1.GetType());
tt1 = t1;
}
using (IServiceScope iss2 = sp.CreateScope())
{
TestServiceImpl t1 = iss2.ServiceProvider.GetService<TestServiceImpl>();
t1.Name = "xiaoli";
t1.SayHi();
TestServiceImpl t2 = iss2.ServiceProvider.GetService<TestServiceImpl>();
//true 同一个范围内的对象相同
Console.WriteLine(object.ReferenceEquals(t1, t2));
//false,两个范围(scope)的对象不相同
Console.WriteLine(object.ReferenceEquals(tt1, t2));
}
}
/*
Hi, I'm xiaoli
True
ioc1.TestServiceImpl
Hi, I'm xiaoli
True
False
*/
生命周期的选择:如果类无状态,建议为Singleton;如果类有状态,且有Scope控制,建议为Scoped,因为通常这种Scope控制下的代码都是运行在同一个线程中的,没有并发修改的问题;在使用Transient的时候要谨慎。
简单应用:
创建3个接口和对应的实现类,再建一个服务容器类
//日志信息
interface ILog
{
public void Log(string msg);
}
class LogImpl : ILog
{
public void Log(string msg)
{
Console.WriteLine($"日志信息:{msg}");
}
}
//配置信息
interface IConfig
{
public string GetValue(string name);
}
class ConfigImpl : IConfig
{
public string GetValue(string name)
{
return "Hello";
}
}
//保存信息
interface IStorage
{
public void Save(string content, string name);
}
class StorageImpl : IStorage
{
private readonly IConfig config;
public StorageImpl(IConfig config)
{
this.config = config;
}
public void Save(string content, string name)
{
string server = config.GetValue("server");
Console.WriteLine($"向服务器:{server}的文件名为:{name}上传{content}");
}
}
//服务容器
class Controller
{
private readonly ILog log;
private readonly IStorage storage;
public Controller(ILog log, IStorage storage)
{
this.log = log;
this.storage = storage;
}
public void Test()
{
log.Log("开始上传");
storage.Save("4646461jhk", "1.txt");
log.Log("上传完毕");
}
}
在主函数中实现
static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
services.AddScoped<Controller>();
services.AddScoped<ILog, LogImpl>();
services.AddScoped<IStorage, StorageImpl>();
services.AddScoped<IConfig, ConfigImpl>();
using(ServiceProvider sp = services.BuildServiceProvider())
{
var c = sp.GetRequiredService<Controller>();
c.Test();
}
Console.ReadKey();
}
/*输出结果
日志信息:开始上传
向服务器:Hello的文件名为:1.txt上传4646461jhk
日志信息:上传完毕
*/
学习来自杨中科大佬在某站上面的视频
.net core的依赖注入学习的更多相关文章
- ASP.NET Core之依赖注入
本文翻译自:http://www.tutorialsteacher.com/core/dependency-injection-in-aspnet-core ASP.NET Core支持依赖注入,依赖 ...
- 【半小时大话.net依赖注入】(下)详解AutoFac+实战Mvc、Api以及.NET Core的依赖注入
系列目录 上|理论基础+实战控制台程序实现AutoFac注入 下|详解AutoFac+实战Mvc.Api以及.NET Core的依赖注入 前言 本来计划是五篇文章的,每章发个半小时随便翻翻就能懂,但是 ...
- 几十行代码实现ASP.NET Core自动依赖注入
在开发.NET Core web服务的时候,我们习惯使用自带的依赖注入容器来进行注入. 于是就会经常进行一个很频繁的的重复动作:定义一个接口->写实现类->注入 有时候会忘了写Add这一步 ...
- 重新整理 .net core 实践篇————依赖注入应用[二]
前言 这里介绍一下.net core的依赖注入框架,其中其代码原理在我的另一个整理<<重新整理 1400篇>>中已经写了,故而专门整理应用这一块. 以下只是个人整理,如有问题, ...
- 【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类
依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体原则就是:俺要啥,你就给俺送啥过来.服务类型的实例转由容器自动管理,无需我们在代码中显式处理. 因此,有了依 ...
- .Net Core 通过依赖注入和动态加载程序集实现宿程序和接口实现类库完全解构
网上很多.Net Core依赖注入的例子代码,例如再宿主程序中要这样写: services.AddTransient<Interface1, Class1>(); 其中Interface1 ...
- .NET Core的依赖注入[1]: 控制反转
写在前面:我之前写过一系列关于.NET Core依赖注入的文章,由于.NET Core依赖注入框架的实现原理发生了很大的改变,加上我对包括IoC和DI这些理论层面的东西又有了一些新的理解,所以我在此基 ...
- .NET Core 中依赖注入 AutoMapper 小记
最近在 review 代码时发现同事没有像其他项目那样使用 AutoMapper.Mapper.Initialize() 静态方法配置映射,而是使用了依赖注入 IMapper 接口的方式 servic ...
- 用工厂模式解决ASP.NET Core中依赖注入的一个烦恼
这是最近在实际开发中遇到的一个问题,用 asp.net core 开发一个后端 web api ,根据指定的 key 清除 2 台 memcached 服务器上的缓存.背景是我们在进行 .net co ...
- .Net Core 使用依赖注入
ASP.NET Core 源码阅读笔记(1) ---Microsoft.Extensions.DependencyInjection 在asp .net中使用依赖注入很简单,只需要在Startup类的 ...
随机推荐
- Python笔记六之多进程
本文首发于公众号:Hunter后端 原文链接:Python笔记六之多进程 在 Python 里,我们使用 multiprocessing 这个模块来进行多进程的操作. multiprocessing ...
- [win10] 开始-设置 / 右键-显示设置 / 右键个性化 等都不好使了。。 ms-settings:display
现象: 各种win10自带的都打不开了. 发现: 最近总是断网,重启下就好了,然后点击网络,就一直出不来.后来发现所有win10的窗口都出不来了.控制面板等等. 解决:好消息是最后解决了.坏消息是没有 ...
- linux-debian-把用户加入root组
使用vim进入 /etc/sudoers 打开这个文件(或者 vi)也行 修改数据: 敲击键盘上个的 i 就可以键入字符了, 在root = ALL(ALL:ALL) ALL 的下面敲击 用户 ...
- RAG 范式、技术和趋势
这里分享同济大学 Haofen Wang的关于检索增强生成的报告:<Retrieval-Augmented Generation (RAG): Paradigms, Technologies, ...
- Linux常用指令2
1.系统常用命令 1)在文件中查找内容 grep >grep hello passwd //在passwd文件中搜索hello内容,会把hello所在行的内容打印到终端显示 2)查看系统中活跃 ...
- [Raspberry Pi]树莓派多线程下串口收发数据
[Raspberry Pi]树莓派多线程下串口收发数据 鼠鼠用的是python开发树莓派,因为python是最优美的语言! 少废话,直接上代码: import threading import ser ...
- 记录--图解 Vue 响应式原理
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 最近部门分享,有同学提到了 Vue 响应式原理,大家在讨论时,发现一些同学对这一知识理解还不够深入,不能形成一个闭环,为了帮助大家理解这个 ...
- 基于电脑软件的任意波形发生器SIG852初识(类似虚拟示波器)
基于电脑软件的任意波形发生器SIG852初识(类似虚拟示波器) 对于从事电路板开发的硬件工程师来说,信号源是经常使用也非常熟悉的.我们用它来作为电路板的输入,测试电路板是否能按预期正常处理这些信号.最 ...
- go两种遍历chan
go中对通道chan遍历有两种方式一种是用range另一种为for select. package main import ( "fmt" "strings" ...
- KingbaseES特殊权限介绍
用户需求:新建一个用户B,需要能够查询A用户的所有表,并且对以后新建的表也要有select权限. 对于现有的表可以通过动态sql批量进行授权,但是未来新建的表要如何进行授权呢? 查询了帮助文档发现通过 ...