1

I'm doing an application using server streaming.

The problem is the client doesn't read the data from the server streaming.

This is my proto service:

service UserService {
    rpc GetData(Id) returns (stream DataResponse) {}
}
message Id {
    int32 id = 1;
}

message DataResponse {
    bytes data = 1;
}

c# server is like this:

public override async Task GetData(Id request, IServerStreamWriter<DataResponse> response, ServerCallContext context)
{
    var user = {} // get user
    foreach (var d in user.Data)
    {
        await response.WriteAsync(new DataResponse { Data = d });
    }
}

And it works because I have a NodeJS client where I can call the server and works perfectly.

Client in Node is

let call = client.getData({id:1})
call.on('data', function (response) {
    // do things
})
call.on('end', function () {
    // do things
})

And c# client is:

AsyncServerStreamingCall<DataResponse> response = client.GetData(new Id{Id_ = 1});
while(await response.ResponseStream.MoveNext())
{
    Console.WriteLine("Into while loop"); // <-- This is never executed
    DataResponse current = response.ResponseStream.Current;
    Console.WriteLine($"{current.Data}");
}

I've also added a try/catch and it doesn't output anything so it seems MoveNext() is always false.

What is the problem here? Why NodeJS client works and c# client can't read the stream? Have I missed something?

Here is full client.cs class:

class Program
{
    const int Port = 50051;
    static void Main(string[] args)
    {
        try
        {
            Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
            var client = new UserService.UserServiceClient(channel);
            GetDataStreaming(client);
        }
        catch (RpcException ex)
        {
            Console.WriteLine($"Error: {{Code: {ex.StatusCode}, Status: {ex.Status.Detail}}}");
        }
    }

    private static async void GetDataStreaming(UserService.UserServiceClient client)
    {
        
            AsyncServerStreamingCall<DataResponse> response = client.GetData(new Id { Id_ = 1 });
            while (await response.ResponseStream.MoveNext())
            {
                Console.WriteLine("Into while loop");
                DataResponse current = response.ResponseStream.Current;
                Console.WriteLine($"{current.Data.ToStringUtf8()}");
            }

    }

}
J.F.
  • 13,927
  • 9
  • 27
  • 65
  • Cannnot reproduce the issue. It works fine for me. Does host name and port match between the server and the client? – user2250152 Nov 02 '21 at 14:33
  • Yes. Server receive both calls, from c# and NodeJS clients. Also I've tried another client (NodeJS client) and works ok. The connection is the same, the server is up and should works but... The problem is c# client but I cannot find what happen. – J.F. Nov 02 '21 at 14:53
  • Do you use the both clients at the same time? Could you share the whole code of C# client? – user2250152 Nov 03 '21 at 07:49
  • No, the use of NodeJS client was only to test if c# server works correctly, but I only use one client (c# client). I've also updated the question to show the client class. – J.F. Nov 03 '21 at 12:36

1 Answers1

3

The issue is that your client has ended before the client receive the response. When you call GetDataStreaming(client) in Main it doesn't wait and finishes.

To fix the issue change async void GetDataStreaming to async Task GetDataStreaming.

private static async Task GetDataStreaming(UserService.UserServiceClient client)
{        
        AsyncServerStreamingCall<DataResponse> response = client.GetData(new Id { Id_ = 1 });
        while (await response.ResponseStream.MoveNext())
        {
            Console.WriteLine("Into while loop");
            DataResponse current = response.ResponseStream.Current;
            Console.WriteLine($"{current.Data.ToStringUtf8()}");
        }
}

Change static void Main to static async Task Main and you should also call channel.ShutdownAsync method at the end.

static async Task Main(string[] args)
{
    try
    {
        Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
        var client = new UserService.UserServiceClient(channel);
        await GetDataStreaming(client);
        await channel.ShutdownAsync();
    }
    catch (RpcException ex)
    {
        Console.WriteLine($"Error: {{Code: {ex.StatusCode}, Status: {ex.Status.Detail}}}");
    }
}

Another option is to change async void GetDataStreaming to async Task GetDataStreaming and in Main method wait until Task complete.

static void Main(string[] args)
{
    try
    {
        Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
        var client = new UserService.UserServiceClient(channel);
        var task = GetDataStreaming(client);
        task.Wait();
    }
    catch (RpcException ex)
    {
        Console.WriteLine($"Error: {{Code: {ex.StatusCode}, Status: {ex.Status.Detail}}}");
    }
}
user2250152
  • 14,658
  • 4
  • 33
  • 57