使用.NET5和Orleans开发HelloWorld时触发主键InvalidOperationException异常
问题背景与异常现象
基于Orleans框架编写Hello World示例程序,开发环境为.NET 5,项目中引入了Microsoft.Orleans.CodeGeneration.MSBuild NuGet包,运行时抛出如下异常:
InvalidOperationException: 如果Grain使用主键扩展特性,则不能使用UniqueKey.PrimaryKeyToGuid的当前重载方法。
对应的异常调用堆栈:
Orleans.Runtime.UniqueKey.ThrowIfHasKeyExt(String methodName)Orleans.Runtime.UniqueKey.PrimaryKeyToGuid()Orleans.Runtime.GrainId.GetPrimaryKey()
涉及的核心代码片段:
- 客户端调用Grain的代码
var result = await _clusterClient.GetGrain<IHelloWorldGrain>("leke").SayHelloToAsync(name); - Grain实现类代码
public class HelloWorldGrain : Grain, IHelloWorldGrain { private int _invocationCount = 0; public Task<string> SayHelloToAsync(string name) { return Task.FromResult($"Hello {name} from {this.GetPrimaryKey()} - I have said hello {_invocationCount++} times."); } } - Grain接口定义
public interface IHelloWorldGrain: IGrainWithStringKey { Task<string> SayHelloToAsync(string name); }
异常根因
- 接口定义层面:
IHelloWorldGrain继承自IGrainWithStringKey,说明该Grain的主键类型为字符串类型 - 代码调用层面:Grain实现内使用的
this.GetPrimaryKey(),是Orleans为Guid类型主键Grain提供的专属扩展方法,内部逻辑会调用PrimaryKeyToGuid转换主键值 - 底层校验逻辑:当为字符串类型主键传入实例"leke"时,Orleans会把字符串值存储在主键扩展字段中,此时调用Guid专属的主键读取方法,会触发内置的类型匹配校验,抛出对应异常
修复方案
- 替换Grain内部的主键读取方法,针对字符串类型主键,使用匹配的
this.GetPrimaryKeyString()方法,替代原来的Guid专属读取方法 - 修改后的核心代码示例:
public Task<string> SayHelloToAsync(string name) { return Task.FromResult($"Hello {name} from {this.GetPrimaryKeyString()} - I have said hello {_invocationCount++} times."); }
内容的提问来源于stack exchange,提问作者2cool4school
相关产品推荐
相关产品推荐

