《ASP.NET Core 6框架揭秘》实例演示[04]:自定义依赖注入框架

ASP.NET Core框架建立在一个依赖注入框架之上,已注入的方式消费服务已经成为了ASP.NET Core基本的编程模式。为了使读者能够更好地理解原生的注入框架框架,我按照类似的设计创建了一个简易版本的依赖注入框架,并它命名为“Cat”。本篇提供的四个实例主要体现了针对Cat的用法,《一个Mini版的依赖注入框架》提供了针对设计和实现原理的介绍。[本文节选《ASP.NET Core 6框架揭秘》第2章]

[201]模拟容器Cat-普通服务的注册和提取(源代码)
[202]模拟容器Cat-针对泛型服务类型的支持(源代码)
[203]模拟容器Cat-为同一类型提供多个服务注册(源代码)
[204]模拟容器Cat-服务实例的生命周期(源代码)

[201]模拟容器Cat-普通服务的注册和提取

我们定义了如下所示的接口和对应的实现类型来演示针对Cat的服务注册。Foo、Bar、Baz和Qux分别实现了对应的接口IFoo、IBar、IBaz和IQux,其中Qux类型上标注的MapToAttribute特性注册了与对应接口IQux之间的映射。四个类型派生于的基类Base实现了IDisposable接口,我们在其构造函数和实现的Dispose方法中输出相应的文本,以确定对应的实例何时被创建和释放。我们还定义了一个泛型的接口IFoobar<T1, T2>和对应的实现类Foobar<T1, T2>,用来演示Cat针对泛型服务实例的提供。

public interface IFoo {}
public interface IBar {}
public interface IBaz {}
public interface IQux {}
public interface IFoobar<T1, T2> {}public class Base : IDisposable
{public Base()   => Console.WriteLine($"Instance of {GetType().Name} is created.");public void Dispose()  => Console.WriteLine($"Instance of {GetType().Name} is disposed.");
}public class Foo : Base, IFoo{ }
public class Bar : Base, IBar{ }
public class Baz : Base, IBaz{ }
[MapTo(typeof(IQux), Lifetime.Root)]
public class Qux : Base, IQux { }
public class Foobar<T1, T2>: IFoobar<T1,T2>
{public T1 Foo { get; }public T2 Bar { get; }public Foobar(T1 foo, T2 bar){Foo = foo;Bar = bar;}
}

Lifetime是一个代表服务实例生命周期的枚举,它代表的三种生命周期模式定义如下。

public enum Lifetime
{Root,Self,Transient
}

如下所示的代码片段创建了一个Cat对象,并采用上面提到的方式针对接口IFoo、IBar和IBaz注册了对应的服务,它们采用的生命周期模式分别为Transient、Self和Root。另外,我们还调用了另一个将当前入口程序集作为参数的Register方法,该方法会解析指定程序集中标注了MapToAttribute特性的类型并进行批量服务注册。对于我们演示的程序来说,该方法会完成针对IQux/Qux类型的服务注册。接下来我们利用Cat对象创建了它的两个子容器,并调用子容器的GetService<T>方法来提供相应的服务实例。

using App;var root = new Cat().Register<IFoo, Foo>(Lifetime.Transient).Register<IBar>(_ => new Bar(), Lifetime.Self).Register<IBaz, Baz>(Lifetime.Root).Register(typeof(Foo).Assembly);
var cat1 = root.CreateChild();
var cat2 = root.CreateChild();void GetServices<TService>(Cat cat) 
where TService : class
{cat.GetService<TService>();cat.GetService<TService>();
}GetServices<IFoo>(cat1);
GetServices<IBar>(cat1);
GetServices<IBaz>(cat1);
GetServices<IQux>(cat1);
Console.WriteLine();
GetServices<IFoo>(cat2);
GetServices<IBar>(cat2);
GetServices<IBaz>(cat2);
GetServices<IQux>(cat2);

上面的程序运行之后会在控制台上输出图1所示的结果。由于服务IFoo被注册为Transient服务,所以Cat针对四次请求都会创建一个全新的Foo对象。IBar服务的生命周期模式为Self,对于同一个Cat只会创建一个Bar对象,所以整个过程中会创建两个Bar对象。IBaz和IQux服务采用Root生命周期,所以同根的两个Cat对象提供的其实是同一个Baz/Qux对象。

