跳到主要内容
版本:4.0

调用上下文

定义

命名空间:
TouchSocket.Rpc
安装:
dotnet add package TouchSocket.Rpc

一、说明

Rpc服务的调用是无状态的,即只知道当前服务被调用,但无法得知是被谁调用,这个问题给日志记录、Rpc回调等带来了很多麻烦事。所以我们在设计Rpc时,也设计了调用上下文获取。

在上下文中可以获得调用者Caller等信息,可以获得调用的IP或其他信息。

说明

调用上下文(ICallContext)实例每次请求都会创建,所以,不要在上下文中存放一些需要长期使用的数据。

二、使用

2.1 通过传参获得

当服务是单例注册时,服务方法可能会被并发调用,所以,调用上下文必须从参数获得传入。

步骤:

定义的服务方法的第一个参数使用ICallContext或其派生类(例如:DmtpRpc可以使用IDmtpRpcCallContext)。

🔄 正在加载代码...
提示

在单例服务中,通过参数传递调用上下文可以确保在并发调用时,每个调用都能获取到正确的上下文信息。

2.2 通过瞬时生命周期获取

当服务是瞬态注册时,每次调用服务会创建新的实例,所以当前方法只会被当前调用者拥有,所以,调用上下文会从属性直接注入。

步骤:

  1. 继承TransientRpcServer或者实现ITransientRpcServer接口。
🔄 正在加载代码...

或使用泛型上下文:

🔄 正在加载代码...
提示

瞬态服务每次调用都会创建新的实例,因此可以直接通过this.CallContext属性访问调用上下文,无需通过参数传递。

2.3 通过IRpcCallContextAccessor服务获取

不管在单例,还是瞬态的Rpc服务,都可以通过IRpcCallContextAccessor服务获取到当前调用的上下文。

首先,需要在容器中注册IRpcCallContextAccessor服务。

.ConfigureContainer(a =>
{
a.AddRpcCallContextAccessor();
});

然后,在Rpc服务中,通过IRpcCallContextAccessor服务获取到当前调用的上下文。

🔄 正在加载代码...
提示

该方式是通过AsyncLocal的方式实现的,所以,即使把IRpcCallContextAccessor保存到静态变量中,也能正常获取到正确的CallContext。但前提是,获取流程在调用上下文生命周期内,否则,可能会获取到错误的CallContext

三、取消任务

一般的,Rpc在执行时,如遇到异常,或主动操作,会自动取消任务。所以我们在调用上下文ICallContext接口中也规范了取消任务的方法。

下列将以DmtpRpc为例,介绍如何取消任务。

🔄 正在加载代码...
提示

由于Rpc框架仅约束了取消任务的接口,并无实际实现。所以取消任务的时机,完全取决于具体Rpc框架的实现者。例如:对于DmtpRpc,当连接断开或主动取消任务时,均会触发取消任务。

同时,如果想自己手动取消任务,也可以在调用上下文生命周期内的任意地方,使用callContext.Cancel()来取消任务。

四、调用上下文属性

调用上下文是所有Rpc均支持的(包括DmtpRpcJsonRpcXmlRpcWebApi)。

但是由于不同的Rpc实现方式,其调用上下文参数的类型也不同。

一般的:

  • Caller属性就是调用的触发终端。例如:使用DmtpRpc-Tcp,由客户端调用服务器时,Caller就是TcpDmtpSessionClient
  • RpcMethod属性就是调用的触发方法。
  • 其他参数可以参阅注释帮助理解。

五、示例代码