IceRPC之依赖注入快乐的RPC

news/2025/1/21 6:23:18/文章来源:https://www.cnblogs.com/xlgwr/p/18238532

作者引言

很高兴啊,我们来到了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 提供如IDispatcherBuilderIInvokerBuilder IceRpc.Deadline.dll之类的抽象以及其他拦截器/中间件组件,为IDispatcherBuilderIInvokerBuilder提供了扩展方法。这些扩展方法与 DI 容器无关。
  • IceRpc.Extensions.DependencyInjection.dll 为 Microsoft 的 DI 容器提供支持代码。这包括 IServiceCollection 的各种扩展方法,例如 AddIceRpcServerAddIceRpcClientConnection,以及 IDispatcherBuilderIInvokerBuilder 的实现。
--- title: 程序集依赖图 --- flowchart BTdi([Microsoft.Extensions.DependencyInjection.Abstractions.dll])logging([Microsoft.Extensions.Logging.Abstractions.dll])options([Microsoft.Extensions.Options.dll])IceRpc.dll --> loggingIceRpc.Logger.dll --> IceRpc.dllIceRpc.Logger.dll --> loggingIceRpc.Deadline.dll --> IceRpc.dllIceRpc.Extensions.DependencyInjection.dll --> diIceRpc.Extensions.DependencyInjection.dll --> optionsIceRpc.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>());

这里,UseLoggerIceRpc.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.");

我们建议在创建自己的标准中间件时遵循相同的模式,并为 RouterIDispatcherBuilder 提供使用扩展方法。

通常不鼓励在运行时调用 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 deadlineInfodeadlineInfo.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>())

这里,UseLoggerIceRpc.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.");

我们建议在创建自己的拦截器时遵循相同的模式,并为 PipelineIInvokerBuilder 提供使用扩展方法。

通常不鼓励在运行时调用 DI 容器—它是反模式的服务定位器。在这里,应该将 UseLogger 扩展方法视为不受此规则约束的基础设施代码。

收尾

最近写的都是基础相关的概念,大家看看就行,以官方为主更为妙哉。

作者结语

  • 一直做,不停做,才能提升速度
  • 翻译的不好,请手下留情,谢谢
  • 觉得还不错的话,点个
  • 如果对我有点小兴趣,如可加我哦,一起探讨人生,探讨道的世界
    image

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

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

相关文章

图床

表视图触发器本文来自博客园,作者:zhywyt,转载请注明原文链接:https://www.cnblogs.com/zhywyt/p/18238527

阅读习惯

本学期开始时我的阅读量大约在50小时左右,通过这一学期读电子书,我的阅读时长为200小时,大约增加了150小时,在这150小时中,我每天会抽出半个小时来读书,这其中包括课外书和娄老师推荐的书目,比方说《学会提问》、《批判性思维》,目前在书架上的书有四本,在每天坚持读书…

纯CSS+单个div实现抖音LOGO

纯CSS+单个div就能绘制抖音LOGO。 主要借助了两个伪元素实现了整体结构,借助了 drop-shadow 生成一层整体阴影。 drop-shadow 只能是单层阴影,所以另一层阴影需要多尝试。 contrast(150%) brightness(110%) 则可以增强图像的对比度和亮度,更贴近抖音LOGO的效果。纯CSS+单个d…

完美解决SqlServer2012启动报错(cannot find one or more components.Please reinstall the application。)

出现这问题的原因是,vs组件没有安装或被卸载,重新安装这个组件即可。微软官网下载忒麻烦,这里分享一下 我用夸克网盘分享了「vs shell2010安装文件.rar」链接:https://pan.quark.cn/s/0347cf062d65

web开发之浏览器扩展插件开发-chrome浏览器扩展插件开发-入门

一.起步:开始,开发一个浏览器扩展程序: 参考文档: https://developer.chrome.google.cn/docs/extensions/get-started/tutorial/hello-world?authuser=19&%3Bhl=zh-cn&hl=zh-cn1.配置文档:manifest.json 对应文件 :新建manifest.json /popup.html / icon-green.…

Docker的资源限制

目录一、什么是资源限制1、Docker的资源限制2、内核支持Linux功能3、OOM异常4、调整/设置进程OOM评分和优先级4.1、/proc/PID/oom_score_adj4.2、/proc/PID/oom_adj4.3、/proc/PID/oom_score二、容器的内存限制1、实现原理2、命令格式及指令参数2.1、命令格式2.2、指令参数3、案…

医学图像分析入门

医学图像是什么? 医学图像是反映解剖区域内部结构或内部功能的图像,它是由一组图像元素--像素(2D)或立体像素(3D)组成的。医学图像是由采样或者重建产生的离散图像,它能将数值映射到不同的空间位置上。像素所表达的具体数值是由成像设备、成像协议、影像重建以及后期加工…

【MATLAB】去除imagesc()白边

目的:在MATLAB中去除imagesc()白边,去除图片的白边,可以将图片复制到word中的表格中显得更加紧凑。 示例代码如下: figure;imagesc(sarImageNormalization);colormap jet;axis xy; set(gca,Position,[0 0 1 1]);%消除白边实验结果: 未去除白边的效果:去除白边的效果:最终…

机器学习笔记(3): 神经网络初步

神经网络应该由若干神经元组成。前面的每一个神经元都会给到一个参数,将传递的所有参数看作一个向量 \(\vec x\),那么此神经元的净输入为: \[z = x \omega + b \]其中 \(\omega\) 称为权重向量。这里认为 \(x\) 是行向量,而 \(\omega\) 是列向量。神经元还有一个激活函数 \…

配置并集集成Sentinel微服务保护

Sentinel 微服务保护的技术有很多,但在目前国内使用较多的还是Sentinel,所以接下来我们学习Sentinel的使用。 介绍和安装 Sentinel是阿里巴巴开源的一款服务保护框架,目前已经加入SpringCloudAlibaba中。官方网站: https://sentinelguard.io/zh-cn/Sentinel 的使用可以分为…

设计模式:命令模式(Command Pattern)及实例

好家伙,0.什么是命令模式 在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。 但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。 在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组…

gRPC入门学习之旅(十)

gRPC是一个高性能、通用的开源远程过程调用(RPC)框架,基于底层HTTP/2协议标准和协议层Protobuf序列化协议开发, gRPC 客户端和服务端可以在多种环境中运行和交互。你可以用Java创建一个 gRPC 服务端,用 Go、Python、C# 来创建客户端。本系统文章详细描述了如何创建一个自己…