套接字上的Protobuf-net序列化。 没有无参数构造函数发现ProtoException

我创建了一个使用套接字完成进程间通信的应用程序。 当客户端与我创建的服务器连接并发送序列化消息时,该过程开始。 这条消息,我使用Protobuf-net进行序列化,使用SerializeWithLengthPrefix并使用DeserializeWithLengthPrefix对其进行反序列化。 客户端将消息发送到完全反序列化的服务器,但在服务器到客户端的情况下却不是这样。

主类是BaseMessage,它是抽象的。

[Serializable, ProtoContract, ProtoInclude(5001, typeof(LogonMessage))] abstract public class BaseMessage { public BaseMessage() { } abstract public int MessageType { get; } } 

LogonMessage实现了BaseMessage类。

 [Serializable, ProtoContract] public class LogonMessage : BaseMessage { public LogonMessage() { } [ProtoMember(1)] public string Broker { get; set; } [ProtoMember(2)] public int ClientType { get; set; } public override int MessageType { get { return 1; } } } 

在初始握手之后,客户端请求在protobuf-net的帮助下序列化一些服务,并且我端的本地服务器通过从Web上的另一个服务器请求数据来服务它。 从客户端到服务器的此消息传输完美无瑕。

当我的服务器从Web服务器接收数据时,它将其序列化并将数据发送到客户端。 但是这一次,当我尝试使用相同的过程反序列化客户端的数据时,我得到以下exception:“找不到BaseMessage的无参数构造函数”

我使用以下代码行反序列化(这是exception发生的地方)。

 BaseMessage baseMessage = Serializer.DeserializeWithLengthPrefix(networkStream, PrefixStyle.Base128); 

这就是消息在服务器上序列化的方式。

 Serializer.SerializeWithLengthPrefix(networkStream, baseMessage, PrefixStyle.Base128); 

在客户端和服务器之间的连接开始时使用的NetworkStream存储在对象中,该对象存储在字典中。 我从字典中的该对象中挑出相同的NetworkStream,并使用它将序列化数据发送到客户端(从服务器)。 但是会出现上述问题。 有帮助吗?

提前致谢…

这应该在任何v2版本中都能正常工作; 2.0.0.480是目前在NuGet上公布的下载,但也可以使用2.0.0.580。 我已经检查了1.0.0.280和2.0.0.480,它们都没有显示这个症状,所以我猜你正在使用不同的版本。 因此,我的建议是:确保您使用其中一个(或更高,如果可用)。

有关信息,您不需要[Serializable]用于protobuf-net,但它也不会受到伤害。 此外,您的BaseMessage构造函数应该受到protectedpublicabstract类型的构造函数没有意义)。 但由于编译器会自动为您完成所有这些操作,因此您可以简化:

 [ProtoContract, ProtoInclude(5001, typeof(LogonMessage))] abstract public class BaseMessage { abstract public int MessageType { get; } } [ProtoContract] public class LogonMessage : BaseMessage { [ProtoMember(1)] public string Broker { get; set; } [ProtoMember(2)] public int ClientType { get; set; } public override int MessageType { get { return 1; } } } 

其他想法: 5001有点偏高; 从低价值的包含数字中获得更高的效率。 1跳跃到脑海。 它们不必具有普遍的独特性:在该类型中仅具有独特性。

只是添加,我试图反序列化一个没有寻找到原点的MemoryStream,并获得“找不到BaseObject的无参数构造函数”exception,即使该类确实有一个无参数构造函数。

 var tdp = new DerivedObject("Test"); using (var ms = new MemoryStream()) { Serializer.Serialize(ms,tdp); //was missing this line ms.Seek(0, SeekOrigin.Begin); var tdp2 = Serializer.Deserialize(ms); } 

我知道这是问题得到解答后的几年,但是对于其他人的价值,我只是遇到了一个问题,我正在使用一个抽象基类并获得{className的无参数构造函数“消息,但是出于一个完全错误的原因……愚蠢的我,我从一个没有任何内容的MemoryStream中反序列化(显然,当时我并不知道)。 令人沮丧的愚蠢。 正确的错误信息应该是: "id10t error - cannot deserialize nothing, dum dum!"

因为错误消息是指一些构造函数问题,以及抽象类的使用,这让我觉得我错误地使用了库(即 – 没有正确地装饰具​​有相应Proto *属性的类/成员等)

关键是:把这个错误信息带到一粒盐 – 你的exception的根本原因可能就像我的; 退后一步,看看你正在访问protobuf-net API周围的移动部件,并确保在将头撞到墙上之前没有任何愚蠢的行为,搜索一个库(也就是说,在这种情况下,实际上工作正常)从外面。

如何重现错误? 有一堆嘈杂的代码分散你的实际错误与红鲱鱼错误信息… …如下所示:

 [TestClass] public class UnitTestJammieJawns { [TestMethod] public void ProtobufAbstract_TestMethod() { var sub = new Sub() { AbstractInt = 234 , OtherInt32 = 987, SomeString = "qwer" }; byte[] buffer = null; using (var ms = new MemoryStream()) { ProtoBuf.Serializer.Serialize(ms, sub); // works - hooray! buffer = ms.ToArray(); // we've got binary content, people! } Sub obj = null; using (var ms = new MemoryStream()) // woops... you forgot the provide the serialized object - should be: new MemoryStream(buffer) { obj = ProtoBuf.Serializer.Deserialize(ms); // <- throws exception (this is good) with misleading message (this is not so good) } } } [ProtoContract] [ProtoInclude(1, typeof(Sub))] public abstract class Super { public abstract int AbstractInt { get; set; } [ProtoMember(1)] public string SomeString { get; set; } } [ProtoContract] public class Sub : Super { [ProtoMember(2)] private int asdf; public override int AbstractInt { get { return asdf; } set { asdf = value; } } [ProtoMember(3)] public int OtherInt32 { get; set; } } 

希望这可以节省别人给我带来的麻烦。