后端微服务【免费下载链接】orleansCloud Native application framework for .NET项目地址https://gitcode.com/gh_mirrors/or/orleans点击查看免费下载Orleans 的源生成器source generator会为每个 Grain 方法自动生成代理proxy与请求request类型构成 RPC 调用面。对于大多数应用而言Task、ValueTask、IAsyncEnumerableT已足够但当库需要提供明确完成、取消、失败、生命周期、分配与并发语义的调用抽象时可以通过自定义返回类型 自定义 invokable 请求基类来扩展这套生成面。本文以仓库中的完整示例 CustomGrainCallReturnType 为主线讲解InvokableBaseTypeAttribute、ReturnValueProxyAttribute、GeneratedActivatorConstructorAttribute等扩展点的注册位置、解析优先级、验证要求与跨程序集发布策略并结合源码说明底层工作原理。扩展点概述什么时候需要自定义返回类型Orleans 会为实现 Grain 调用的代理与请求类型生成代码。高级库可以将一个返回类型与一个自定义 invokable 请求基类关联从而扩展生成的 RPC 表面返回类型定义了面向应用方的调用模型请求基类则决定了生成的请求如何进入 Orleans 运行时、目标结果如何变成响应。适用场景是库需要一种具备显式语义的调用抽象而这种语义超出Task、ValueTask或IAsyncEnumerableT所能表达的范围。此时库必须自己拥有该抽象的完成completion、取消cancellation、失败failure、生命周期lifetime、分配allocation与并发concurrency契约。例如示例中的GrainCallT是基于任务task-backed的返回类型调用生成的代理会立即发起一次 Orleans 请求返回的值可被多次 await、缓存终止结果并通过底层任务传播远端失败。完整可运行应用见 samples 目录中的 CustomGrainCallReturnType 条目其核心实现位于 samples/CustomGrainCallReturnType/。定义一个可等待的返回类型GrainCallT是面向应用的返回类型。下面这段代码来自文档 snippet CustomGrainCallReturnType.cs与仓库示例 GrainCall.cs 一一对应[InvokableBaseType( typeof(GrainReference), typeof(GrainCall), typeof(GrainCallRequest))] public sealed class GrainCallT { private readonly TaskT? _task; private GrainCall(TaskT? task) _task task; public bool IsCompleted _task.IsCompleted; public TaskT? AsTask() _task; public TaskAwaiterT? GetAwaiter() _task.GetAwaiter(); public static GrainCallT FromResult(T? value) new(Task.FromResult(value)); internal static GrainCallT FromInvocation(ValueTaskT? invocation) new(invocation.AsTask()); }要点说明类型本身是一个**可等待awaitable**的包装器通过公开GetAwaiter()返回TaskAwaiterT和AsTask()应用方可以直接await调用结果也可以把它转成Task使用。InvokableBaseTypeAttribute注册的是开放泛型族它把GrainCall与GrainCallRequest关联到代理基类GrainReference上。对每一个返回GrainCallT的方法生成器都会用相同的T关闭出GrainCallRequestT。FromResult与FromInvocation是包装器的两个构造入口前者用于 Grain 实现方直接返回结果后者用于代理侧把IGrainReferenceRuntime.InvokeMethodAsync返回的ValueTask转为可缓存的任务。该类型不参与序列化——它是纯应用面包装器真正序列化的是生成出的请求类型。适配生成的请求请求基类的两个职责请求基类GrainCallRequestT完成两项工作调用方一侧其初始化器把生成的请求通过IGrainReferenceRuntime提交并返回面向应用的GrainCallT。目标一侧其IInvokable.Invoke()实现 await Grain 实现返回的值并创建Response。[SerializerTransparent] [ReturnValueProxy(nameof(InitializeRequest))] public abstract class GrainCallRequestT : RequestBase { [NonSerialized] private readonly IGrainReferenceRuntime _runtime; [GeneratedActivatorConstructor] protected GrainCallRequest(IGrainReferenceRuntime runtime) _runtime runtime; public GrainCallT InitializeRequest(GrainReference proxy) GrainCallT.FromInvocation( _runtime.InvokeMethodAsyncT(proxy, this, Options)); public sealed override ValueTaskResponse Invoke() { try { return CompleteAsync(InvokeInner()); } catch (Exception exception) { return ValueTask.FromResult(Response.FromException(exception)); } } private static async ValueTaskResponse CompleteAsync(GrainCallT call) { try { return Response.FromResult(await call); } catch (Exception exception) { return Response.FromException(exception); } } protected abstract GrainCallT InvokeInner(); }三个关键特性的作用如下ReturnValueProxyAttribute告诉生成的代理直接返回request.InitializeRequest(this)的返回值而不是把请求交给运行时去做传统的请求-响应式调用。也就是说初始化器是“启动操作 / 创建应用面适配器”的交接点handoff point。源码中生成器在 InvokableGenerator.cs 里读取该特性的构造参数初始化器方法名并据此改变代理方法的生成方式。Orleans 会校验重载解析选择的是一个可访问的、具体的、非泛型的实例方法该方法接收一个按值传入的生成的代理参数且返回值能隐式转换为 Grain 方法声明的返回类型。GeneratedActivatorConstructorAttribute用于为生成的请求激活选择依赖注入构造器。它继承自ActivatorUtilitiesConstructorAttribute指示生成的 activator 实现使用该构造器来激活请求实例。当请求基类不需要任何服务时无参构造器同样可行包括带可选参数或params的构造器。[NonSerialized] 字段标记运行时专用字段如示例中的_runtime这些字段不会进入序列化的请求载荷生成出的参数字段才是序列化载荷本身。RequestBase基类位于 src/Orleans.Core.Abstractions/Runtime/GrainReference.cs被标记为[SerializerTransparent]提供InvokeMethodOptions Options、参数读写、Invoke()、目标获取/设置、Dispose()等抽象成员。示例中的_runtime.InvokeMethodAsyncT对应接口 IGrainReferenceRuntime 上的ValueTaskT? InvokeMethodAsyncT(GrainReference reference, IInvokable request, InvokeMethodOptions options)。在 Grain 契约中使用自定义返回类型接口与实现两侧都使用自定义返回类型。生成的请求会用相同签名重写InvokeInner而请求基类决定其值如何被完成与传输public interface ICalculatorGrain : IGrainWithStringKey { GrainCallint Add(int left, int right); GrainCallint Fail(string message); } public sealed class CalculatorGrain : Grain, ICalculatorGrain { public GrainCallint Add(int left, int right) GrainCallint.FromResult(left right); public GrainCallint Fail(string message) throw new InvalidOperationException(message); }完整契约见 CalculatorGrain.cs客户端调用方式见 Program.cs先await calculator.Add(20, 22)打印20 22 42再await calculator.Fail(...)捕获从远端传播回来的InvalidOperationException。该样本契约的语义可以归纳为五个维度文档原文即以此方式定义契约这也正是“库拥有抽象契约”的含义完成Completion代理初始化器立即提交一次请求任务在 Orleans 响应到达时完成。失败Failure同步的 Grain 失败、以及 awaitGrainCallT期间产生的失败都会变成 Orleans 的异常响应并重新抛给调用方。在请求基类中同步异常由Invoke()的 catch 捕获并转为Response.FromException异步失败由CompleteAsync的 catch 捕获并转为Response.FromException。取消CancellationCancellationToken作为 Grain 方法参数参与 Orleans 的协作式调用取消。示例包装器本身不添加独立的取消来源。生命周期Lifetime请求提交后由运行时拥有包装器只保留代表该次调用的任务。并发Concurrency基于任务的包装器支持多个 awaiter 观察同一个终止结果它代表一次调用绝不重新提交。自定义适配器可以实现其他策略例如延迟提交lazy submission、流式streaming或订阅subscriptions。文档明确提示这些策略应作为公开返回类型契约的一部分加以说明并且要考虑到 Grain 激活的生命周期、释放disposal、背压backpressure以及被遗弃的消费者abandoned consumers。注册位置与解析优先级InvokableBaseTypeAttribute构造函数签名(proxyBaseClass, returnType, invokableBaseType)见 Annotations.cs可以出现在四个位置注册位置用途应用到 Grain 方法上的特性类型attribute type为携带该特性的方法选择行为。返回类型定义该返回类型库自有的默认适配器。程序集连接由独立库拥有的返回类型与代理基类。代理基类上的DefaultInvokableBaseTypeAttribute定义代理内建built-in的返回族。解析过程分**两遍two passes**进行Orleans 先考虑精确构造返回类型exact constructed return type的匹配再考虑开放泛型匹配open-generic matching。在每一遍内部优先级为方法特性 返回类型 程序集注册 代理默认值。因此一条精确的程序集注册会优先于一条开放泛型的方法注册。其他几条关键规则每条注册都限定在代理基类的原始泛型定义original generic definition范围内。例如GrainReference上的映射不会影响另一个代理层级程序集注册可以添加映射包括引用适配器程序集提供的映射但不能替换代理内建默认映射。完全相同的注册会合并coalesce。若在同一胜出位置上存在不同的 invokable 基类会产生**确定性deterministic**的构建诊断按类型与程序集标识排序——这样引用的顺序不会改变生成的代码行为。相关诊断 ID 为ORLEANS0111InvalidInvokableBaseTypeMapping定义见 DiagnosticRuleId.cs。在生成器内部代理基类的映射集合会被复制为方法级字典的默认值随后方法上的特性属性按InvokableBaseTypeAttribute合并进来见 InvokableMethodDescription.cs这正是“默认值→方法特性覆盖”优先级的实现来源。精确映射与开放泛型映射精确映射把一个已构造的返回类型例如GrainCallint与一个请求基类关联它会覆盖GrainCall的开放映射。开放泛型返回映射要求请求基类同为开放泛型且元数arity相同Orleans 会用返回类型的类型实参关闭请求基类并校验每一个泛型约束。因此一个已关闭closed的请求基类无法服务开放返回族。实践建议用精确映射应对专门的协议或优化把开放映射保留为族级契约这样新增的构造返回类型会获得一致的行为。生成器的验证要求在消费编译consuming compilation中生成器会对被选中的请求基类做如下校验它是可访问的、非 static、非 sealed 的类。它的泛型元数与开放返回类型匹配且构造类型实参满足其约束。生成的派生请求可以调用一个可访问的无参构造器包括无歧义的可选参数或params构造器或一个标记了GeneratedActivatorConstructorAttribute的可访问构造器。依赖注入构造器的参数均为按值传递并能通过生成的派生构造器无歧义地绑定。标记了ReturnValueProxyAttribute的初始化器从生成的代理类型绑定并返回声明的自定义返回类型。这些诊断应被当作**扩展契约失败extension-contract failures**处理它们会指出注册位置便于库修正其已发布的映射。跨程序集库适配器程序集的注册方式当返回类型与代理基类由独立库拥有时适配器包可以注册来自这些独立程序集的类型。文档 snippet 展示了程序集级注册的写法注意是[assembly: ...][assembly: InvokableBaseType( typeof(GrainReference), typeof(Serialization.GrainCall), typeof(Serialization.GrainCallRequest))]使用约束与发布建议消费项目必须同时引用返回类型所有者、代理所有者以及适配器程序集。生成器会从源码与引用程序集读取程序集特性然后在消费编译中校验可访问性与绑定。公开类型与成员给每个消费者相同的映射而internal成员要求与每个生成的代理程序集建立显式的友元程序集friend-assembly关系。发布时应把返回类型、请求基类、注册和所需的序列化元数据作为一个带版本号的兼容单元versioned compatibility unit并验证在“不同程序集中生成代理”的消费者以及“调用方与 silo 运行相邻包版本”的部署场景。标识、序列化与兼容性生成的请求类型就是序列化的消息体。Orleans 会为它赋予一个复合标识compound identity包含调用标记、代理标识、Grain 接口类型与方法标识。方法标识来自 IdAttribute、AliasAttribute或确定性的签名哈希显式别名能在 CLR 名称改变时保持标识稳定。值得注意的兼容性要点自定义请求基类控制调用行为而生成成员持有方法参数与目标分发元数据。保持序列化成员 ID 与别名稳定并在滚动升级rolling upgrade期间保持参数与结果类型的兼容。更改映射可能改变生成请求的基类行为——即使 Grain 方法签名未变跨调用方与 silo 版本的请求也可能不同。所有生成的请求参数与响应值都由同一套 Orleans.Serialization 编解码器、copier、activator 与 converter 处理。发布适配器库之前建议通读文档 序列化与代码生成内部实现 了解底层机制。运行示例仓库提供了可直接运行的控制台示例samples/CustomGrainCallReturnType/它基于 .NET 10使用 localhost 集群UseLocalhostClustering()无需任何外部服务dotnet run --project CustomGrainCallReturnType.csproj运行后客户端会先打印成功结果20 22 42随后观察到 Grain 返回的InvalidOperationException消息为The grain reported a sample failure.完整流程见 Program.cs。其他相关自定义面围绕序列化与代码生成Orleans 文档体系还提供了多个相邻的扩展面可作为本篇的延伸阅读自定义序列化IGeneralizedCodec、IGeneralizedCopier与类型过滤器。配置序列化通过ISerializerBuilder注册 codec、copier、activator、converter 或外部序列化器。声明不可变类型ImmutableAttribute。生成序列化器与稳定标识GenerateSerializerAttribute、IdAttribute、AliasAttribute。检查或修改生成的请求参数在 Grain 调用过滤器grain call filters中处理。用生成的请求元数据进行调度。结合示例 CustomGrainCallReturnType 与源码 Orleans.CodeGenerator 阅读可以完整看到“应用面返回类型 → 生成请求 → 运行时分发 → 响应回传”的整条调用链并据此在自己的库中设计、注册与发布自定义的 Grain 调用返回类型。赞分享后端微服务【免费下载链接】orleansCloud Native application framework for .NET项目地址https://gitcode.com/gh_mirrors/or/orleans点击查看免费下载相关推荐BDI 心智状态 RDF/Turtle 建模实战Agent Skills for Context Engineering 完整认知工作流示例BDI 心智状态 RDF/Turtle 建模实战Agent Skills for Context Engineering 完整认知工作流示例 本文是 Agen后端微服务Orleans 诊断 ORLEANS0026 完全指南自定义 Grain 调用返回类型的 InvokableBaseType 映射失效与修复Orleans 诊断 ORLEANS0026 完全指南自定义 Grain 调用返回类型的 InvokableBaseType 映射失效与修复 导读 ORLEA后端微服务给 ImmortalWrt 插件换上中文皮肤给 ImmortalWrt 插件换上中文皮肤 装了个国外插件打开 LuCI浏览器里 192.168.1.1 那个网页管理页满屏英文当场劝退。别慌Imm操作系统嵌入式嵌入式OS固件网络创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考