gRPC/C#技术问题:调用带流式响应的接口时MoveNext方法参数异常
解决gRPC客户端MoveNext参数缺失的问题
这个错误原因很直接——你调用的MoveNext方法需要一个CancellationToken类型的参数,但你现在的代码里没有传递任何参数,不符合方法签名要求。下面给你几个可行的解决方案:
方案1:传递默认取消令牌(最简单)
如果你的场景不需要主动取消流的读取操作,直接传入CancellationToken.None即可,这个令牌表示不会触发取消逻辑:
private async void RequestAllOnlinePlayers() { AllPlayersOnMapRequest request = new AllPlayersOnMapRequest(); request.MapId = (uint)AuthorativeClientManager.Instance().GetActiveMapId(); using (var call = gRPCManager.Instance.GetPlayerClient.GetAllPlayersOnMap(request)) { // 传入默认取消令牌 while (await call.ResponseStream.MoveNext(CancellationToken.None)) { WorldObjectData worldObjectData = call.ResponseStream.Current; Console.WriteLine("Name " + worldObjectData.Name); } } }
方案2:使用可控制的取消令牌
如果后续需要在特定场景下(比如用户退出操作、停止加载)取消这个流的读取,可以创建CancellationTokenSource来生成令牌,方便主动触发取消:
private async void RequestAllOnlinePlayers() { AllPlayersOnMapRequest request = new AllPlayersOnMapRequest(); request.MapId = (uint)AuthorativeClientManager.Instance().GetActiveMapId(); // 创建取消令牌源,后续可通过cts.Cancel()主动取消 using var cts = new CancellationTokenSource(); using (var call = gRPCManager.Instance.GetPlayerClient.GetAllPlayersOnMap(request)) { while (await call.ResponseStream.MoveNext(cts.Token)) { WorldObjectData worldObjectData = call.ResponseStream.Current; Console.WriteLine("Name " + worldObjectData.Name); } } }
方案3:使用异步枚举简化代码(推荐)
如果你使用的是.NET Core 3.0及以上版本(或.NET 5+),gRPC支持异步枚举语法,代码会更简洁易读,同时也能传入取消令牌:
private async void RequestAllOnlinePlayers() { AllPlayersOnMapRequest request = new AllPlayersOnMapRequest(); request.MapId = (uint)AuthorativeClientManager.Instance().GetActiveMapId(); using (var call = gRPCManager.Instance.GetPlayerClient.GetAllPlayersOnMap(request)) { // 用await foreach直接遍历响应流 await foreach (var worldObjectData in call.ResponseStream.ReadAllAsync(CancellationToken.None)) { Console.WriteLine("Name " + worldObjectData.Name); } } }
简单补充下背景:早期的gRPC版本中MoveNext可能存在无参数的重载,但后续版本为了统一异步操作的取消逻辑,移除了无参重载,要求必须显式传递取消令牌,这就是你遇到这个错误的原因。
内容的提问来源于stack exchange,提问作者Venelin
相关产品推荐
相关产品推荐

