重新整理.net core 计1400篇[八] (.net core 中的依赖注入的深入理解)
生命周期策略
在实例Transient 和 Scoped 中,所以实现Idisposable 接口的服务实例会被当前IServiceProvider 对象保存起来,当IService 对象的Dispose 方法被调用的时候,这些服务实例的Dispose 方法被随着调用。
在singleton由于服务实例保存在根容器的IserviceProvide 对象上,所以只有当后者的Dispose方法被调用的时候,这些服务实例的Dispose方法才会随之被调用。
在.net core 应用中,他具有一个与当前应用绑定代表的全局根容器的IServiceProvider对象。对于处理的每一次请求,ASP.Net Core框架会利用这个根容器来创建基于当前请求的服务范围,并利用后者提供的IServiceProvider对象来提供请求处理所需的服务实例。
请求处理完成之后,创建的服务范围被终结,那么会调用IDisposable让其他服务实例得到释放。
服务注册的验证
为什么服务注册需要验证呢?
对于singleton和scoped 两种不同生命周期是通过将提供的服务实例分别存放到作为根容器的IServiceProvider对象和当前的IServiceProvider 对象来实现的。
这意味着作为根容器提供的Scoped也是单例的。
在asp.net core应用中,将某个服务注册的生命周期设置为Scoped的真正意图是希望依赖注入容器根据接收的每个请求来创建和释放服务实例,但是一旦一个singleton引用了一个scoped,那么scoped将会变成一个singleton。
可能这样说有些模糊,代码来示范一下:
static void Main()
{
var root = new ServiceCollection()
.AddSingleton<IFoo, Foo>()
.AddScoped<IBar, Bar>()
.BuildServiceProvider(true);
var child = root.CreateScope().ServiceProvider;
void ResolveService<T>(IServiceProvider provider)
{
var isRootContainer = root == provider ? "Yes" : "No";
try
{
provider.GetService<T>();
Console.WriteLine($"Status: Success; Service Type: { typeof(T).Name}; Root: { isRootContainer}");
}
catch (Exception ex)
{
Console.WriteLine($"Status: Fail; Service Type: { typeof(T).Name}; Root: { isRootContainer}");
Console.WriteLine($"Error: {ex.Message}");
}
}
ResolveService<IFoo>(root);
ResolveService<IBar>(root);
ResolveService<IFoo>(child);
ResolveService<IBar>(child);
Console.ReadKey();
}
public interface IFoo { }
public interface IBar { }
public class Foo : IFoo
{
public IBar Bar { get; }
public Foo(IBar bar) => Bar = bar;
}
public class Bar : IBar { }
是这样的一个故事,在Foo中是一个单例,因为Foo引用了Bar,那么再Foo中Bar就是一个单例了。
上面有一个方法:.BuildServiceProvider(true);,设置为true,那么这个时候就会验证Scoped模式是不是就真的就是scoped。
结果为:
实际上,服务范围的校验中,是根据一个叫做ServiceProviderOptions来做设置的,刚刚我们设置的是ValidateScopes,也就是校验范围,但是这个校验范围是在我们创建服务实例的时候校验的,那么能不能在我们注册的时候就校验呢?
/// <summary>
/// Options for configuring various behaviors of the default <see cref="T:System.IServiceProvider" /> implementation.
/// </summary>
public class ServiceProviderOptions
{
internal static readonly ServiceProviderOptions Default = new ServiceProviderOptions();
/// <summary>
/// <c>true</c> to perform check verifying that scoped services never gets resolved from root provider; otherwise <c>false</c>. Defaults to <c>false</c>.
/// </summary>
public bool ValidateScopes
{
[CompilerGenerated]
get;
[CompilerGenerated]
set;
}
/// <summary>
/// <c>true</c> to perform check verifying that all services can be created during <code>BuildServiceProvider</code> call; otherwise <c>false</c>. Defaults to <c>false</c>.
/// NOTE: this check doesn't verify open generics services.
/// </summary>
public bool ValidateOnBuild
{
[CompilerGenerated]
get;
[CompilerGenerated]
set;
}
internal ServiceProviderMode Mode
{
[CompilerGenerated]
get;
[CompilerGenerated]
set;
}
}
可以看到还有一个属性,ValidateOnBuild,这个显示当在构造的时候就会被验证。
举例子:
static void Main()
{
BuildServiceProvider(false);
BuildServiceProvider(true);
void BuildServiceProvider(bool validateOnBuild)
{
try
{
var options = new ServiceProviderOptions
{
ValidateOnBuild = validateOnBuild
};
new ServiceCollection()
.AddSingleton<IFoobar, Foobar>()
.BuildServiceProvider(options);
Console.WriteLine($"Status: Success; ValidateOnBuild: {validateOnBuild}");
}
catch (Exception ex)
{
Console.WriteLine($"Status: Fail; ValidateOnBuild: {validateOnBuild}");
Console.WriteLine($"Error: {ex.Message}");
}
}
Console.Read();
}
结果为:
也就是说在注册服务的时候就会报错。
总结
后面介绍服务注册的一些细节。
原文地址:https://www.cnblogs.com/aoximin/p/12923589.html
- 学习Spark——那些让你精疲力尽的坑
- Silverlight 3.0 中的 WriteableBitmap
- WCF后续之旅(10): 通过WCF Extension实现以对象池的方式创建Service Instance
- Silverlight菜单控件 — CurveMenu
- 实力终端撑腰 两枚域名均五位数被秒
- Silverlight制作逐帧动画 v2 - part2
- Nodejs学习笔记(四)--- 与MySQL交互(felixge/node-mysql)
- 学习Spark——环境搭建(Mac版)
- 离线网络环境下一键式部署
- WCF后续之旅(17):通过tcpTracer进行消息的路由
- Linux同步机制(一) - 线程锁
- Silverlight类库介绍-FJCore
- 大型网站的自强之路
- 人工智能:浮现
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- kali linux下的常用bash命令
- shell脚本快速入门之-----linux设置 自定义脚本开机启动,一键式部署网卡配置文件
- jdbc连接oracle语法
- java实现数据库连接的工具类
- shell脚本快速入门之-----正则三剑客之一grep用法大全!!!
- 【网页特效】11 个文本输入和 6 个按钮操作 特效库
- shell脚本快速入门之-----正则三剑客之二sed用法大全!!!
- JSP中的Cookie
- 傅里叶变换
- shell脚本快速入门之-----shell脚本练习100例!!!
- java监听器
- shell脚本快速入门之-----函数
- shell脚本快速入门之-----循环(for、while、until)
- ThreadPoolExecutor系列三——ThreadPoolExecutor 源码解析
- shell脚本快速入门之-----数组