protobuf -net 不知道如何序列化 type = object 的数据成员

Posted

技术标签:

【中文标题】protobuf -net 不知道如何序列化 type = object 的数据成员【英文标题】:protobuf -net doesn’t know how to serialize datamember that are of type = object 【发布时间】:2013-03-06 03:43:52 【问题描述】:

我们将以下类作为 ADO.NET Provider 的一部分,使用 WCF 在网络上运行。

[KnownType(typeof(AdoServiceCommandExecutionScalarResult))]
[DataContract(Namespace = Namespaces.SoafXmlNamespace)]
public class AdoServiceCommandExecutionResult


[DataContract(Namespace = Namespaces.SoafXmlNamespace)]
public class AdoServiceCommandExecutionScalarResult : AdoServiceCommandExecutionResult

    [DataMember]
    public object Result  get; set; 

    public override string ToString()
    
        return new XDocument(new XElement(GetType().Name, new XAttribute("Result", Result))).ToString();
    

我们正在尝试使用 protobuf-net 进行序列化,但是抛出了无法解析类型对象的异常。

异常消息:

No serializer defined for type: System.Object

堆栈跟踪:

ProtoBuf.Meta.ValueMember.BuildSerializer()
ProtoBuf.Meta.ValueMember.get_Serializer()
ProtoBuf.Meta.MetaType.BuildSerializer()
ProtoBuf.Meta.MetaType.get_Serializer()
ProtoBuf.Meta.MetaType.ProtoBuf.Serializers.ISerializerProxy.get_Serializer()
ProtoBuf.Serializers.SubItemSerializer.ProtoBuf.Serializers.IProtoTypeSerializer.HasCallbacks(CallbackType callbackType)
ProtoBuf.Serializers.TypeSerializer.HasCallbacks(CallbackType callbackType)
ProtoBuf.Serializers.TypeSerializer.ProtoBuf.Serializers.IProtoSerializer.EmitWrite(CompilerContext ctx, Local valueFrom)
ProtoBuf.Compiler.CompilerContext.WriteNullCheckedTail(Type type, IProtoSerializer tail, Local valueFrom)
ProtoBuf.Compiler.CompilerContext.BuildSerializer(IProtoSerializer head, TypeModel model)
ProtoBuf.Serializers.CompiledSerializer..ctor(IProtoTypeSerializer head, TypeModel model)
ProtoBuf.Meta.MetaType.get_Serializer()
ProtoBuf.Meta.RuntimeTypeModel.Serialize(Int32 key, Object value, ProtoWriter dest)
ProtoBuf.Meta.TypeModel.TrySerializeAuxiliaryType(ProtoWriter writer, Type type, DataFormat format, Int32 tag, Object value, Boolean isInsideList)
ProtoBuf.Meta.TypeModel.TrySerializeAuxiliaryType(ProtoWriter writer, Type type, DataFormat format, Int32 tag, Object value, Boolean isInsideList)
ProtoBuf.Meta.TypeModel.SerializeCore(ProtoWriter writer, Object value)
ProtoBuf.Meta.TypeModel.Serialize(Stream dest, Object value, SerializationContext context)
ProtoBuf.ServiceModel.XmlProtoSerializer.WriteObjectContent(XmlDictionaryWriter writer, Object graph)
System.Runtime.Serialization.XmlObjectSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph)
System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer)
System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota)
System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
System.ServiceModel.Channels.HttpOutput.SerializeBufferedMessage(Message message)
System.ServiceModel.Channels.HttpOutput.Send(TimeSpan timeout)
System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.SendReplyCore(Message message, TimeSpan timeout)
System.ServiceModel.Channels.HttpRequestContext.OnReply(Message message, TimeSpan timeout)
System.ServiceModel.Channels.RequestContextBase.Reply(Message message, TimeSpan timeout)
System.ServiceModel.Channels.RequestContextBase.Reply(Message message, TimeSpan timeout)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.Reply(MessageRpc& rpc)

有可能解决这个问题吗?

编辑: 我们有一个自定义例程,基本上可以(为简洁起见)。

type.GetAttributes<KnownTypeAttribute>().Select(a => a.Type).Distinct().ForEach(t => AddKnownTypeHierarchy(t));  

public static void AddKnownTypeHierarchy(Type type)


    ProtoBuf.Meta.MetaType metaType = RuntimeTypeModel.Default.Add(type, true);
    ...
    var fieldNumber = derivedType.MetadataToken;
    metaType.AddSubType(fieldNumber, derivedType);
    ...
    var memberType = member.MemberInfo.As<PropertyInfo>().IfNotNull(p => p.PropertyType) ?? member.As<FieldInfo>().IfNotNull(f => f.FieldType);
    var field = metaType.AddField(member.Order, member.Name);
    if (memberType == typeof (object) || memberType.EqualsGenericTypeFor(typeof (IEnumerable<>))) field.DynamicType = true;
    ...

我们添加了一个逻辑,即如果遇到一个对象,它应该被视为动态的。 这种方法导致了以下异常:

Dynamic type is not a contract-type: Int32

是否可以添加对将对象视为动态对象的支持?

【问题讨论】:

请问您能报告exact异常消息吗? 编辑问题以包含异常消息和堆栈跟踪 是否可以添加对将对象视为动态对象的支持? 对此的支持有限,但我真诚的建议是:不要。 Protobuf 本质上不是基于元类型。最好简单地告诉它你在合约 API 上使用什么数据,而不是使用对象, 【参考方案1】:

Protobuf 需要特定类型来序列化/反序列化。你需要给它一些具体的东西而不是对象。

【讨论】:

以上是关于protobuf -net 不知道如何序列化 type = object 的数据成员的主要内容,如果未能解决你的问题,请参考以下文章

谷歌出品:Protobuf 你知道吗?

Netty如何使用Protobuf 序列化

我需要用 Protobuf 存储长度信息吗?

图文分析:如何利用Google的protobuf,来思考设计实现自己的RPC框架

如何使用 protobuf 在 C# 中序列化字典?

如何序列化/反序列化 protobuf-c 中的枚举