Сериализация IEnumerable в protobuf-net
У меня есть библиотека довольно тяжелых DTO, которая в настоящее время используется некоторыми службами WCF. Мы пытаемся перенести его в мир protobuf-net с минимальными изменениями. Один конкретный набор элементов вызывает у меня проблемы с сериализацией. Я собираюсь просто их здесь, потому что это немного усложняется, но суть проблемы такова:
public class Key
{
public string Id {get; set;}
}
public class KeyCollection : IEnumerable<Key>
{
private readonly List<Key> list;
#region IEnumerable
// etc...
#endregion
}
public class Item
{
public long Id { get; set; }
}
public abstract class ContainerBase
{ }
public abstract class ContainerBase<T> : ContainerBase
where T : Item
{ }
public abstract class ContainerType1Base : ContainerBase<Item>
{
public KeyCollection Keys { get; set; }
}
public class ContainerType1 : ContainerType1Base
{ }
Я пропустил декораторы, потому что они не проблема, в основном потому, что если я добавлю
void Add(Key item) { }
к
KeyCollection
все вроде работает. В противном случае я столкнусь с проблемами при попытке сериализовать экземпляр
ContainerType1
.
Собственно, меняя подпись
KeyCollection
является своего рода запретительным, поэтому я пытаюсь следовать этому ответу, чтобы попытаться сделать это программно. В частности, установка
itemType
и
defaultType
обнулить "Ключи"
ValueMember
из
ContainerType1
,
ContainerType1Base
и
ContainerBase<Item>
. Я также установил
IgnoreListHandling
к
true
на
KeyCollection
... что совершенно не работает. Я получаю общее исключение "не удалось десериализовать" на клиенте, которое я могу опубликовать здесь, если это поможет. На стороне сервера я сериализую его, используя
Serializer.Serialize()
, и я выплюнул
Serializer.GetProto<>()
а также JSON объекта, и все они, похоже, работают нормально.
Как отключить обработку списков? В связи с этим, есть ли способ включить дополнительную отладку при сериализации, чтобы попытаться получить дополнительную информацию о проблеме?
1 ответ
По сути, показанный код выглядит нормально. К сожалению, в настоящее время в gRPC есть "функция", которая означает, что он отбрасывает исходное исключение, когда маршаллер (сериализатор) по какой-то причине дает сбой, поэтому gRPC в настоящее время не выявляет фактическую проблему. Я отправил исправление для этого - оно может быть принято или не принято.
А пока я предлагаю вам просто удалить gRPC из уравнения и смоделировать только рабочую нагрузку маршаллера; для этого на сервере: сгенерируйте данные, которые вы пытаетесь отправить, и выполните:
var ms = new MemoryStream();
Serializer.Serialize(ms, yourDataHere);
var payload = Convert.ToBase64String(ms.ToArray());
и получить значение
payload
(это просто
string
). Теперь на клиенте измените это:
var ms = new MemoryStream(Convert.FromBase64String(thatStringValue));
Serialize.Deserialize<YourTypeHere>(ms);
Я ожидаю, что это вызовет исключение, которое расскажет вам, в чем реальная проблема.
Если изменение gRPC объединяется, ошибка должна быть доступна через:
catch (RpcException fault)
{
var originalFault = fault.Status.DebugException;
// ^^^
}