使用C#的GRPC和来自服务器的流式响应会导致错误:'关闭已被调用'

时间:2018-01-22 18:04:57

标签: c# streaming grpc

我尝试使用带有C#的GRPC使用服务器流,我的客户端收到一个响应,然后抛出错误:

  

已经调用了关机

  at Grpc.Core.Internal.CompletionQueueSafeHandle.BeginOp()
   at Grpc.Core.Internal.CallSafeHandle.StartReceiveMessage(IReceivedMessageCallback callback)
   at Grpc.Core.Internal.AsyncCallBase`2.ReadMessageInternalAsync()
   at Grpc.Core.Internal.ClientResponseStream`2.<MoveNext>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at GRPCTransferClient.Program.<Test>d__1.MoveNext() in Program.cs:line 25

我尝试通过在服务器端和客户端都放置延迟来限制响应,但我仍然遇到错误。但是我注意到如果我在尝试调用MoveNext()之前在客户端上放置了1秒钟的延迟,我甚至不会得到第一个响应并立即抛出错误。

我的原型是:

syntax = "proto3";

package Mega.SplitText;

service SplitText {
  rpc Split(Text) returns (stream Line) {}
}

message Text {
  string text = 1;
}

message Line {
  string line = 1;
}

服务器代码:

public class SplitTextServiceImpl : SplitTextBase
    {
        public SplitTextServiceImpl()
        {
        }

        public override async Task Split(Text request, IServerStreamWriter<Line> responseStream, ServerCallContext context)
        {
            foreach (string line in request.Text_.Split(';'))
            {
                await responseStream.WriteAsync(new Line { Line_ = line });                
                Console.WriteLine($"Sent {line}");
            }
        }
    }

客户代码:

class Program
    {
        static void Main(string[] args)
        {
            var program = new Program();
            program.Test();            
        }

        async void Test()
        {
            Channel channel = new Channel($"127.0.0.1:50051", ChannelCredentials.Insecure);
            var client = new SplitTextClient(channel);
            using (var response = client.Split(new Text { Text_ = "a;b;c;d;e" }))
            {
                while (await response.ResponseStream.MoveNext())
                {
                    Console.WriteLine(response.ResponseStream.Current);
                }
            }
            Console.ReadLine();
        }
    }

我从官方GRPC存储库的examples文件夹中复制了这个结构,这在我的机器上工作正常,所以我不知道我在这个其他项目中做错了什么。

这些项目都是.Net Core 2.0,但我也试过.Net Framework 4.6.1以防万一。在这两种情况下,结果都是一样的。

1 个答案:

答案 0 :(得分:1)

解决了,问题是我忘了等待客户端异步功能。解决方案:

static void Main(string[] args)
{
    var program = new Program();
    program.Test().Wait(); // Need to wait here
}

async Task Test()
{
    Channel channel = new Channel($"127.0.0.1:50051", ChannelCredentials.Insecure);
    var client = new SplitTextClient(channel);
    using (var response = client.Split(new Text { Text_ = "a;b;c;d;e" }))
    {
        await Task.Delay(1000);
        while (await response.ResponseStream.MoveNext())
        {
            Console.WriteLine(response.ResponseStream.Current);
        }
    }
    Console.ReadLine();
}