Deserialize from MemoryStream issue - c#

I need help to figure out how to deserialize from MemoryStream.
var xmlStream = new MemoryStream();
e.Extract(xmlStream);
if (xmlStream != null)
{
TextReader tr = new StreamReader(xmlStream);
var contentItems = new ContentItems();
var serializer = new XmlSerializer(typeof(ContentItems));
contentItems = (ContentItems)serializer.Deserialize(tr); // Error is here

I found the solution
we should add
xmlStream.Seek(0, SeekOrigin.Begin);
so the final code looks like
var xmlStream = new MemoryStream();
e.Extract(xmlStream);
if (xmlStream != null)
{
xmlStream.Seek(0, SeekOrigin.Begin);
var contentItems = new ContentItems();
var serializer = new XmlSerializer(typeof(ContentItems));
contentItems = (ContentItems)serializer.Deserialize(xmlStream); // NO ERROR

Related

Blob Storage infrastructure IBlobContainer relies on deprecated mechanism. How should I fix this?

I am implementing the BLOB Storing capability provided through the Volo.Abp.BlobStoring.IBlobContainer interface.
I believe I have everything coded and configured correctly but a recent deprecation by Microsoft has me wondering if there is a better implementation than what I am attempting.
Here is my code:
public async Task StorePhotoAsync(Photo photo)
{
var photoBytes = ObjectToByteArray(photo);
await _blobContainer.SaveAsync(photo.Id.ToString(), photoBytes);
}
// TODO - Reimplement (deprecated serialization) - JLavallet 2022-03-09 10:41
private byte[] ObjectToByteArray(object obj)
{
if (obj == null)
{
return null;
}
var bf = new BinaryFormatter();
using var ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
// TODO - Reimplement (deprecated serialization) - JLavallet 2022-03-09 10:41
private object ByteArrayToObject(byte[] arrBytes)
{
using var memStream = new MemoryStream();
var binForm = new BinaryFormatter();
memStream.Write(arrBytes, 0, arrBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
var obj = binForm.Deserialize(memStream);
return obj;
}
As you can see from my to do comments and the screenshot below, there is a deprecation of the Serialize and Deserialize methods of the BinaryFormatter:
Could anyone suggest an alternative approach? The IBlobContainer only wants to save a byte array.
So after Mr. T set me straight, I read the documentation for JSON UTF8 serialization and deserialization, and here's what I came up with:
public async Task StorePhotoCacheItemAsync(PhotoCacheItem photoCacheItem)
{
var bytes = PhotoCacheItemToByteArray(photoCacheItem);
await _blobContainer.SaveAsync(photoCacheItem.Id.ToString(), bytes);
}
private byte[] PhotoCacheItemToByteArray(PhotoCacheItem photoCacheItem)
{
if (photoCacheItem == null)
{
return null;
}
// the old way
//var bf = new BinaryFormatter();
//using var ms = new MemoryStream();
//bf.Serialize(ms, obj);
// a new way
//using var ms = new MemoryStream();
//using var writer = new Utf8JsonWriter(ms);
//JsonSerializer.Serialize(writer, photoCacheItem);
//return ms.ToArray();
// a better new way
var bytes = JsonSerializer.SerializeToUtf8Bytes(photoCacheItem);
return bytes;
}
private async Task<PhotoCacheItem> GetPhotoCacheItemFromBlobStorage(Guid photoId)
{
var bytes = await _blobContainer.GetAllBytesOrNullAsync(photoId.ToString());
if (bytes == null)
{
return null;
}
var photoCacheItem = ByteArrayToPhotoCacheItem(bytes);
return photoCacheItem;
}
private PhotoCacheItem ByteArrayToPhotoCacheItem(byte[] bytes)
{
// the old way
//using var ms = new MemoryStream();
//var bf = new BinaryFormatter();
//ms.Write(bytes, 0, bytes.Length);
//ms.Seek(0, SeekOrigin.Begin);
//var obj = bf.Deserialize(ms);
// a new way
//var utf8Reader = new Utf8JsonReader(bytes);
//var photoCacheItem = JsonSerializer.Deserialize<PhotoCacheItem>(ref utf8Reader)!;
// a better new way
var readOnlySpan = new ReadOnlySpan<byte>(bytes);
var photoCacheItem = JsonSerializer.Deserialize<PhotoCacheItem>(readOnlySpan)!;
return photoCacheItem;
}

How to Convert Different Enities in a single XML string

I have Converted a the Different entities in a List and now I have a master list containing the many list of different models.
public static string xmlSerialize(List<Object> o)
{
XmlDocument xmlOut = new XmlDocument();
foreach(var i in o)
{
using (MemoryStream xmlStream = new MemoryStream())
{
//MemoryStream myMemStr = new MemoryStream();
XmlSerializer xmlSerializer = new XmlSerializer(i.GetType());
xmlSerializer.Serialize(xmlStream, i);
xmlStream.Position = 0;
xmlOut.Load(xmlStream);
}
}
return xmlOut.InnerXml;
}
The above method converts the multiple List into a XML. But this code Overwrites the previous XML string in every loop run.
Is There any solution to get the single XML for every entity.
IMHO - the simplest solution here is to load xml into temporary XmlDocument and then perform Import
Idea is the following
public static string xmlSerialize(List<Object> o)
{
XmlDocument xmlOut = new XmlDocument();
foreach(var i in o)
{
var tmpDoc = new XmlDocument();
using (MemoryStream xmlStream = new MemoryStream())
{
//MemoryStream myMemStr = new MemoryStream();
XmlSerializer xmlSerializer = new XmlSerializer(i.GetType());
xmlSerializer.Serialize(xmlStream, i);
xmlStream.Position = 0;
tmpDoc.Load(xmlStream);
}
var newNode = xmlOut.ImportNode(tmpDoc.DocumentElement.LastChild, true);
xmlOut.DocumentElement.AppendChild(newNode);
}
return xmlOut.InnerXml;
}

Deserialization of MemoryStream via BinaryFormatter

didn't find a solution to following problem.
I had a working code for saving/loading a TreeView in a file but I want to save it to Properties.Settings.Default.
Unfortunately I get the error "no map for object" in this line:
object obj = bf.Deserialize(ms);
Here is the complete code for (de)serialization:
Don't know how to solve this one. :(
public static void SaveTreeView(TreeView tree)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, tree.Nodes.Cast<TreeNode>().ToList());
ms.Position = 0;
var sr = new StreamReader(ms);
Properties.Settings.Default.tree = sr.ReadToEnd();
Properties.Settings.Default.Save();
}
}
public static void LoadTreeView(TreeView tree)
{
using (MemoryStream ms = new MemoryStream())
{
var sw = new StreamWriter(ms);
sw.WriteLine(Properties.Settings.Default.tree);
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
BinaryFormatter bf = new BinaryFormatter();
object obj = bf.Deserialize(ms);
TreeNode[] nodeList = (obj as IEnumerable<TreeNode>).ToArray();
tree.Nodes.AddRange(nodeList);
}
}
Anybody got an idea?
Thanks is advance.
Try this out
public static void SaveTree(TreeView tree)
{
using (var ms = new MemoryStream())
{
new BinaryFormatter().Serialize(ms, tree.Nodes.Cast<TreeNode>().ToList());
Properties.Settings.Default.tree = Convert.ToBase64String(ms.ToArray());
Properties.Settings.Default.Save();
}
}
public static void LoadTree(TreeView tree)
{
byte[] bytes = Convert.FromBase64String(Properties.Settings.Default.tree);
using (var ms = new MemoryStream(bytes, 0, bytes.Length))
{
ms.Write(bytes, 0, bytes.Length);
ms.Position = 0;
var data = new BinaryFormatter().Deserialize(ms);
tree.Nodes.AddRange(((List<TreeNode>)data).ToArray());
}
}

Converting code to use JSON.net instead of System.Runtime.Serialization.DataContractSerializer

How do I do the equivalent in JSON.net?
public SerializedResults SerializeResults(Type queryType, IEnumerable entities)
{
var results = SerializeDynamicType(queryType);
var objList = AnonymousFns.DeconstructMany(entities, false, queryType).ToList();
var ms = new MemoryStream();
var type = objList.GetType();
var serializer = new DataContractSerializer(type);
using (ms)
{
using (GZipStream compress = new GZipStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression))
{
serializer.WriteObject(compress, objList);
}
}
results.ByteArray = ms.ToArray();
return results;
}
I am confused with this line in particular:
var serializer = new DataContractSerializer(type);
How do you do that in JSON.NET??
THANKS :-)
With JSON.NET, you don't need the type when serializing. I'm assuming that it works out the type you are passing in on its own.
So, you can get rid of this completely:
var type = objList.GetType();
var serializer = new DataContractSerializer(type);
And change this:
serializer.WriteObject(compress, objList);
To:
var json = JsonConvert.SerializeObject(objList);
Here are the JSON.Net docs for JsonConvert.
I believe you can use the BsonWriter to write to a stream. I'm not sure it will give you the exact same binary format you had before, but in concept it is the same.
public SerializedResults SerializeResults(Type queryType, IEnumerable entities)
{
var results = SerializeDynamicType(queryType);
var objList = AnonymousFns.DeconstructMany(entities, false, queryType).ToList();
var ms = new MemoryStream();
using (ms)
{
using (GZipStream compress = new GZipStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression))
{
using( BsonWriter writer = new BsonWriter(compress))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(writer, objList);
}
}
}
results.ByteArray = ms.ToArray();
return results;
}

Converting Class to XML to string

I'm using XMLSerializer to serialize a class into a XML. There are plenty of examples to this and save the XML into a file. However what I want is to put the XML into a string rather than save it to a file.
I'm experimenting with the code below, but it's not working:
public static void Main(string[] args)
{
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
MemoryStream m = new MemoryStream();
ser.Serialize(m, new TestClass());
string xml = new StreamReader(m).ReadToEnd();
Console.WriteLine(xml);
Console.ReadLine();
}
public class TestClass
{
public int Legs = 4;
public int NoOfKills = 100;
}
Any ideas on how to fix this ?
Thanks.
You have to position your memory stream back to the beginning prior to reading like this:
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
MemoryStream m = new MemoryStream();
ser.Serialize(m, new TestClass());
// reset to 0 so we start reading from the beginning of the stream
m.Position = 0;
string xml = new StreamReader(m).ReadToEnd();
On top of that, it's always important to close resources by either calling dispose or close. Your full code should be something like this:
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
string xml;
using (MemoryStream m = new MemoryStream())
{
ser.Serialize(m, new TestClass());
// reset to 0
m.Position = 0;
xml = new StreamReader(m).ReadToEnd();
}
Console.WriteLine(xml);
Console.ReadLine();
There's the [Serializabe] attribute missing on class TestClass and you have to set the position of the memory stream to the beginning:
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
MemoryStream m = new MemoryStream();
ser.Serialize(m, new TestClass());
m.Position = 0;
string xml = new StreamReader(m).ReadToEnd();
Console.WriteLine(xml);
Console.ReadLine();
Your memory stream is not closed, and is positioned at the end (next available location to write in). My guess is that you must Close it, or Seek to its beginning. The way you do you don't read anything because you are already at the end of stream. So add Seek() after you serialize objects. Like this:
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
MemoryStream m = new MemoryStream();
ser.Serialize(m, new TestClass());
m.Seek(0, SeekOrigin.Begin); //<-- ADD THIS!
string xml = new StreamReader(m).ReadToEnd();
Console.WriteLine(xml);
Console.ReadLine();

Categories

Resources