using System.Collections.Generic;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using System.Globalization;
public class GrpcServiceResult
public bool Success { get; set; }
public string Message { get; set; } = null!;
private GrpcServiceResult() { }
public GrpcServiceResult(bool success, string message = "")
public class GrpcServiceResult<T> where T : class
public bool Success { get; set; }
public string Message { get; set; } = null!;
public T Data { get; set; } = null!;
private GrpcServiceResult() { }
public GrpcServiceResult(bool success, T result = null!, string message = "")
public class PagedResult<T> where T : class
public int CurrentPage { get; set; }
public int PageCount { get; set; }
public int PageSize { get; set; }
public int RowCount { get; set; }
public int FirstRowOnPage
get { return (CurrentPage - 1) * PageSize + 1; }
get { return Math.Min(CurrentPage * PageSize, RowCount); }
public IList<T> Results { get; set; }
public class SystemItemsRequestContract
public string SearchPattern { get; set; } = null!;
public int PartnerId { get; set; }
public int SearchField { get; set; }
public int Page { get; set; }
public int Count { get; set; }
public class SystemItemsResponseContract : ItemInfoSyncResponseContract
public int Id { get; set; }
public DateTimeOffset? InsertedOn { get; set; }
public ESellingType SoldAs { get; set; }
public List<SystemItemsResponseContract> Packs { get; set; }
[ProtoInclude(1000, typeof(SystemItemsResponseContract))]
public class ItemInfoSyncResponseContract
public List<ItemBarcode> Barcodes { get; set; } = null!;
public List<string> Images { get; set; } = null!;
public string Barcode { get; set; } = null!;
public string Check { get; set; } = null!;
public interface IDataReadService
Task<GrpcServiceResult<PagedResult<SystemItemsResponseContract>>> GetSystemItems(SystemItemsRequestContract contract);
public class DateTimeOffsetSurrogate
public string DateTimeString { get; set; }
public static implicit operator DateTimeOffsetSurrogate(DateTimeOffset value)
return new DateTimeOffsetSurrogate {DateTimeString = value.ToString("u")};
public static implicit operator DateTimeOffset(DateTimeOffsetSurrogate value)
return DateTimeOffset.Parse(value.DateTimeString);
public static T RoundTrip<T>(T input)
using var stream = new MemoryStream();
Serializer.Serialize(stream, input);
var output = Serializer.Deserialize<T>(stream);
public static void Test()
RuntimeTypeModel.Default.Add(typeof(DateTimeOffset), false).SetSurrogate(typeof(DateTimeOffsetSurrogate));
RoundTrip(new SystemItemsRequestContract());
RoundTrip(new SystemItemsResponseContract());
RoundTrip(new PagedResult<SystemItemsResponseContract>());
var result = RoundTrip(new GrpcServiceResult<PagedResult<SystemItemsResponseContract>>(false, new() { Results = { new(), new() { InsertedOn = default(DateTimeOffset) }}}, "foo"));
Console.WriteLine("Round-tripped {0}:", result);
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(result, new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));
public static class ProtobufNetExtensions
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version);
Console.WriteLine("protobuf-net Serializer version: " + typeof(ProtoBuf.Serializer).Assembly.FullName);
Console.WriteLine("protobuf-net ProtoReader version: " + typeof(ProtoBuf.ProtoReader).Assembly.FullName + "\n");
I tried to reproduce your problem in a standalone fiddle here: https: