3
votes

I'm trying to use server streaming using GRPC with C#, and my client receives one response and then throws error:

Shutdown has already been called

  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

I tried throttling the responses by putting delays both on the server and client side but I still got the error. But I noticed that if I put a 1 second delay on the client before trying to call MoveNext() I won't even get the first response and it throws the error immediately.

My proto is this:

syntax = "proto3";

package Mega.SplitText;

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

message Text {
  string text = 1;
}

message Line {
  string line = 1;
}

Server code:

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}");
            }
        }
    }

Client code:

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();
        }
    }

I copied this structure from the examples folder on the official GRPC repository, and that works fine on my machine, so I have no idea what I'm doing wrong in this other project.

The projects are both .Net Core 2.0, but I also tried with .Net Framework 4.6.1 just in case. In both cases the result is the same.

1

1 Answers

2
votes

Solved, the problem was that I forgot to wait for the client async function. Solution:

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();
}