IceRPC之依赖注入>快乐的RPC
作者引言
很高兴啊,我们来到了IceRPC之依赖注入>快乐的RPC,基础引导,打好基础,才能让自已不在迷茫,快乐的畅游世界。
依赖注入和IceRPC
了解 IceRPC (C#) 如何为依赖注入(DI)提供支持。
DI作为可选功能
DI的第一条规则是:不要引入对DI的依赖。
IceRPC (C#) 将此规则放首要位置上,即为 DI 提供全方位支持,同时使此支持完全可选。
IceRPC C# API 被设计为可选 DI 容器。此外,IceRPC 还提供支持代码来帮助大家,在 Microsoft's DI container中使用 IceRPC。.
DI APIs
IceRPC 提供的所有与 DI 相关的 API 都在同一个命名空间中, IceRpc.Extensions.DependencyInjection, 但由多个组件实现:
- IceRpc.dll 提供如
IDispatcherBuilder和IInvokerBuilderIceRpc.Deadline.dll之类的抽象以及其他拦截器/中间件组件,为IDispatcherBuilder和IInvokerBuilder提供了扩展方法。这些扩展方法与 DI 容器无关。 - IceRpc.Extensions.DependencyInjection.dll 为 Microsoft 的 DI 容器提供支持代码。这包括
IServiceCollection的各种扩展方法,例如AddIceRpcServer和AddIceRpcClientConnection,以及IDispatcherBuilder和IInvokerBuilder的实现。
title: 程序集依赖图
---
flowchart BT
di([Microsoft.Extensions.DependencyInjection.Abstractions.dll])
logging([Microsoft.Extensions.Logging.Abstractions.dll])
options([Microsoft.Extensions.Options.dll])
IceRpc.dll --> logging
IceRpc.Logger.dll --> IceRpc.dll
IceRpc.Logger.dll --> logging
IceRpc.Deadline.dll --> IceRpc.dll
IceRpc.Extensions.DependencyInjection.dll --> di
IceRpc.Extensions.DependencyInjection.dll --> options
IceRpc.Extensions.DependencyInjection.dll --> IceRpc.dll
调度管道与 DI
了解如何使用 DI 容器构建调度管道。
传统的调度管道
传统的调度管道相当静态: 创建路由、添加一些中间件、在此路由中映射或安装少量叶片调度程序,然后让服务器将传入的请求调度到此路由。
叶片调度程序(通常是 Slice 服务)被映射或安装在固定路径(例如/greeter 或/admin/greeter-manager)。 这些调度程序是单例(或类似单例),其使用寿命与路由和服务器相同。
调度管道中的中间件使用以下features相互通信: 上游中间件设置下游中间件可以检索的features。叶片调度程序还可以使用相同的features与这些中间件进行通信。
这对于许多应用程序来说都很有效。然而,这并不是使用 DI 时的典型模型。
DI容器构建调度管道
DI,调度管道通常更具动态性: 一些基础设施代码为每个调度创建唯一的 DI 范围,并且叶片调度程序是由 DI 容器管理的服务。当该叶片调度器的生命周期是短暂的或范围化的时,该叶片调度器是按需创建的(每个调度)。
DI 调度管道中的中间件可以像往常一样使用features,与其他中间件和叶片调度器进行通信。然而,更惯用的方法是使用注入服务进行通信。例如:
- 上游中间件接收范围服务(通过注入),然后填写此服务
- 下游中间件接收相同的作用域服务(也通过注入)并读取上游中间件填写的信息
- 叶片调度器的构造函数(作用域或瞬态服务)与该先前填充的作用域服务自动连线
中间件链本身是静态的: 每个调度不会创建新的中间件实例。中间件通常是由 DI 容器管理的单例。
使用 Microsoft 的 DI 容器构建调度管道
IceRpc.Extensions.DependencyInjection组件为 IServiceCollection 提供了多种接受 Action<IDispatcherBuilder> 参数的扩展方法。
所有这些方法都允许 Microsoft 的 DI 容器构建和配置调度管道。例如:
// Construct a dispatch pipeline using Microsoft's DI container.
using IceRpc.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
...
// Add a new IDispatcher singleton configured with an action.
services.AddIceRpcDispatcher(builder => builder.Map<IGreeterService>());
由此产生的调度程序(调度管道)为每个传入请求创建一个新的 DI 范围,并使用 IServiceProviderFeature 将此范围传输到下游调度程序。
在 IDispatcherBuilder 中安装标准中间件
标准中间件是可以与 DI 容器一起使用或不使用 DI 容器的中间件: 它不依赖DI容器注入服务来运行,并且实现了接口 IDispatcher 。
IceRPC 附带的所有中间件都是标准中间件: 可以在有或没有 DI 的情况下使用它们,并且它们在调度中使用功能进行通信。
这些中间件可以安装在路由或 IDispatcherBuilder 中。例如:
// Construct a dispatch pipeline using Microsoft's DI container.
using IceRpc.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
...
services.AddIceRpcDispatcher(
builder => builder
.UseLogger()
.Map<IGreeterService>());
这里,UseLogger 是 IceRpc.Logger 组件提供的扩展方法。此扩展方法适用于实现 IServiceProvider 的任何 DI 容器,例如 Microsoft 的 DI 容器和 Simple Injector 的容器。
UseLogger 的实现只是从 DI 容器中检索一个记录器实例, 然后用这个实例创建一个新的中间件:
public static IDispatcherBuilder UseLogger(this IDispatcherBuilder builder) =>
builder.ServiceProvider.GetService(typeof(ILogger<LoggerMiddleware>)) is ILogger logger ?
builder.Use(next => new LoggerMiddleware(next, logger)) :
throw new InvalidOperationException(
$"Could not find service of type '{nameof(ILogger<LoggerMiddleware>)}' in the service container.");
我们建议在创建自己的标准中间件时遵循相同的模式,并为 Router 和 IDispatcherBuilder 提供使用扩展方法。
通常不鼓励在运行时调用 DI 容器—它是反模式的服务定位器。在这里,应该将
UseLogger扩展方法视为不受此规则约束的基础设施代码。
具有注入服务的中间件
DI 容器注入的服务来创建与其他中间件和叶片调度器通信的中间件,而不是提供标准的中间件。
DI 友好的中间件需要实现以下 IMiddleware 接口之一:
IMiddleware<TDep>IMiddleware<TDep1, TDep2>IMiddleware<TDep1, TDep2, TDep3>
例如,我们希望以更适合 DI 的方式,重新实施截止日期中间件。标准截止日期中间件读取截止日期字段,并创建截止日期功能,以将此截止日期传达给,下游中间件和叶片调度程序。新的 DI 友好截止日期中间件,解码截止日期并将此信息,保存在注入的 scoped 服务中:
// Configured as a scoped service in the composition root of the application.
public class DeadlineInformation
{
public DateTime Value { get; set; } = DateTime.MinValue; // MinValue means no deadline.
}
...
// New DI-friendly deadline middleware. Note that it does not implement IDispatcher.
public class DIDeadlineMiddleware : IMiddleware<DeadlineInformation>
{
private readonly IDispatcher _next;
// A constructor with an IDispatcher parameter is required for auto-wiring.
public DIDeadlineMiddleware(IDispatcher next) => _next = next;
// deadlineInfo is a scope service provided by the DI container.
public ValueTask<OutgoingResponse> DispatchAsync(
IncomingRequest request,
DeadlineInformation deadlineInfo,
CancellationToken cancellationToken)
{
// Decode the deadline field as usual.
DateTime deadline = request.Fields.DecodeValue(
RequestFieldKey.Deadline,
(ref SliceDecoder decoder) => decoder.DecodeTimeStamp());
if (deadline != DateTime.MinValue)
{
// If deadline is not MinValue, store it in deadlineInfo
deadlineInfo.Value = deadline;
// TODO: enforce deadline while calling _next.DispatchAsync.
}
else
{
// Call _next.DispatchAsync as usual.
return _next.DispatchAsync(request, cancellationToken);
}
}
}
如果使用 Microsoft 的 DI 容器,可以使用 IceRpc.Extensions.DependencyInjection 组件提供的 UseMiddleware 扩展方法安装此中间件:
using IceRpc.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
...
// The DIDeadlineMiddleware is instantiated and managed by the DI container.
services.AddIceRpcDispatcher(
builder => builder
.UseLogger()
.UseMiddleware<DIDeadlineMiddleware>()
.Map<IGreeterService>());
// To be registered as a transient or scoped service in the DI container.
[SliceService]
internal partial class Chatbot : IGreeterService
{
// DeadlineInformation is auto-wired by the DI container.
internal Chatbot(DeadlineInformation deadlineInfo)
{
...
}
...
}
调用管道与DI
了解如何使用 DI 容器构建调用管道。
DI 容器构建调用管道
与调度管道不同,调用管道在有或没有 DI 容器的情况下几乎相同。 这是因为调用没有自然的 DI 范围: DI 作用域内执行调用,则该作用域来自另一个封闭活动,例如进行此调用的调度。
IceRPC [C#] 不会为 DI 范围内的调用提供任何特殊支持。特别是
IMiddleware没有拦截器对应物。
使用 Microsoft 的 DI 容器构建调用管道
可以调用 AddIceRpcInvoker 将新的调用器(调用管道)单例添加到您的 DI 容器中。
例如:
// Construct an invocation pipeline using Microsoft's DI container.
using IceRpc.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
...
// Add a new IInvoker singleton configured with an action.
services
.AddIceRpcClientConnection()
.AddIceRpcInvoker(builder => builder.Into<ClientConnection>())
必须使用 Into 方法指定最终调用器。通过此示例,新调用器流入我们之前配置的 ClientConnection 单例。
在 IInvokerBuilder 中安装拦截器
所有使用 IceRPC 发送的拦截器都可以在有或没有 DI 的情况下使用,并使用调用中的通信 features 。 例如,重试拦截器使用 IServerAddressFeature 与连接缓存通信,以协调复制服务器上的重试。
这些拦截器可以安装在管道或 IInvokerBuilder 中。
例如:
// Construct an invocation pipeline using Microsoft's DI container.
using IceRpc.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
...
// Add a new IInvoker singleton configured with an action.
services
.AddIceRpcClientConnection()
.AddIceRpcInvoker(builder =>
builder
.UseLogger()
.Into<ClientConnection>())
这里,UseLogger 是 IceRpc.Logger 组件提供的扩展方法。 此扩展方法适用于实现 IServiceProvider 的任何 DI 容器,例如 Microsoft 的 DI 容器和 Simple Injector 的容器。
UseLogger 方法的实现只是从 DI 容器中检索一个记录器实例, 然后用这个实例创建一个新的拦截器:
public static IInvokerBuilder UseLogger(this IInvokerBuilder builder) =>
builder.ServiceProvider.GetService(typeof(ILogger<LoggerInterceptor>)) is ILogger logger ?
builder.Use(next => new LoggerInterceptor(next, logger)) :
throw new InvalidOperationException(
$"Could not find service of type '{nameof(ILogger<LoggerInterceptor>)}' in the service container.");
我们建议在创建自己的拦截器时遵循相同的模式,并为 Pipeline 和 IInvokerBuilder 提供使用扩展方法。
通常不鼓励在运行时调用 DI 容器—它是反模式的服务定位器。在这里,应该将
UseLogger扩展方法视为不受此规则约束的基础设施代码。
收尾
最近写的都是基础相关的概念,大家看看就行,以官方为主更为妙哉。
作者结语
- 一直做,不停做,才能提升速度
- 翻译的不好,请手下留情,谢谢
- 觉得还不错的话,点个赞哦
- 如果对我有点小兴趣,如可加我哦,一起探讨人生,探讨道的世界。

IceRPC之依赖注入>快乐的RPC的更多相关文章
- Java 控制反转和依赖注入模式【翻译】【整理】
Inversion of Control Containers and the Dependency Injection pattern --Martin Fowler 本文内容 Component ...
- 从celery rabbitmq with docker-compose 引出对容器、依赖注入、TDD的感悟
用docker配置项目管理系统taiga的时候,不是我一个人遇到这个问题.https://github.com/douglasmiranda/docker-taiga/issues/5 问题描述: 用 ...
- Ioc 器管理的应用程序设计,前奏:容器属于哪里? 控制容器的反转和依赖注入模式
Ioc 器管理的应用程序设计,前奏:容器属于哪里? 我将讨论一些我认为应该应用于“容器管理”应用程序设计的原则. 模式1:服务字典 字典或关联数组是我们在软件工程中学到的第一个构造. 很容易看到使 ...
- 依赖注入【转自知乎 PHP】
第一章:小明和他的手机 从前有个人叫小明 小明有三大爱好,抽烟,喝酒…… 咳咳,不好意思,走错片场了.应该是逛知乎.玩王者农药和抢微信红包 <img src="https://pic1 ...
- 30个类手写Spring核心原理之依赖注入功能(3)
本文节选自<Spring 5核心原理> 在之前的源码分析中我们已经了解到,依赖注入(DI)的入口是getBean()方法,前面的IoC手写部分基本流程已通.先在GPApplicationC ...
- 【.NET6+WPF】WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入
前言:在C/S架构上,WPF无疑已经是"桌面一霸"了.在.NET生态环境中,很多小伙伴还在使用Winform开发C/S架构的桌面应用.但是WPF也有很多年的历史了,并且基于MVVM ...
- webapi - 使用依赖注入
本篇将要和大家分享的是webapi中如何使用依赖注入,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity:由于快过年这段时间打算 ...
- ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入
原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...
- 在WPF中使用依赖注入的方式创建视图
在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...
- MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息
MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...
随机推荐
- 技术解读:现代化工具链在大规模 C++ 项目中的运用 | 龙蜥技术
简介: 本文详细介绍我们在实际工作中的大型 C++ 项目中现代化工具链的实践以及结果. 编者按:C++ 语言与编译器一直都在持续演进,出现了许多令人振奋的新特性,同时还有许多新特性在孵化阶.除此之外, ...
- 从零开始入门 K8s | 调度器的调度流程和算法介绍
导读:Kubernetes 作为当下最流行的容器自动化运维平台,以声明式实现了灵活的容器编排,本文以 v1.16 版本为基础详细介绍了 K8s 的基本调度框架.流程,以及主要的过滤器.Score 算法 ...
- 10个Bug环环相扣,你能解开几个?
简介:由阿里云云效主办的2021年第3届83行代码挑战赛已经收官.超2万人围观,近4000人参赛,85个团队组团来战.大赛采用游戏闯关玩儿法,融合元宇宙科幻和剧本杀元素,让一众开发者玩得不亦乐乎. ...
- [FE] iframe 相关选项 x-frame-options: 设置 meta 标签无效 & helmet
The X-Frame-Options HTTP 响应头是用来给浏览器 指示允许一个页面 可否在 <frame>, <iframe>, <embed> 或者 < ...
- dotnet 在 UOS 统信系统上运行 UNO 程序输入时闪烁黑屏问题
本文记录我在虚拟机内安装了 UOS 统信系统,运行 UNO 的基于 Skia 的 Gtk 应用程序时,在输入的过程中不断窗口闪黑问题 本质上说这个问题和 UNO 毫无关系,这是一个 OpenGL 硬件 ...
- GitHub 的 Action 接入 Stryker.NET 进行自动化测试单元测试鲁棒性
假设有一个捣蛋的小伙伴加入了你的团队,这个捣蛋的小伙伴喜欢乱改代码,请问此时的单元测试能否拦住这些逗比行为?如果不能拦住逗比行为,是否代表着单元测试有所欠缺,或者有某些分支逻辑没有考虑到.本文将告诉大 ...
- ESP32 使用LVGL案例
一.完成LVGL移植 在使用LVGL提供的测试案例时,需要先移植LVGL,不明白的小伙伴看我之前的笔记 esp-idf 移植 lvgl8.3.3. 移植完成后的项目文件如下图所示 二.添加需要的测试案 ...
- STM32F10x 串口使用DMA
一.DMA简介 DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载.否则,CPU 需要 ...
- Photoshop批量替换图层的方法
平时做图片,应该有遇到这样的场景,比如P奖状.P邀请函,内容是一样的,但是图片上的名字是不一样的,要是要P100张的话,一个个手动复制改名字肯定会吐血(╯°□°)╯︵ ┻━┻ Photoshop里有个 ...
- 原生js写悬浮广告效果
网上抄的,改成vue写法失败,下一篇是自己写的vue版本的 <html> <head> <meta http-equiv="Content-Type" ...