views:

64

answers:

1

I have an elementary stumper using serialization in an ASP.NET 2.0 application on a C# class containing an enum property. It's my understanding that serialization of enumerations is supported if they map to integers. So, I can't figure out why I'm having this problem serializing/deserializing my enum.

My Code:

[Serializable]
public class Report
{
    public PercentTime paramPercentRange;

    // Constructors
    public Report()
    {
    }
    public Report(PercentTime percentRange)
    {
        paramPercentRange = percentRange;
    }
}

public enum PercentTime
{
    Null = 0,
    ZeroToFivePercent = 1,
    FiveToTenPercent = 2,
    TenToFifteenPercent = 3,
    FifteenToTwentyPercent = 4,
    MoreThanTwentyPercent = 5
}

// Serialize Report to a HiddenField
public void SaveReportObject(Report reportObj, HiddenField hiddenReportObj)
{
    IFormatter formatter = new BinaryFormatter();
    Stream stream = new MemoryStream();

    // Seralize Report Object to Binary Format
    formatter.Serialize(stream, reportObj);
    stream.Position = 0;

    // Convert Stream to ASCII Encoding
    StreamReader reader = new StreamReader(stream, Encoding.ASCII);

    // Store Report Object as a Base64 Encoded String in a HiddenField
    hiddenReportObj.Value = Convert.ToBase64String(Encoding.ASCII.GetBytes(reader.ReadToEnd()));

    // Close Streams
    reader.Close();
    stream.Close();
}

public Report GetReportObject(String strBase64)
{
    Report report;
    Stream stream = new MemoryStream();
    IFormatter formatter = new BinaryFormatter();
    StreamWriter writer = new StreamWriter(stream, Encoding.ASCII);
    writer.AutoFlush = true;
    stream.Position = 0;

    // Convert Base64 String to ASCII encoded Stream
    writer.Write(Encoding.ASCII.GetString(Convert.FromBase64String(strBase64)));
    stream.Position = 0;

    // Deserialze ASCII encoded Stream
    report = (Report)formatter.Deserialize(stream);  // error 

    // Close Streams
    writer.Close();
    stream.Close();

    return report;
}

I get the following Invalid BinaryFormatter Error:

   at System.Runtime.Serialization.Formatters.Binary.SizedArray.IncreaseCapacity(Int32 index)
   at System.Runtime.Serialization.Formatters.Binary.SizedArray.set_Item(Int32 index, Object value)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
   at Pages_Reports_PercentTimeLobbyingReport.GetReportObject(String strBase64) 

When I look at the stream object, it's length is 287 but the position is 282. My first guess is that it's a problem with not reading the entire stream, but I am able to change the Report class to store the enum as an integer and it works fine. I'm very interested in learning what the problem is here.

+2  A: 

Your stream contains binary data. You're then converting that into ASCII. This is a really, really bad idea. You'll lose data. Don't do that.

You're doing base64 encoding, but in the wrong place. You should be converting the originally written binary data into base64, e.g. like this:

string text = Convert.ToBase64String(stream.ToArray());

Then to deserialize, you'd convert it the other way round:

IFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream(Convert.FromBase64String(text))
{
    return (Report)formatter.Deserialize(stream); 
}

I don't know why it was working for you when you were using an int... but my guess is that was more by luck than anything else.

You should never try reading the output of a BinaryFormatter as if it was just plain text.

Jon Skeet
I rebuilt with your suggested changes and viola no error! Jon, you are the man!
Sephrial