Работа с датами и временем, а также временными интервалами имеет свои особенности, поскольку для типов DateTime, TimeSpan и DateTimeOffset в Protobuf нет примтивных типов, которые напрямую конвертируются в типы .NET. Поэтому Protobuf предоставляет дополнительные расширения:
Тип C# | Тип Protobuf |
DateTimeOffset | google.protobuf.Timestamp |
DateTime | google.protobuf.Timestamp |
TimeSpan | google.protobuf.Duration |
Рассмотрим применение этих типов на примере. Допустим, клиент посылает серверу свое имя, и сервис в ответ посылает клиенту приглашение на некоторое мероприятие, а также дату мероприятия и его длительность.
Для описания сообщений и сервиса определим следующий файл proto:
syntax = "proto3"; option csharp_namespace = "GrpcServiceApp"; // импортируем нужные пакеты import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; package metanit; message Request{ string name = 1; } message Response{ string invitation = 1; google.protobuf.Timestamp start = 2; google.protobuf.Duration duration = 3; } service Inviter{ rpc Invite (Request) returns (Response); }
Сообщение Request
в свойстве name будет содержать имя клиента. Сообщение Response
в свойстве invitation хранит текст приглашения. Свойство start представляет начало мероприятия, а свойство duration - его длительность.
При этом дата и время представляет тип google.protobuf.Timestamp
, для использования которого импортируется пакет "google/protobuf/timestamp.proto"
Аналогично длительность мероприятия представляет тип google.protobuf.Duration
, для которого импортируется пакет "google/protobuf/duration.proto"
Сервис Inviter с помощью метода invite получает сообщение Request и отправляет сообщение Response.
В проекте сервера определим следующий класс сервиса:
using Google.Protobuf.WellKnownTypes; // пространство имен для Timestamp и Duration using Grpc.Core; namespace GrpcServiceApp.Services { public class InviterService : Inviter.InviterBase { public override Task<Response> Invite(Request request, ServerCallContext context) { // начало мероприятия - условно следующий день var eventDateTime = DateTime.UtcNow.AddDays(1); // длительность мероприятия - условно 2 часа var eventDuration = TimeSpan.FromHours(2); // отправляем ответ return Task.FromResult(new Response { Invitation = $"{request.Name}, приглашаем вас посетить мероприятие", Start = Timestamp.FromDateTime(eventDateTime), Duration = Duration.FromTimeSpan(eventDuration) }); } } }
В данном случае для краткости сервис просто отправляет простейшее приглашение, в качестве даты мероприятия устанавливается завтрашняя дата, а в качестве длительности мероприятия - 2 часа.
Следует отметить, что сгенерированные свойства в классе C# в реальности не представляют стандартные типы DateTimeOffset, DateTime и TimeSpan, а используют классы Timestamp и Duration из пространства имен Google.Protobuf.WellKnownTypes. Однако эти классы предоставляют методы для преобразования из стандартных типов DateTimeOffset, DateTime и TimeSpan:
Start = Timestamp.FromDateTime(eventDateTime), Duration = Duration.FromTimeSpan(eventDuration)
Для отправки сервису сообщений в проекте клиента определим следующий код:
using Grpc.Net.Client; using GrpcClientApp; // создаем канал для обмена сообщениями с сервером // параметр - адрес сервера gRPC using var channel = GrpcChannel.ForAddress("https://localhost:7229"); // создаем клиент var client = new Inviter.InviterClient(channel); // посылаем имя и получаем приглашение на мероприятие var response = await client.InviteAsync(new Request { Name = "Tom" }); var eventInvitation = response.Invitation; var eventDateTime = response.Start.ToDateTime(); var eventDuration = response.Duration.ToTimeSpan(); // выводим данные на консоль Console.WriteLine(eventInvitation); Console.WriteLine($"Начало: {eventDateTime.ToString("dd.MM HH:mm")} Длительность: {eventDuration.TotalHours} часа");
На стороне клиента мы получаем данные также в виде объектов Timestamp и Duration. Но эти типы также предоставляют методы для обратного преобразования - в типы DateTimeOffset, DateTime и TimeSpan:
var eventDateTime = response.Start.ToDateTime(); var eventDuration = response.Duration.ToTimeSpan();
Запустим сервис, а затем клиент, и клиент получит дату и время и продолжительность мероприятия
Tom, приглашаем вас посетить мероприятие Начало: 25.11 18:13 Длительность: 2 часа