5

I have created an application where interprocess communication is done using sockets. The procedure starts when a client connects with the server that I created and sends a serialized message. This message, I serialize using Protobuf-net, using SerializeWithLengthPrefix and deserialize it using DeserializeWithLengthPrefix. The client sends messages to the server who deserializes it perfectly, but the same is not true in the case of server to client.

The main class is BaseMessage, which is abstract.

[Serializable, ProtoContract, ProtoInclude(5001, typeof(LogonMessage))]
abstract public class BaseMessage
{
    public BaseMessage()
    {

    }

    abstract public int MessageType { get; }
}

And LogonMessage implements the BaseMessage Class.

[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; }
    }
}

After the initial handshake, the client requests some service serialized with the help of protobuf-net and the local server at my end serves it by requesting data from another server on the web. This message transfer from the client to the server is done flawlessly.

When my server receives the data from the web server, it serializes it and sends the data to the client. But this time, when I try to deserialize the data on the client-side using the same procedure, I get the following exception: "No parameterless Constructor found for BaseMessage"

I deserialize using the following line of code(this is where the exception occurs).

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

And this is how the message was serialized on the server.

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

The NetworkStream used at the start of the connection between the client and server is stored in an object and that object is stored in a dictionary. I pick out the same NetworkStream from that object in the dictionary and use it to send serialized data to the client(from the server). But the above mentioned problem occurs. Any help?

Thanks in advance...

Syed Waqas
  • 2,576
  • 4
  • 29
  • 36

5 Answers5

4

That should work fine in any v2 release; 2.0.0.480 is the currently advertised download on NuGet, but 2.0.0.580 is also available. I've checked both 1.0.0.280 and 2.0.0.480, and neither of them show this symptom, so I'm guessing you're using a different build. My advice, therefore, is: make sure you're on one of those two (or higher, where available).

For info, you don't need [Serializable] for protobuf-net, but it doesn't hurt either. Also, your BaseMessage constructor should probably be protected (public doesn't really make sense on the constructor of an abstract type). But since the compiler does all that for you automatically, you can simplify:

[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; }
    }
}

Other thoughts: 5001 is a bit on the high-side; you will get better efficiency from low-value include-numbers. 1 leaps to mind. They don't have to be universally unique: just unique inside that type.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanx Marc... I was using r580 indeed, but there are many dlls in the folders present inside the package(CoreOnly, Full etc.) I will like to know which of the dlls suit my application best, i.e., a desktop application employing sockets? If you have time, plese elaborate the difference between CoreOnly, Full and their sub-folders(net30 netcore45 etc.) Thanx – Syed Waqas Sep 14 '12 at 11:41
  • @WaqasShah please see [`What Files Do I Need.txt`](http://protobuf-net.googlecode.com/svn/trunk/What%20Files%20Do%20I%20Need.txt), which is included in the google-code zip – Marc Gravell Sep 14 '12 at 12:22
  • @WaqasShah I couldn't reproduce this on r580; is it now behaving itself properly again? If you are still seeing this, I can investigate more. – Marc Gravell Sep 14 '12 at 12:22
  • It is working fine at my end now... Just one more thing, when does Protobuf throws this No parameterless constructor found exception although their are parameterless constructors present? Is there another scenario related to this one that can throw the exception? – Syed Waqas Sep 14 '12 at 13:29
  • @Waqas one that leaps to mind is: if you are running on a restricted framework (Silcerlight, etc) and the parameterless constructor is non-public. Then it won't be able to use it. But on regular full framework it can use non-public constructors, or even skip the constructor entirely. – Marc Gravell Sep 15 '12 at 06:53
  • I'll just mention that I'm getting this exception when I stupidly tried to deserialize an abstract class. Maybe provide a more specific exception for that case? (The abstract class had a parameterless constructor, making the current exception text seem incorrect.) – RenniePet Sep 01 '13 at 21:13
  • I get this error now in `2.4.0`. Abstract base class, but all the default constructors are there and the stream is not empty. – mark Oct 02 '18 at 02:34
  • @mark any chance you removed a concrete type? I'd love to see a code example – Marc Gravell Oct 02 '18 at 06:46
  • I am probably doing something wrong. Would love to debug the code myself but building protobuf is another challenge... – mark Oct 02 '18 at 11:51
  • @mark I meant some minimal code from what you *are* doing, so I can try to repro it; you shouldn't need to build the lib for that – Marc Gravell Oct 02 '18 at 12:53
  • @MarcGravell - Here you go - https://stackoverflow.com/questions/52618157/why-does-the-following-trivial-c-sharp-code-raise-a-protoexception-about-a-missi – mark Oct 03 '18 at 00:34
3

Just to add, I was trying to deserialize a MemoryStream that was not seeked to the origin and got the "No parameterless Constructor found for BaseObject" exception even if the class did have a parameterless constructor.

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<DerivedObject>(ms);
}
Halvor Holsten Strand
  • 19,829
  • 17
  • 83
  • 99
JP Tissot
  • 51
  • 5
  • Thank you for this, I was pulling my hair out for an hour. I wasn't able to deserialize the base class, I even tried adding constructors to no avail. Seeking to the beginning of the stream worked! – Michael Brown Apr 26 '18 at 06:19
2

i know this is a couple of years after the question has been answered, but for what it's worth to others, i was just running in to an issue where i was using an abstract base class and getting the "No parameterless constructor found for {className}" message, but for a totally wrong reason... silly me, i was deserializing from a MemoryStream with nothing in it (obviously, unbeknownst to me at the time). frustratingly dumb. the proper error message should have been: "id10t error - cannot deserialize nothing, dum dum!".

because the error message was referring to some constructor problem, along with the usage of abstract classes, that made me think i was using the library incorrectly (i.e. - not correctly adorning the classes/members with repective Proto* attributes, etc.)

the point is: take this take this error message with a grain of salt - your root cause of the exception could be like mine; take a step back and look at the moving parts around where you're accessing the protobuf-net API and make sure there's nothing goofy going on around there before banging your head against the wall, scouring a library (that is, in this case, actually working correctly) from the outside.

how to reproduce the error? have a bunch of noisy code distract you from the actual bug in tandem with a red-herring error message... like so:

[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<Sub>(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; }
}

hope this saves someone else the headache it caused me.

isandburn
  • 134
  • 5
0

This error message seems to be a catch all for a variety of different errors like @isandburn and @JP Tissot have pointed out.

Another is if you Deserialize data that isn't protobuf.

var tdp = new DerivedObject("Test");
using (var ms  = new MemoryStream())
{
    JsonSerializer.Serialize(ms,tdp); //should be protobuf
    ms.Seek(0, SeekOrigin.Begin);

    var tdp2 = Serializer.Deserialize<DerivedObject>(ms);
}
odyth
  • 4,324
  • 3
  • 37
  • 45
-3

Error

"No parameterless constructor found"

i got, when in protocol buffer binary stream was not Sub class (linked through [ProtoInclude]) just on begin stream (first in binary data).

Community
  • 1
  • 1
tokmo
  • 1
  • 1