Client Streaming with gRPC in C#

,proto

syntax = "proto3";

option csharp_namespace = "GrpcClientStreaming";

import "google/protobuf/timestamp.proto";

package greet;

service Greeter {
  rpc SayHello (stream HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
  google.protobuf.Timestamp timestamp = 2;
}

message HelloReply {
  repeated string messages = 1;
}

Server

public override async Task<HelloReply> SayHello(IAsyncStreamReader<HelloRequest> requestStream,
    ServerCallContext context)
{
    HelloReply response = new HelloReply();

    while (await requestStream.MoveNext() && !context.CancellationToken.IsCancellationRequested)
    {
        response.Messages.Add(requestStream.Current.Timestamp.ToString());
        Console.WriteLine(requestStream.Current.Timestamp.ToString());
    }

    return response;
}

Client

static async Task Main(string[] args)
{
    using var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greeter.GreeterClient(channel);

    CancellationToken cancellationToken = new CancellationToken(false);
    var response = client.SayHello(new CallOptions(null, null, cancellationToken));

    for (int i = 0; i < 5; i++)
    {
        var timestamp = Timestamp.FromDateTime(DateTime.UtcNow);
        await response.RequestStream.WriteAsync(new HelloRequest
        {
            Name = "Mahmood",
            Timestamp = timestamp
        });

        Console.WriteLine(String.Format("Request : {0}", timestamp.ToString()));

        await Task.Delay(1000);
    }

    await response.RequestStream.CompleteAsync();

    Console.WriteLine("--------------------------------------");

    var result = response.ResponseAsync.Result;

    foreach (string message in result.Messages)
    {
        Console.WriteLine("Response : {0}", message);
    }
}

References
https://www.youtube.com/watch?v=DNxdvRQ4qRQ&list=PLUOequmGnXxPOlhyA57ijmEyOeVmYQt32&index=3