Я реализовал оболочку класса удобства клиента, чтобы превратить потоковые вызовы сервера в обычные события для проекта, над которым я работаю. Не уверен, что это то, что вы после. Вот простой сервер gRP C, который раз в секунду публикует время в виде строки.
syntax = "proto3";
package SimpleTime;
service SimpleTimeService
{
rpc MonitorTime(EmptyRequest) returns (stream TimeResponse);
}
message EmptyRequest{}
message TimeResponse
{
string time = 1;
}
Реализация сервера, которая просто зацикливается раз в секунду, возвращая строковое представление текущего времени до отмены , выглядит следующим образом
public override async Task MonitorTime(EmptyRequest request, IServerStreamWriter<TimeResponse> responseStream, ServerCallContext context)
{
try
{
while (!context.CancellationToken.IsCancellationRequested)
{
var response = new TimeResponse
{
Time = DateTime.Now.ToString()
};
await responseStream.WriteAsync(response);
await Task.Delay(1000);
}
}
catch (Exception)
{
Console.WriteLine("Exception on Server");
}
}
Для клиента я создал класс, который содержит клиент gRP C и предоставляет результаты сервера, транслирующего вызов MonitorTime, как обычное событие ole. net.
public class SimpleTimeEventClient
{
private SimpleTime.SimpleTimeService.SimpleTimeServiceClient mClient = null;
private CancellationTokenSource mCancellationTokenSource = null;
private Task mMonitorTask = null;
public event EventHandler<string> OnTimeReceived;
public SimpleTimeEventClient()
{
Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
mClient = new SimpleTime.SimpleTimeService.SimpleTimeServiceClient(channel);
}
public void Startup()
{
mCancellationTokenSource = new CancellationTokenSource();
mMonitorTask = Task.Run(() => MonitorTimeServer(mCancellationTokenSource.Token));
}
public void Shutdown()
{
mCancellationTokenSource.Cancel();
mMonitorTask.Wait(10000);
}
private async Task MonitorTimeServer(CancellationToken token)
{
try
{
using (var call = mClient.MonitorTime(new SimpleTime.EmptyRequest()))
{
while(await call.ResponseStream.MoveNext(token))
{
var timeResult = call.ResponseStream.Current;
OnTimeReceived?.Invoke(this, timeResult.Time);
}
}
}
catch(Exception e)
{
Console.WriteLine($"Exception encountered in MonitorTimeServer:{e.Message}");
}
}
}
Теперь создайте клиент и подпишитесь на событие.
static void Main(string[] args)
{
SimpleTimeEventClient client = new SimpleTimeEventClient();
client.OnTimeReceived += OnTimeReceivedEventHandler;
client.Startup();
Console.WriteLine("Press any key to exit");
Console.ReadKey();
client.Shutdown();
}
private static void OnTimeReceivedEventHandler(object sender, string e)
{
Console.WriteLine($"Time: {e}");
}
, которое при запуске выдает
Я упустил много проверок на ошибки и тому подобное, чтобы сделать пример меньше. Одна вещь, которую я сделал, - это для интерфейсов gRP C со многими потоковыми вызовами сервера, которые могут или не могут представлять интерес для вызова клиентов, является реализация средства доступа к событиям (добавление, удаление), чтобы вызывать только потоковый метод на стороне сервера, если есть клиент, подписавшийся на завернутое событие Надеюсь, что это полезно