I am attempting to save an object as serialized string and then I need to deserialize it back to an object at a later stage. I want to avoid using the file system.
The serializing is being done with this function:
public string SerializeObject<T>(T objectToSerialize)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream memStr = new MemoryStream();
try
{
bf.Serialize(memStr, objectToSerialize);
memStr.Position = 0;
return Convert.ToBase64String(memStr.ToArray());
}
finally
{
memStr.Close();
}
}
Which I got from here .
This appears to be working. However, when I attempt to deserialize to an object using the following functions, I am getting an error.
public Call deSerialize(string Serialized)
{
Stream Fs = GenerateStreamFromString(Serialized);
BinaryFormatter F = new BinaryFormatter();
Call s1 = (Call)F.Deserialize(Fs);
Fs.Close();
return s1;
}
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(Convert.FromBase64String(s));
writer.Flush();
stream.Position = 0;
return stream;
}
The error I am getting is:
End of Stream encountered before parsing was completed.
And it is occurring on the line reading:
Call s1 = (Call)F.Deserialize(Fs);
Is there a way around this, or perhaps a better way to deserialize a string without using the file system?
Disclaimer: I don't have anything against the use of Newtonsoft Json in general
The problem is that you are using StreamWriter
to write the re-constructed bytes from Convert.FromBase64String
to a MemoryStream
.
MSDN: (my empasis)
Implements a TextWriter for writing characters to a stream in a particular encoding.
In your case this results in a much smaller buffer in MemoryStream
thus leading to an exception later in Deserialize
.
We can see the differences in sizes below:
MemStreamTest.exe Information: 0 : Position: 206 after save
MemStreamTest.exe Information: 0 : ToArray returned: 206 bytes
MemStreamTest.exe Information: 0 : Position: 13 after reconstruction
Change this:
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(Convert.FromBase64String(s));
writer.Flush();
stream.Position = 0;
return stream;
}
...to:
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
var bytes = Convert.FromBase64String(s);
stream.Write(bytes, 0, bytes.Length);
Trace.TraceInformation($"Position: {stream.Position} after reconstruction");
stream.Position = 0;
return stream;
}
The following example of Call
results in 206 bytes in each MemoryStream
.
var call = new Call {PhoneNumber = "0812345678", Duration = TimeSpan.FromMinutes(5)};
[Serializable]
public class Call
{
public TimeSpan Duration { get; set; }
public string PhoneNumber { get; set; }
}
Results:
MemStreamTest.exe Information: 0 : Position: 206 after save
MemStreamTest.exe Information: 0 : ToArray returned: 206 bytes
MemStreamTest.exe Information: 0 : Position: 206 after reconstruction
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace MemStreamTest
{
class Program
{
static void Main(string[] args)
{
var program = new Program();
program.Run();
}
private void Run()
{
var call = new Call {PhoneNumber = "0812345678", Duration = TimeSpan.FromMinutes(5)};
var contents = SerializeObject(call);
var other = deSerialize(contents);
}
public string SerializeObject<T>(T objectToSerialize)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream memStr = new MemoryStream();
try
{
bf.Serialize(memStr, objectToSerialize); // serialise as binary
Trace.TraceInformation($"Position: {memStr.Position} after save");
memStr.Position = 0;
var bytes = memStr.ToArray();
Trace.TraceInformation($"ToArray returned: {bytes.Length} bytes");
return Convert.ToBase64String(bytes); // binary to Base64
}
finally
{
memStr.Close();
}
}
public Call deSerialize(string Serialized)
{
Stream Fs = GenerateStreamFromString(Serialized);
BinaryFormatter F = new BinaryFormatter();
Call s1 = (Call)F.Deserialize(Fs);
Fs.Close();
return s1;
}
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
var bytes = Convert.FromBase64String(s);
stream.Write(bytes, 0, bytes.Length);
Trace.TraceInformation($"Position: {stream.Position} after reconstruction");
stream.Position = 0;
return stream;
}
}
[Serializable]
public class Call
{
public TimeSpan Duration { get; set; }
public string PhoneNumber { get; set; }
}
}
Unless you really want a Base64 payload you would be advised to use Newtonsoft Json.
You can use Newtonsoft Jsonconvert to do this out of the box:
var stringValue = JsonConvert.SerializeObject(entity);
var object = JsonConvert.DeserializeObject<T>(stringValue);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.