Skip to content
On this page

Client streaming RPC

We have a protobuf file with a Client streaming RPC CreateEmployees defined. It creates a set of employees and then returns the ID of all created employees.

syntax = "proto3";

import "google/protobuf/wrappers.proto";

package Examples.Grpc;

service EmployeeService {
  rpc CreateEmployees(stream Employee) returns (CreatedEmployeesIdsResponse);
}

message Employee {
  string guid = 1;
  string full_name = 2;
  string position = 3;
  int32 age = 4;
}

message CreatedEmployeesIdsResponse {
  repeated string guid = 1;
}

Call Client streaming RPC

Create employees and call the desired client method:

csharp
var employees = new[]
{
	new Employee()
	{
		Guid = Guid.NewGuid().ToString(),
		Age = 23,
		FullName = "Elon Musk"
	},
	new Employee()
	{
		Guid = Guid.NewGuid().ToString(),
		Age = 54,
		FullName = "Neil Armstrong"
	}
};

GrpcHost
	.CreateClient<EmployeeService.EmployeeServiceClient>()
	.ClientStreaming
		.Call(x=>x.CreateEmployees());

Let's turn to RequestStream and send all the entities:

csharp
GrpcHost
	.CreateClient<EmployeeService.EmployeeServiceClient>()
	.ClientStreaming
		.Call(x=>x.CreateEmployees())
		.RequestStream
            //All at once
			.WriteMany(employees)
            //Or each separately
            //.Write(employees[0])
            //.Write(employees[1])
            .Complete()

WARNING

Don't forget to close the stream by calling the Complete() method.

Let's check that we received the correct Guid:

csharp
GrpcHost
	.CreateClient<EmployeeService.EmployeeServiceClient>()
	.ClientStreaming
		.Call(x=>x.CreateEmployees())
		.RequestStream
			.WriteMany(employees)
            .Complete()
        .Response
			.AssertThat(resp => resp.Guid.Should().BeEquivalentTo(employees.Select(e=>e.Guid)));

Handling Errors

Let's change the age of the second employee to negative:

csharp

var employees = new[]
{
	new Employee()
	{
		Guid = Guid.NewGuid().ToString(),
		Age = 23,
		FullName = "Elon Musk"
	},
	new Employee()
	{
		Guid = Guid.NewGuid().ToString(),
		Age = -12,
		FullName = "Neil Armstrong"
	}
};

We can check that after sending the second employee, the RPC status changed to InvalidArgument:

csharp
GrpcHost
	.CreateClient<EmployeeService.EmployeeServiceClient>()
	.ClientStreaming
		.Call(x=>x.CreateEmployees())
		.RequestStream
			.WriteMany(employees)
        .Response
			.AssertStatusCode(StatusCode.InvalidArgument)

We can also check not only the status code, but also the RpcException:

csharp
GrpcHost
	.CreateClient<EmployeeService.EmployeeServiceClient>()
	.ClientStreaming
		.Call(x=>x.CreateEmployees())
		.RequestStream
			.WriteMany(employees)
		.Response
			.AssertError(exception => exception.Status.Detail.Should().Be("Age can't be negative."));