f2edf5bfa391b99e5eb1b9f8ed7fb39d.png

图1Cat按照服务注册对应的生命周期模式提供服务实例

[202]模拟容器Cat-针对泛型服务类型的支持

Cat同样可以提供泛型服务实例。如下面的代码片段所示,在为创建的Cat对象添加了针对IFoo和IBar接口的服务注册之后,我们调用Register方法注册了针对泛型定义IFoobar<,>的服务注册,具体的实现类型为Foobar<,>。当我们利用Cat对象提供一个类型为IFoobar<IFoo, IBar>的服务实例时,它会创建并返回一个Foobar<Foo, Bar>对象。

using App;using System.Diagnostics;var cat = new Cat().Register<IFoo, Foo>(Lifetime.Transient).Register<IBar, Bar>(Lifetime.Transient)    .Register(typeof(IFoobar<,>), typeof(Foobar<,>), Lifetime.Transient);
var foobar = (Foobar<IFoo, IBar>?)cat.GetService<IFoobar<IFoo, IBar>>();
Debug.Assert(foobar?.Foo is Foo);
Debug.Assert(foobar?.Bar is Bar);

[203]模拟容器Cat-为同一类型提供多个服务注册

我们可以为同一个类型提供多个服务注册。虽然添加的所有服务注册均是有效的,但由于GetService<TService>扩展方法总是返回一个服务实例,我们对该方法应用了“后来居上”的策略,即采用最近添加的服务注册创建服务实例。另一个GetServices<TService>扩展方法将返回根据所有服务注册提供的服务实例。下面的代码片段为创建的Cat对象添加了三个针对Base类型的服务注册,对应的实现类型分别为Foo、Bar和Baz。我们调用了Cat对象的GetServices<Base>方法返回包含三个Base对象的集合,集合元素的类型分别为Foo、Bar和Baz。

using App;
using System.Diagnostics;var services = new Cat().Register<Base, Foo>(Lifetime.Transient).Register<Base, Bar>(Lifetime.Transient).Register<Base, Baz>(Lifetime.Transient).GetServices<Base>();
Debug.Assert(services.OfType<Foo>().Any());
Debug.Assert(services.OfType<Bar>().Any());
Debug.Assert(services.OfType<Baz>().Any());

[204]模拟容器Cat-服务实例的生命周期

如果提供服务实例的类型实现了IDisposable接口,我们必须在适当的时候调用其Dispose方法释放它。由于服务实例的生命周期完全由作为依赖注入容器的Cat对象来管理,所以通过调用Dispose方法针对服务实例的释放也由它负责。Cat对象针对提供服务实例的释放策略取决于采用的生命周期模式,具体的策略如下。

  • TransientSelf:所有实现了IDisposable接口的服务实例会被当前Cat对象保存起来,当Cat对象自身的Dispose方法被调用的时候,这些服务实例的Dispose方法会随之被调用。

  • Root:由于服务实例保存在作为根容器的Cat对象上,所以当作为根的Cat对象的Dispose方法被调用的时候,这些服务实例的Dispose方法会随之被调用。

上述释放策略可以通过如下演示实例来印证。如下代码片段所示,我们创建了一个Cat对象并添加了相应的服务注册。我们调用它的CreateChild方法创建了代表子容器的Cat对象,并用它提供了四个注册服务对应的实例。

using App;
using (var root = new Cat().Register<IFoo, Foo>(Lifetime.Transient).Register<IBar>(_ => new Bar(), Lifetime.Self).Register<IBaz, Baz>(Lifetime.Root).Register(typeof(IFoo).Assembly))
{    using (var cat = root.CreateChild()){cat.GetService<IFoo>();cat.GetService<IBar>();cat.GetService<IBaz>();cat.GetService<IQux>();Console.WriteLine("Child cat is disposed.");}Console.WriteLine("Root cat is disposed.");
}

由于两个Cat对象的创建都是在using块中进行的,所以它们的Dispose方法都会在using块结束的地方被调用。该程序运行之后会在控制台上输出图2所示的结果,我们可以看到当作为子容器的Cat对象的Dispose方法被调用时,由它提供的两个生命周期模式分别为Transient和Self的服务实例(Foo和Bar)被正常释放。而生命周期模式为Root的服务实例(Baz和Qux对象)的Dispose方法会延迟到作为根容器的Cat对象的Dispose方法被调用的时候。

