Как вы конфигурируете RuntimeModel.Default в protobuf-net для поддержки сериализации / десериализации SessionSecurityToken?
BinaryFormatter может выполнять сериализацию просто:
private byte[] TokenToBytes(SessionSecurityToken token)
{
if (token == null)
{
return null;
}
using (var memoryStream = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, token);
return memoryStream.ToArray();
}
}
Когда я попытался заменить BinaryFormatter на protobuf-Net:
using (var memoryStream = new MemoryStream())
{
Serializer.Serialize(memoryStream, token);
return memoryStream.ToArray();
}
Я получаю следующее исключение:
Тип не ожидается, и никакой контракт не может быть выведен: System.IdentityModel.Tokens.SessionSecurityToken
Я попытался добавить:
RuntimeTypeModel.Default.Add(typeof(SessionSecurityToken), true);
Который проходит через исключение, но теперь я получаю нулевой байтовый массив.
Как правильно настроить protobuf-Net для сериализации SessionSecurityToken?
С другой стороны, SessionSecurityToken не имеет конструктора без параметров.
using (var memoryStream = new MemoryStream(tokenAsBytes))
{
return Serializer.Deserialize<SessionSecurityToken>(memoryStream);
}
Выдает исключение ProtoException:
Не найден конструктор без параметров для SessionSecurityToken
BinaryFormatter
может сделать это без суеты
using (var memoryStream = new MemoryStream(bytes))
{
var binaryFormatter = new BinaryFormatter();
return (SessionSecurityToken)binaryFormatter.Deserialize(memoryStream);
}
Как правильно настроить protobuf-Net для десериализации SessionSecurityToken?
1 ответ
protobuf-net не претендует на возможность сериализации каждого отдельного типа; действительно, вам будет очень трудно сериализовать это через большинство сериализаторов (XmlSerializer
любой из сериализаторов JSON, DataContractSerializer
, так далее). BinaryFormatter
находится в другой категории сериализаторов - и в этом конкретном случае реализует пользовательскую сериализацию через ISerializable.GetObjectData(SerializationInfo, StreamingContext)
,
Конструктор это красная сельдь; на самом деле protobuf-net может полностью обойти конструкторов, и в этом конкретном сценарии BinaryFormatter
использует пользовательский конструктор сериализации через .ctor(SerializationInfo, StreamingContext)
,
В простых случаях protobuf-net можно настроить с помощью атрибутов или параметров времени выполнения; для более сложных сценариев можно использовать суррогаты для отображения между представлениями - однако в этом случае я бы предложил (глядя на реализацию SessionSecurityToken
) что это сложнее, чем вы, вероятно, хотите сохранить.
Я бы отступил на шаг или два здесь; большинство сериализаторов предназначены для работы с данными, а не для реализации, и прекрасно работают с DTO и т. д. SessionSecurityToken
это очень не DTO, и не существует простого способа переключения между ними. Мое сильное предложение здесь будет: сериализовать то, что это представляет, а не то, что это. Однако, если это является частью существующей сложной модели и ее действительно трудно выделить, вы можете вернуться к BinaryFormatter
за эти биты. Я не проверял это, но подумайте:
RuntimeTypeModel.Default.Add(typeof(SessionSecurityToken), false)
.SetSurrogate(typeof(BinaryFormatterSurrogate<SessionSecurityToken>));
С:
[ProtoContract]
public class BinaryFormatterSurrogate<T>
{
[ProtoMember(1)]
public byte[] Raw { get; set; }
public static explicit operator T(BinaryFormatterSurrogate<T> value)
{
if(value==null || value.Raw == null) return default(T);
using(var ms = new MemoryStream(value.Raw))
{
return (T)new BinaryFormatter().Deserialize(ms);
}
}
public static explicit operator BinaryFormatterSurrogate<T>(T value)
{
object obj = value;
if (obj == null) return null;
using (var ms = new MemoryStream())
{
new BinaryFormatter().Serialize(ms, obj);
return new BinaryFormatterSurrogate<T> { Raw = ms.ToArray() };
}
}
}
Имейте в виду, что это просто встраивает вывод одного сериализатора как необработанные данные в другой. К счастью, protobuf-net хорошо говорит о двоичном коде, так что это не добавит заметных накладных расходов (только префикс заголовка и длины для большого двоичного объекта), но также не будет делать ничего особенно умного или умного с SessionSecurityToken
экземпляров. Если это единственное, что вы сериализуете, это действительно того не стоит. Если это всего лишь один уродливый удар в более крупной модели DTO, где большинство из них может хорошо сериализоваться - тогда это может сделать работу за вас.