Ryan Rodemoyer
Ryan Rodemoyer

Reputation: 5682

protobuf-net returns null when calling Deserialize

My end goal is to use protobuf-net and GZipStream in an attempt to compress a List<MyCustomType> object to store in a varbinary(max) field in SQL Server. I'm working on unit tests to understand how everything works and fits together.

Target .NET framework is 3.5.

My current process is:

  1. Serialize the data with protobuf-net (good).
  2. Compress the serialized data from #1 with GZipStream (good).
  3. Convert the compressed data to a base64 string (good).

At this point, the value from step #3 will be stored in a varbinary(max) field. I have no control over this. The steps resume with needing to take a base64 string and deserialize it to a concrete type.

  1. Convert a base 64 string to a byte[] (good).
  2. Decompress the data with GZipStream (good).
  3. Deserialize the data with protobuf-net (bad).

Can someone assist with why the call to Serializer.Deserialize<string> returns null? I'm stuck on this one and hopefully a fresh set of eyes will help.

FWIW, I tried another version of this using List<T> where T is a custom class I created and I Deserialize<> still returns null.

FWIW 2, data.txt is a 4MB plaintext file residing on my C:.

    [Test]
    public void ForStackOverflow()
    {
        string data = "hi, my name is...";
        //string data = File.ReadAllText(@"C:\Temp\data.txt");

        string serializedBase64;

        using (MemoryStream protobuf = new MemoryStream())
        {
            Serializer.Serialize(protobuf, data);

            using (MemoryStream compressed = new MemoryStream())
            {
                using (GZipStream gzip = new GZipStream(compressed, CompressionMode.Compress))
                {
                    byte[] s = protobuf.ToArray();
                    gzip.Write(s, 0, s.Length);
                    gzip.Close();
                }

                serializedBase64 = Convert.ToBase64String(compressed.ToArray());
            }
        }

        byte[] base64byteArray = Convert.FromBase64String(serializedBase64);

        using (MemoryStream base64Stream = new MemoryStream(base64byteArray))
        {
            using (GZipStream gzip = new GZipStream(base64Stream, CompressionMode.Decompress))
            {
                using (MemoryStream plainText = new MemoryStream())
                {
                    byte[] buffer = new byte[4096];
                    int read;

                    while ((read = gzip.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        plainText.Write(buffer, 0, read);
                    }

                    // why does this call to Deserialize return null?
                    string deserialized = Serializer.Deserialize<string>(plainText);

                    Assert.IsNotNull(deserialized);
                    Assert.AreEqual(data, deserialized);
                }
            }
        }
    }

Upvotes: 2

Views: 1886

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062492

Because you didn't rewind plainText after writing to it. Actually, that entire Stream is unnecessary - this works:

using (MemoryStream base64Stream = new MemoryStream(base64byteArray))
{
    using (GZipStream gzip = new GZipStream(
        base64Stream, CompressionMode.Decompress))
    {
        string deserialized = Serializer.Deserialize<string>(gzip);

        Assert.IsNotNull(deserialized);
        Assert.AreEqual(data, deserialized);
    }
}

Likewise, this should work for the serialize:

using (MemoryStream compressed = new MemoryStream())
{
    using (GZipStream gzip = new GZipStream(
        compressed, CompressionMode.Compress, true))
    {
        Serializer.Serialize(gzip, data);
    }

    serializedBase64 = Convert.ToBase64String(
        compressed.GetBuffer(), 0, (int)compressed.Length);
}

Upvotes: 4

Related Questions