d0ddb466fbbb3ca7368ee235730a24b2.png
图2 服务实例的释放

《ASP.NET Core 6框架揭秘》实例演示[01]:编程初体验
《ASP.NET Core 6框架揭秘》实例演示[02]:基于路由、MVC和gRPC的应用开发
《ASP.NET Core 6框架揭秘》实例演示[03]:Dapr初体验

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

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

相关文章

【QGIS入门实战精品教程】4.8:QGIS如何下载SRTM数字高程模型DEM?

本文讲解QGIS中下载SRTM数字高程模型DEM,以黑龙江省塔河县为例。 图幅效果: 最终效果: 文章目录 1. 下载安装STRM Download插件2. 加载矢量数据,读取范围3. 下载STRM4. DEM拼接5. DEM裁剪1. 下载安装STRM Download插件 点击【插件】→【管理并安装插件】。 在搜索框中输入…

Win11 恢复设置Win10任务栏、快速启动栏及右键菜单(Win11 22000.100版本测试通过)

恢复方法 按下边路径添加 UndockingDisabled项&#xff0c;DWORD (32-bit)值为1&#xff1a; [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell\Update\Packages] "UndockingDisabled"dword:00000001显示效果 已知问题 开始按钮点击无反应&a…

vue vue-router vuex element-ui axios 写一个代理平台的学习笔记(十一)构思商品页面...

在写商品页面product.vue之前&#xff0c;我应该思考一下&#xff0c;商品页面要实现那些功能&#xff0c;该不如布局&#xff1f;要实现的功能 1、所有商品列表的展示2、分类商品的列表展示 3、搜索商品或得列表展示4、单一商品的详细页面5、商品列表分页功能6、还没想到的...…

【ArcGIS Pro微课1000例】0019:ArcGIS Pro从海洋的视角看世界---海洋投影(Spilhaus Projection)

从海洋的视角看世界: 世界地图大多是以陆地为主要载体,如果以海洋为主角,就需要使用一种海洋投影。该投影以Spilhaus博士的名称命名。ArcGIS Pro自2.5版本以来提供了Spilhaus Projection。 投影效果预览: 接下来演示ArcGIS Pro 2.8中海洋投影的转换方法: 1. 新建一个工程…

有人撸了个网页版win11,惊艳!

演示地址&#xff1a;https://win11.blueedge.me/ Github地址&#xff1a;https://github.com/blueedgetechno/windows11

Vue3+.NET6+C#10,最近优质前后端分离项目汇总

据说80%的WEB开发都是管理后台&#xff0c;一套开源的优秀管理后台开发模板堪称福音&#xff01;分享一套Vue3 Axios TS Vite Element Plus .NET 6 WebAPI JWT SqlSugar的前后端分离架构的通用管理后台源码数据库脚本&#xff0c;还有与之配套录制的一组视频教程&#xff0c;全…

C++ 对象的内 存布局(下)

原文地址&#xff1a;http://blog.csdn.net/haoel/article/details/3081385 (注:看本文的时候由于宿舍快断电了,来不及细看,所以怕自己忘记,先贴出来.不排除文章有错误,大家自己测试一下.) 重复继承 下面我们再来看看&#xff0c;发生重复继承的情况。所谓重复继承&#xff0c;…

【GIS风暴】一文彻底弄懂数字地形(DEM、DOM、TDOM、DSM)的区别与联系

在2021自然资源部发布的《实景三维中国建设技术大纲(2021版)》中,空间数据部分包括“数字高程模型(DEM)、数字表面模型(DSM)、数字正射影像(DOM)、真正射影像(TDOM)、倾斜摄影三维模型、激光点云等。” 那么到底什么是DEM、DOM、TDOM、DSM,它们之间又有什么用的区别…

什么是“异步 Request-Reply”模式?编程如何实现?

在某些情况下&#xff0c;WEB API 可能需要很长时间来处理请求&#xff0c;而客户端如果一直等待工作完成是不可行的&#xff0c;比如连接超时等。这时&#xff0c;可以使用“异步 Request-Reply 模式”。异步 Request-Reply 模式异步 Request-Reply 模式是指&#xff1a;在后端…

【测绘程序设计】Excel度分秒(° ‘ “)转换度(°)模板附代码超实用版

