DubboNet 是一个面向 .NET 的 Dubbo 客户端库。它可以从 ZooKeeper 发现 Provider,依据 Provider URL 选择传输执行器,并通过经典 Dubbo TCP/Hessian2 或 Dubbo 3 Triple HTTP/JSON 调用 Java 接口,因此调用方不需要引用 Java 接口 JAR。
当前项目目标框架为 .NET 10。原生 Dubbo TCP 调用已在 Dubbo 2.7.3 Provider 上完成真实环境验证;Triple 第一期已在 Dubbo 3.3.6 Java Interface Provider 上完成真实环境验证。其他版本的支持边界请先阅读版本兼容性 / Compatibility。
- 从 ZooKeeper 的经典接口级目录
/dubbo/{interface}/providers自动发现和监听 Provider。 - 根据 Provider URL scheme 自动选择执行器:
dubbo://:NativeDubboActuatorSuite,使用 Dubbo2 TCP 帧和 Hessian2 泛化调用。tri://:TripleDubboActuatorSuite,使用 Dubbo 3.3 的 Java Interface Unary HTTP/JSON 调用。
- 支持按权重随机、平滑加权轮询、最短响应、一致性 Hash 等负载策略。
- 自动从 Dubbo 元数据中心或 Provider Telnet
ls -l获取 Java 方法签名。 - 根据实参数量和 CLR 类型推断重载,并缓存方法元数据。
- 支持调用方显式指定 Java 参数类型,用于元数据缺失、
null、包装类型和重载歧义等场景。 - 支持服务版本、分组、自定义 attachments、POJO、集合和 Map 参数。
- 暴露 Request ID、Dubbo response status、serialization id、响应 attachments 和动态原始结果。
- ZooKeeper、Provider 连接和服务驱动在多个请求之间复用。
- 主要公共 API 提供中英文 XML documentation,并随程序集/NuGet 包生成
DubboNet.xml。
应用调用
|
v
DubboClient
|-- ZooKeeper 注册中心 --> /dubbo/{interface}/providers
| |
| +-- Provider URL / 节点变更 Watch
|
|-- DubboMetadataManager
| |-- release >= 2.7.3 或未知 --> 元数据中心 FullServiceDefinition
| | |
| | +-- 失败时一次性 Telnet ls -l
| +-- release < 2.7.3 -----------> 一次性 Telnet ls -l
|
+-- DubboServiceDriver --> 负载均衡 --> 按 scheme 选择执行器
|-- dubbo:// --> NativeDubboActuatorSuite --> Dubbo TCP + Hessian2
+-- tri:// --> TripleDubboActuatorSuite --> Triple Unary HTTP/JSON
release 只决定元数据获取顺序;执行器由 Provider URL 的 scheme 决定。Provider URL 中的 dubbo=2.0.2 是经典线协议版本,version 和 group 则是服务路由信息,这几个字段不要混用。
项目文件当前声明版本为 2.1.0、NuGet 包 ID 为 DubboNet。对应版本已经发布到你的 NuGet 源时,可以执行:
dotnet add package DubboNet --version 2.1.0如果包尚未发布,或需要使用当前仓库中的最新实现,请直接引用源码项目:
<ItemGroup>
<ProjectReference Include="../DubboNet/DubboNet.csproj" />
</ItemGroup>运行和编译需要 .NET 10 SDK。项目的主要依赖是 DistributedLock.ZooKeeper 和 NHessian。
推荐创建一个长生命周期的 DubboClient,在应用关闭时释放,不要为每个请求创建新实例:
using DubboNet.Clients;
using DubboNet.DubboService.DataModle;
using var client = new DubboClient("127.0.0.1:2181");
DubboRequestResult result = await client.QueryGenericAsync(
"com.foo.JobService#getJob",
1234);
if (!result.QuerySuccess)
{
Console.WriteLine(result.ErrorMeaasge);
return;
}
Console.WriteLine(result.Result);服务和方法之间支持 #、. 或 /,例如:
com.foo.JobService#getJob
com.foo.JobService.getJob
com.foo.JobService/getJob
建议使用 #,它能让完整 Java 接口名和方法名的边界最清楚。
DubboRequestResult result = await client.QueryGenericAsync(
"com.foo.HealthService#check");当两种元数据来源都不可用时,无参数方法仍可使用空参数签名发起调用。
DubboRequestResult result = await client.QueryGenericAsync(
"com.foo.CustomerService#getCustomer",
"123",
1234L);自动推断不会只根据 JSON 武断地猜测 Java 类型。客户端先取得服务方法签名,再根据方法名、参数数量和 CLR 实参类型选择唯一重载。无法唯一确定时会抛出 DubboMetadataException。
尤其需要注意:
- C#
1234是int,1234L是long。 - 仅从值无法可靠地区分 Java
int与java.lang.Integer,或long与java.lang.Long。 null无法提供 CLR 类型信息。- 同参数数量且类型兼容的多个 Java 重载可能仍然有歧义。
以上情况优先使用显式类型重载。
显式重载不查询元数据中心,也不连接 Telnet,是生产环境中最确定的调用方式:
DubboRequestResult job = await client.QueryGenericAsync(
"com.foo.JobService#getJob",
new[] { "java.lang.Integer" },
1234);
DubboRequestResult customer = await client.QueryGenericAsync(
"com.foo.CustomerService#getCustomer",
new[] { "java.lang.String", "java.lang.Long" },
"123",
1234L);数组中的类型必须是 Provider $invoke 能加载的准确 Java 类型名,例如:
- 基础类型:
int、long、boolean、double - 包装类型:
java.lang.Integer、java.lang.Long、java.lang.Boolean - 集合和数组:
java.util.List、java.util.Map、java.lang.String[] - POJO:
com.foo.api.dto.CustomerRequest
public sealed class JobDto
{
public long Id { get; set; }
public string? Name { get; set; }
}
DubboRequestResult<JobDto> result =
await client.QueryGenericAsync<JobDto>(
"com.foo.JobService#getJob",
new[] { "java.lang.Long" },
1234L);
if (result.QuerySuccess)
{
JobDto? job = result.ResultModle;
}ResultModle 使用 System.Text.Json 从 Result 反序列化。如果本地反序列化失败,详细信息写入 ErrorMeaasge;它与 Provider 业务返回是否成功是不同概念。
DubboInvocation 适合设置准确签名、服务版本、分组和自定义 attachments:
using DubboNet.DubboService.DataModle;
var invocation = new DubboInvocation(
"com.foo.UserService",
"save",
new[] { "com.foo.api.dto.UserRequest" },
new object[]
{
new
{
name = "demo",
age = 18
}
})
{
Version = "1.0.0",
Group = "prod",
Attachments = new Dictionary<string, string>
{
["traceId"] = "example-trace-id"
}
};
DubboRequestResult result = await client.QueryGenericAsync(invocation);对于 POJO 参数,客户端会根据 ParameterTypes 自动补充泛化调用需要的 class=<Java FQCN>。如果 ParameterTypes 为空,DubboClient 会尝试通过元数据自动推断。
原有 QueryAsync 接口仍可使用:
DubboRequestResult result = await client.QueryAsync(
"com.foo.JobService#getJob",
"1234");
DubboRequestResult<MyResponse> typed =
await client.QueryAsync<MyResponse, long>(
"com.foo.JobService#getJob",
1234L);在 dubbo:// Provider 上,QueryAsync 最终也会尝试用元数据解析准确签名。新代码建议使用 QueryGenericAsync;当类型存在歧义时使用显式 Java 类型重载。
不需要注册中心、已经知道 Provider IP 和端口时,可以直接创建原生执行器。此方式不会提供服务发现、负载均衡或元数据推断,因此应始终传入准确 Java 签名:
using DubboNet.DubboService;
using DubboNet.DubboService.DataModle;
using var suite = new NativeDubboActuatorSuite(
"127.0.0.1",
20880,
new DubboActuatorSuiteConf
{
DubboRequestTimeout = 10_000
});
var invocation = new DubboInvocation(
"com.foo.JobService",
"getJob",
new[] { "java.lang.Integer" },
new object[] { 1234 });
DubboRequestResult result = await suite.SendQuery(invocation);Dubbo 3.3+ Java Interface 服务也可以直接使用 Triple 第一期执行器。请求会发送到
/{service}/{method},正文始终是 JSON 参数数组,并携带服务 version/group 路由头:
using var triple = new TripleDubboActuatorSuite(
"127.0.0.1",
50051,
new DubboActuatorSuiteConf { DubboRequestTimeout = 10_000 });
var invocation = new DubboInvocation(
"com.foo.DataTypeService",
"negate",
new[] { "boolean" },
new object[] { false })
{
Version = "1.0.0",
Group = "default"
};
DubboRequestResult result = await triple.SendQuery(invocation);Provider 开放 Dubbo Telnet 命令时,也可以显式使用 DubboActuator 做诊断:
using DubboNet.DubboService;
using var telnet = new DubboActuator("127.0.0.1", 20880);
var methods = await telnet.GetDubboServiceFuncAsync(
"com.foo.JobService");
var status = await telnet.GetDubboStatusInfoAsync();DubboActuator.SendQuery 和 TelnetDubboActuatorSuite 也保留了 Telnet invoke 业务调用能力,但依赖 Provider 开启 Telnet。新业务调用建议使用 NativeDubboActuatorSuite 或 DubboClient,Telnet 主要用于 ls、status、ps、trace 等诊断。
可以在调用前查看方法的所有重载:
using DubboNet.Clients.DataModle;
IReadOnlyList<DubboMethodMetadata> overloads =
await client.GetMethodMetadataAsync(
"com.foo.JobService",
"getJob");
// 也可以传完整 endpoint。
IReadOnlyList<DubboMethodMetadata> sameOverloads =
await client.GetMethodMetadataAsync(
"com.foo.JobService#getJob");
IReadOnlyList<DubboMethodMetadata> allMethods =
await client.GetServiceMethodsMetadataAsync(
"com.foo.JobService");
foreach (DubboMethodMetadata method in overloads)
{
Console.WriteLine(
$"[{method.MetadataSource}] {method.ReturnType} " +
$"{method.Name}({string.Join(", ", method.ParameterTypes)})");
}
// 仅从元数据中心读取 FullServiceDefinition.types,适合 DubboTester
// 生成 POJO/集合/嵌套参数编辑器;该接口不会使用 Telnet 回退。
IReadOnlyList<DubboTypeMetadata> types =
await client.GetServiceTypesMetadataAsync(
"com.foo.JobService");
foreach (DubboTypeMetadata type in types)
{
Console.WriteLine(type.Type);
foreach (var property in type.Properties)
{
Console.WriteLine($" {property.Key}: {property.Value.Type}");
}
}主要字段包括:
ParameterTypes、ReturnType:准确 Java 签名。MetadataSource:MetadataCenter或Telnet。Application、Version、Group:对应 Provider 信息。MetadataPath:ZooKeeper 节点或telnet://来源地址。TypeDefinitions:FullServiceDefinition 中的 POJO、集合、枚举和引用定义;Telnet 来源通常没有这部分信息。MetadataVersion、LoadedAt:ZooKeeper 数据版本和读取时间。
GetServiceTypesMetadataAsync 会先对完整元数据叶子路径执行 ZooKeeper exists 并安装 watcher,确认节点存在后才读取数据。节点不存在、连接不可用或文档无效时会抛出包含预期路径的 DubboMetadataException;因为 Telnet ls -l 不包含 types,该接口不会退回 Telnet。成功结果和稳定的“节点不存在”结论都会按服务缓存,节点后续创建或修改时 watcher 会刷新缓存。
客户端读取 Provider URL 的 release 字段来选择元数据来源:
Provider release |
获取顺序 |
|---|---|
>= 2.7.3 |
元数据中心优先,失败后 Telnet ls -l |
已知且 < 2.7.3 |
直接尝试 Telnet ls -l |
| 缺失或格式无法识别 | 元数据中心优先,失败后 Telnet ls -l |
| 多个 Provider 版本混合 | 只要存在 >= 2.7.3 或未知版本,就优先元数据中心 |
元数据中心节点按以下结构读取:
{MetadataRootPath}/metadata/{interface}/{version?}/{group?}/provider/{application}
例如:
/dubbo/metadata/com.foo.JobService/provider/job-service
行为说明:
MetadataCenterAddress不填写时复用注册中心地址和同一个 ZooKeeper 客户端。- FullServiceDefinition 成功加载后,会对数据节点安装 ZooKeeper watch。
- 节点修改、删除、后续创建,Provider application/version/group 变化以及 ZooKeeper 会话恢复都会触发缓存刷新。
- Telnet 元数据按服务缓存;一次探测可能依次尝试该服务的多个
dubbo://Provider,直到成功。 - Telnet 成功结果和“Telnet 不可用”的失败结论都会缓存,一个
DubboClient生命周期内不会对同一服务反复连接。 - 如果之后创建了已被 watch 的元数据节点,缓存会切回优先级更高的 FullServiceDefinition。
- 元数据中心瞬时连接失败不会永久缓存;后续请求会重试元数据中心,同时复用已有的 Telnet 正缓存或负缓存。
- 元数据中心文档存在但缺少目标方法或重载时,客户端会再用同一份一次性 Telnet 结果补充。
- Telnet 只用于获取方法签名和显式诊断,原生业务调用仍使用 Dubbo TCP。
- Telnet 回退只能连接注册中心中
dubbo://Provider 的地址和端口,不支持另行配置独立 QoS/Telnet 端口。
如果运行期间刚刚为某个服务开启 Telnet,而该 DubboClient 已缓存“Telnet 不可用”,请重新创建客户端实例;这是避免每次调用重复建立失败连接的设计选择。
using var client = new DubboClient(
"zk-1:2181,zk-2:2181",
new DubboClient.DubboClientConf
{
DubboRootPath = "/dubbo/",
MetadataCenterAddress = "metadata-zk:2181", // 可选
MetadataRootPath = "/dubbo", // 可选
DubboRequestTimeout = 60_000,
TelnetMetadataTimeout = 10_000,
MaintainServiceNum = 20,
NowLoadBalanceMode = DubboClient.LoadBalanceMode.Random
});ZooKeeper 地址支持多个节点,以逗号分隔。认证字符串可以写成:
zk-1:2181,zk-2:2181 [digest user:password]
| 配置项 | 默认值 | 说明 |
|---|---|---|
DubboRootPath |
/dubbo/ |
经典接口级注册目录根路径 |
MetadataCenterAddress |
注册中心地址 | 元数据中心 ZooKeeper;相同地址会复用连接 |
MetadataRootPath |
DubboRootPath |
metadata-report group 根路径,内部会规范为无结尾 / |
DubboRequestTimeout |
60000 ms |
业务请求最大等待时间 |
TelnetMetadataTimeout |
10000 ms |
单次 Telnet 元数据探测超时;非正数会恢复默认值 |
MaintainServiceNum |
20 |
可复用服务驱动数量;0 表示不限制 |
NowLoadBalanceMode |
Random |
当前负载策略 |
DubboActuatorSuiteMaxConnections |
20 |
执行器最大连接数;主要影响 Telnet 连接池,原生执行器使用单 TCP 连接多路复用 |
DubboActuatorSuiteAssistConnectionAliveTime |
300 秒 |
Telnet 辅助连接空闲释放时间;0 表示不主动释放 |
DubboActuatorSuiteMasterConnectionAliveTime |
1200 秒 |
Telnet 主连接空闲释放时间;0 表示不主动释放 |
DefaultServiceName |
null |
省略服务名时使用的默认接口名 |
DefaultFuncName |
null |
endpoint 为空时使用的默认方法名 |
负载策略说明:
Random:加权随机。RoundRobin:平滑加权轮询。ShortestResponse:优先选择近期响应较快的节点。ConsistentHash:根据请求内容计算一致性 Hash。P2CLoadBalance:比较两次随机候选的负载;无法获取 Provider load 时退化为随机候选。LeastActive:当前尚未实现,会退化为Random。
DubboRequestResult 的常用字段:
| 字段 | 含义 |
|---|---|
QuerySuccess |
传输和 Dubbo 调用层是否成功,不代表业务成功 |
Result |
响应值转换后的 JSON 字符串 |
RawResult |
转换为 JSON 前的动态 .NET 值,仅原生 Dubbo 执行器提供 |
ErrorMeaasge |
连接、超时、协议、Provider 异常或本地反序列化错误详情 |
RequestElapsed |
包含网络等待的客户端请求耗时,毫秒 |
ServiceElapsed |
Telnet/HTTP 模式可用的服务耗时;原生 Dubbo 默认不提供 Provider 执行耗时 |
ServiceElapsedAvailable |
ServiceElapsed 是否有实际意义 |
RequestId |
原生 Dubbo Request ID |
ResponseStatus |
原生 Dubbo response status;20 表示协议成功 |
SerializationId |
Dubbo 帧中的序列化 ID;Hessian2 为 2 |
ResponseAttachments |
原生 Dubbo 响应 attachments |
下面这种响应中,即使业务字段 success 为 false,只要传输、协议和 Provider 方法执行正常,QuerySuccess 仍可能是 true:
{
"success": false,
"code": "JOB_NOT_FOUND",
"message": "job does not exist"
}因此应分别处理两层状态:
if (!result.QuerySuccess)
{
// 连接、超时、Dubbo status、Provider 抛出的异常等调用层错误。
Console.WriteLine(result.ErrorMeaasge);
}
else
{
// 再根据 Result 或 ResultModle 中的 code/success 判断业务是否成功。
}下表区分“已经真实验证”和“满足条件时的兼容路径”,不表示对整个 Dubbo 版本线作无条件承诺。
| 组件或版本 | 支持状态 | 说明 |
|---|---|---|
| .NET 10 | 支持 | 当前库、示例和测试项目均只目标化 net10.0 |
| .NET 6/7/8/9 | 当前包不支持 | 项目已从 net6.0 改为 net10.0,未提供多目标构建 |
| ZooKeeper 经典接口级注册 | 支持 | 读取 /dubbo/{interface}/providers 并注册 watch |
| Nacos、Consul、Kubernetes 等注册中心 | 未实现 | 当前 DubboClient 只实现 ZooKeeper 发现 |
Dubbo 2.7.3 + dubbo:// + Hessian2 |
真实验证 | 已验证无参数、单参数、双参数调用以及元数据/Telnet 回退 |
Dubbo >= 2.7.3 的其他版本 |
条件兼容,未逐版本验证 | 需要经典 ZooKeeper 接口级目录、dubbo://、Hessian2 和 $invoke 泛化能力 |
Dubbo < 2.7.3 |
条件兼容,未逐版本验证 | 自动签名依赖 Provider Telnet;也可完全绕过元数据并显式传入 Java 类型 |
Dubbo 3.x 的 classic dubbo:// 兼容模式 |
条件兼容,未完整验证 | 仅限继续发布经典接口级 ZooKeeper URL 并接受 Dubbo2/Hessian2 $invoke 的 Provider |
| Dubbo 3 应用级服务发现 | 未实现 | 未实现 Dubbo 3 application-level service discovery 元数据布局 |
Dubbo 3.3.6 + tri:// + Java Interface Unary JSON |
真实验证(第一期) | 支持 HTTP/1.1、application/json、version/group/timeout 头和 attachments |
| Triple Protobuf/IDL、流式调用、gRPC framing | 未实现 | 第一期仅覆盖 Java Interface Unary HTTP/JSON,不宣称完整 Triple/gRPC 能力 |
| Dubbo Telnet/QoS | 可选 | 仅在 Provider 地址和端口开放相关命令时用于元数据兜底和诊断 |
原生执行器当前有以下边界:
- 使用 16 字节经典 Dubbo2 TCP 帧头,普通双向 Hessian2 请求 flag 为
0xc2。 - 请求体中的 Dubbo protocol version 固定为
2.0.2,它与 Provider 框架release不是同一个版本。 - 只发送
$invoke泛化调用,不发送强类型 Java 接口调用。 - 仅支持 Hessian2,serialization id 为
2。Provider 返回其他序列化 ID 时会失败。 - Provider URL 中的
serialization和prefer.serialization当前不会切换客户端编码器。 - 支持常用标量、字符串、日期、二进制、数组、集合、Map 和 POJO;未覆盖的 Hessian2 tag 会作为协议错误返回。
- POJO 通过带
class的泛化 Map 编码;字段名和 Java DTO 属性必须匹配。 - Telnet 输出中的源码式泛型参数会先做 Java 类型擦除,例如
java.util.Map<String, Long>会转换成java.util.Map。 - 单个原生 TCP 连接按 Request ID 多路复用并发请求;写入串行,响应可以乱序返回。
- 单个收到的 response body 默认上限为 8 MiB,当前没有
DubboClientConf配置项修改该限制。 - 支持应答 Provider 发来的双向 event/heartbeat 帧。
- 不提供 TLS 传输或 Dubbo 自定义序列化扩展。
- 请求写入失败后不会自动重放,以避免 Provider 已执行但客户端误判失败时产生重复业务操作;后续请求会重新建连。
- ZooKeeper Provider URL 的 host 当前必须是 IP 地址,域名/主机名不会自动解析。
更详细的帧头、请求体字段和响应结果 flag 请阅读 Docs/NativeDubboProtocol.md。
Triple 第一期的请求格式、路由头和明确边界请阅读 Docs/TripleProtocol.md。
- 复用
DubboClient。 长生命周期实例才能充分复用 ZooKeeper、Provider TCP 连接、服务驱动和元数据缓存。 - 优先使用
QueryGenericAsync。 它清楚地区分参数对象和 Java 签名;旧QueryAsync主要用于兼容已有代码。 - 关键接口显式传类型。 对重载、包装类型、
null、集合和 POJO,显式 Java 类型比运行时推断更稳定。 - 优先建设元数据中心。 Telnet 是可选的兜底能力,不应成为生产调用的唯一元数据来源;不要把诊断端口暴露到不可信网络。
- 确认 Provider URL 完整。 元数据中心定位依赖
application,服务路由还可能依赖version和group。 - 分别判断调用成功和业务成功。 先检查
QuerySuccess,再检查业务响应中的code、success等字段。 - 谨慎重试非幂等请求。 超时或连接中断不代表 Provider 一定没有执行,请由业务幂等键和重试策略兜底。
- 根据服务数量配置缓存。 大量调用不同接口时提高
MaintainServiceNum,或设为0;同时关注连接和内存占用。 - 原生调用优先使用
Random、RoundRobin或ConsistentHash。LeastActive尚未实现,P2C 在没有 Provider load 时会退化。 - 部署前用真实 Provider 做兼容测试。 尤其是未在兼容矩阵中标记为“真实验证”的 Dubbo 版本、复杂 POJO 和自定义 Hessian 类型。
检查:
DubboRootPath是否与注册中心一致。/dubbo/{完整接口名}/providers是否存在有效子节点。- Provider URL 是否以
dubbo://或tri://开头。 - Provider host 是否为 IP 地址,而不是域名。
- 接口名、服务
version和group是否正确。
服务发现失败通常以 QuerySuccess=false 的 DubboRequestResult 返回,详情在 ErrorMeaasge。
异常会分别说明元数据中心和 Telnet 的失败原因。依次检查:
-
Provider URL 的
release、application、version和group。 -
MetadataCenterAddress和MetadataRootPath是否指向实际元数据中心。 -
预期 FullServiceDefinition 节点是否存在:
{root}/metadata/{interface}/{version?}/{group?}/provider/{application} -
Provider 是否配置并成功上报 metadata-report。只有 consumer 节点不代表存在 provider 方法定义。
-
Provider 注册的
dubbo://地址和端口是否开放 Telnetls -l。
无法修复元数据来源时,按异常建议改用显式类型重载:
await client.QueryGenericAsync(
"com.foo.JobService#getJob",
new[] { "java.lang.Integer" },
1234);查看所有候选签名:
var methods = await client.GetMethodMetadataAsync(
"com.foo.JobService",
"getJob");然后使用显式 Java 类型。不要仅通过把 1234 改成 1234L 来区分 primitive 和 wrapper;long 与 java.lang.Long 仍需要准确签名。
原生执行器只支持 Hessian2。确认 Provider 接受 Hessian2,并且响应帧 serialization id 为 2。当前不会根据 Provider URL 自动切换到 Fastjson2、Kryo、FST、Protobuf 等编码器。
确认 Provider 使用 Dubbo 3.3+ 并开放 Java Interface 的 HTTP/JSON 访问。第一期执行器会向
http://{host}:{port}/{service}/{method} 发送 HTTP/1.1 JSON POST,正文必须是参数数组,
单参数也应为 [value]。有多个 version/group 时还要保证注册 URL 中这两个字段准确。
Dubbo 3.3.6 的默认 Triple HTTP/JSON 映射不能可靠区分全部 Java 重载。通过
DubboClient 调用时,检测到重载方法会在负载均衡前限定使用 dubbo:// 原生协议节点;
若只有 tri:// 节点则返回明确错误。需要通过 Triple 暴露重载时,建议在 Provider 端为
各重载声明不同的 REST 路由。
第一期不支持 Protobuf/IDL、流式调用或 gRPC framing;这些服务不能通过当前的
TripleDubboActuatorSuite 调用。
- 调整
DubboRequestTimeout。 - 检查
ErrorMeaasge和 Provider 日志。 - 原生连接会在后续请求时重新建立,但失败中的业务请求不会自动重放。
- 对非幂等方法,不要在无法确认 Provider 是否执行的情况下盲目重试。
这是预期行为。QuerySuccess 只表示调用层成功;继续解析 Result 或 ResultModle 中的业务状态。
需要 .NET 10 SDK:
dotnet restore DubboNet.sln
dotnet build DubboNet.csproj --no-restore
dotnet test Tests/UnitTestForDubboNet/UnitTestForDubboNet.csproj --no-restore原生协议集成测试默认连接公开测试注册中心 110.40.136.183:2181,也可以把其他
ZooKeeper 地址作为第一个参数传入:
dotnet run \
--project Tests/NativeDubboIntegration/NativeDubboIntegration.csproj \
-- 110.40.136.183:2181测试矩阵覆盖 Dubbo 2.7.23、3.1.11、3.2.20 和 3.3.6,并验证元数据缓存、
自动签名推断、显式 Java 类型、强类型返回、DubboInvocation、旧 QueryAsync
兼容入口、Provider 异常,以及 Dubbo TCP/Hessian2 和 Triple HTTP/JSON 的明确直连。
测试使用专门准备的 com.example.dubbonet 服务;如传入其他 ZooKeeper 地址,需确保
存在相同的根路径和测试服务。程序以非零退出码报告失败,可直接用于手工验收或 CI。
仓库通过 .github/workflows/publish-nuget.yml 自动发布正式版本。创建并发布 GitHub
Release 后,工作流会把 Release Tag(支持 2.1.0 或 v2.1.0)作为包版本,依次运行
单元测试、打包,并将同一个 .nupkg 发布到 GitHub Packages 和 nuget.org。
nuget.org 使用 Trusted Publishing/OIDC 颁发的临时密钥,不在仓库中保存长期 API Key。 首次启用时,需要在 nuget.org 为包所有者创建以下 Trusted Publishing Policy:
- Repository Owner:
lulianqi - Repository:
DubboNet - Workflow File:
publish-nuget.yml - Environment:
release
GitHub Packages 使用工作流自带的 GITHUB_TOKEN;首次发布后可在 Package settings 中
确认包的可见性。包通过项目中的 RepositoryUrl 自动关联到本仓库。
本项目使用 MIT License。