在实际工作中,无论是ArcGIS中,还是CASS中,作图时需要将GPS实测的经纬度度分秒( ’ ")坐标转换为度(),在前面的文章中介绍了C#中将度分秒转为度的转换程序,本文讲解在Excel中快速度分秒( ’ ")转换度(),提高工作效率。 文章目录 准备工作编写代码注意事…

IO扩展控件(System.IO.Abstractions)

刚看到这个Namespace的时候还以为是.Net Framework里自带的包&#xff0c;结果查了一圈无任何结果。果断上Github搜索&#xff0c;一击即中 https://github.com/tathamoddie/System.IO.Abstractions先翻译下开发者给出的简单说明&#xff0c;今后再慢慢使用类似于System.Web.Ab…

[转]面向对象(1、三大特征;2、六大原则)

目录 一、面向对象的概述&#xff1a; 二、封装&#xff1a; 1、封装概述 2、封装原则 3、封装好处 4、封装坏处 5、封装代码展示 三、继承&#xff1a; 1、概念&#xff1a; 2、实现格式&#xff1a; 3、特点&#xff1a; 4、好处&#xff1a; 5、弊端&#xff1…

【测绘程序设计】C#将度分秒(° ‘ “)转换度(°)程序实现(附源码)

在实际工作中,无论是ArcGIS中,还是CASS中,作图时需要将GPS实测的经纬度度分秒( ’ ")坐标转换为度(),在前面的文章中介绍了Excel中将度分秒转为度的转换程序,本文讲解在Visual Studio中,采用C#语言实现快速度分秒( ’ ")转换度(),提高工作效率。 案例…

Spotlight监控工具使用

Spotlight on unix监控linux服务器 1.下载安装&#xff0c;工具包下载地址&#xff1a; 注&#xff1a;安装之后需要破解注册码 2.由于spotlight不能默认使用root用户登录&#xff0c;所以必须先创建一个具有root权限的用户 注&#xff1a;密码最好不要设置的过于简单化 [rootm…

Grpc MagicOnion库 之 客户端和服务端 (案例版)

之前通过自己写动态代理和用现成的动态代理库等实现过RPC功能&#xff0c;今天&#xff0c;就写一下如何直接引用GRPC的库来实现业务逻辑。gRPC的介绍&#xff0c;之前我也说了这个g的含义太多&#xff0c;也包含谷歌的意思了。可以看这个gRPC的文档介绍 : https://grpc.io/doc…

Windows11右下角出现评估副本水印如何去除?

Universal Watermark Disabler是一款十分好用的桌面工具&#xff0c;这款工具可以帮助用户轻松的去除Windows11 版本的操作系统右下角的水印。 使用方法 1、打开Universal Watermark Disabler软件&#xff0c;显示出当前系统的版本与水印状态。 2、Status中显示Ready for insta…

【GlobalMapper精品教程】001:GlobalMapper23+24 Pro-x64中文安装教程(附软件包下载)

Global Mapper 23是一款非常专业的地图绘制软件&#xff0c;功能非常的丰富&#xff0c;内置距离和面积计算&#xff0c;包括光栅混合、对比度调节、海拔高度查询、视线计算以及一些高级功能&#xff0c;可轻松实现图像校正、通过地表数据进行轮廓生成、通过地表数据观察分水岭…

JIL 编译与 AOT 编译

JIT&#xff1a;Just-in-time compilation&#xff0c;即时编译&#xff1b;AOT&#xff1a;Ahead-of-time compilation&#xff0c;事前编译。 JVM即时编译&#xff08;JIT&#xff09; 1. 动态编译与静态编译 动态编译&#xff08;dynamic compilation&#xff09;指的是“在…

中台基础指标列表

便于大家进行更方便的指标圈定&#xff0c;这里我将前面提到的通用指标进行一次拓展&#xff0c;为大家整理了一份完整的数据中台基础指标列表&#xff0c;方便大家在搭建指标体系时进行速查。 &#xff08;1&#xff09;App类产品分析指标 &#xff08;2&#xff09;网站类产…

期末作品检查

1、学期个人总结 在这个学期在杜老师的带领下学习了Python语言&#xff0c;这是一门相对于Java语言来说是比较简单的语言&#xff0c;用处也十分的广大。python是一种面向对象的解释型计算机程序设计语言&#xff0c;语法简洁清晰&#xff0c;目前已超越java成为最热门的编程语…