XML Serialize and deserialize performance comparison - c#

This question asked in different websites but i could not find any useful answer, and still im having some performance issues.
I have two serializer method in my common layer application
public static string Serializer(object o)
{
var x = new XmlSerializer(o.GetType());
var writer = new StringWriter();
var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { OmitXmlDeclaration = true });
var emptyNs = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
x.Serialize(xmlWriter, o, emptyNs);
return writer.ToString();
}
public static string Serializer<T>(T o)
{
var x = new XmlSerializer(typeof(T));
var writer = new StringWriter();
var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { OmitXmlDeclaration = true });
x.Serialize(xmlWriter, o, new XmlSerializerNamespaces( new[] { XmlQualifiedName.Empty } ));
return writer.ToString();
}
and two deserializer method
public static T Deserializer<T>(string objectData)
{
var serializer = new XmlSerializer(typeof(T));
T result;
using (TextReader reader = new StringReader(objectData))
{
result =(T) serializer.Deserialize(reader);
}
return result;
}
public static object Deserializer(object o, string filename)
{
object retVal;
var ser = new XmlSerializer(o.GetType());
using (var reader = XmlReader.Create(filename))
{
retVal = ser.Deserialize(reader);
}
return retVal;
}
I have run different load tests in both of serializer methods, and all of them shown that Serializer<T>(T o) works slower than Serializer(object o), which in my opinion must be reverse since typeof() is faster and the type is known unlike object. I would like to know about your opinions first ?
and second, the serializer and deserializer methods used in another method named
public static TResponse SendRequest <TRequest,TResponse>(TRequest rq, Uri requestUri)
which is responsible to send the request to web server and get the response back, is there anyway to make it more efficient ?

I wrote the following code and I didn't notice any significant difference. Though, serializing through generics is slightly faster. Here is the code:
public class TestData {
public string Name { get; set; }
public string FullName { get; set; }
public string Address { get; set; }
public int PostalCode { get; set; }
public TestData() {
}
public TestData(string name, string fullName, string address, int postalCode) {
Name = name;
FullName = fullName;
Address = address;
PostalCode = postalCode;
}
}
public static class Program
{
public static string Serializer(object o)
{
var x = new XmlSerializer(o.GetType());
var writer = new StringWriter();
var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { OmitXmlDeclaration = true });
var emptyNs = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
x.Serialize(xmlWriter, o, emptyNs);
return writer.ToString();
}
public static string Serializer<T>(T o)
{
var x = new XmlSerializer(typeof(T));
var writer = new StringWriter();
var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { OmitXmlDeclaration = true });
x.Serialize(xmlWriter, o, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
return writer.ToString();
}
public static void Main(string[] args) {
Random rand = new Random();
const int numberOfCycles = 1000000;
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < numberOfCycles; i++) {
object data = new TestData("", "", "", rand.Next());
Serializer(data);
}
watch.Stop();
Console.WriteLine(string.Format("Through object:{0}", watch.ElapsedMilliseconds));
watch.Restart();
for (int i = 0; i < numberOfCycles; i++) {
Serializer(new TestData("", "", "", rand.Next()));
}
watch.Stop();
Console.WriteLine(string.Format("Through generic:{0}", watch.ElapsedMilliseconds));
Console.ReadLine();
}
}
Maybe it would be better to share with us a class you are trying to serialize/deserialize and share the code by which you made your estimations of executing time of serializing methods.

Related

Serialize XML from C# class, need to set namespaces

I'm having trouble getting my top-level element to look exactly like this using the XmlSerializer (and C# attributes):
<rootObject xmlns="http://www.example.com/xmlschemas/nonStandardSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.com/xmlschemas/nonStandardSchema1.xsd">
<otherSerializedObjects />
</rootObject>
Currently, the closest I've gotten is this:
<rootObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
d1p1:schemaLocation="http://www.example.com/xmlschemas/nonStandardSchema1.xsd"
xmlns:d1p1="xsi"
xmlns="http://www.example.com/xmlschemas/nonStandardSchema">
<otherSerializedObjects />
</rootObject>
C#
[XmlRoot("rootObject", Namespace = "http://www.example.com/xmlschemas/nonStandardSchema")]
public class RootObject
{
[XmlAttribute("schemaLocation", Namespace = "xsi")]
public string SchemaLocation { get; set; }
[XmlElement("Image")]
public Object[] OtherSerializedObjects { get; set; }
public RootObject()
{
OtherSerializedObjects = new Object[]{};
}
}
public class Program
{
static void Main(string[] args)
{
var rootObject = new RootObject
{
SchemaLocation = "http://www.example.com/xmlschemas/nonStandardSchema1.xsd",
OtherSerializedObjects = new object[]{}
};
var serializer = new XmlSerializer(typeof(RootObject));
var stringWriter = new StringWriter();
serializer.Serialize(stringWriter, rootObject);
Console.WriteLine(stringWriter.ToString());
}
}
Any ideas?
Firstly, the [XmlAttribute(Namespace=X)] attribute on your schemaLocation field/property needs to have the full namespace for the value of X, not the local namespace shortcut. Incidentally, this can be a property rather than a field. Using a field for this purpose wastes memory.
Secondly, to eliminate the standard xmlns:xsd="http://www.w3.org/2001/XMLSchema", use an XmlSerializer.Serialize overload where you pass in an XmlSerializerNamespaces with just the namespaces you want.
Thus:
[XmlRoot("rootObject", Namespace = "http://www.example.com/xmlschemas/nonStandardSchema")]
public class RootObject
{
public static XmlSerializerNamespaces GetAdditionalNamespaces()
{
XmlSerializerNamespaces xsNS = new XmlSerializerNamespaces();
xsNS.Add("", "http://www.example.com/xmlschemas/nonStandardSchema");
xsNS.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
return xsNS;
}
[XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string XSDSchemaLocation
{
get
{
return "http://www.example.com/xmlschemas/nonStandardSchema1.xsd";
}
set
{
// Do nothing - fake property.
}
}
[XmlElement("Image")]
public Object[] OtherSerializedObjects { get; set; }
public RootObject()
{
OtherSerializedObjects = new Object[]{};
}
}
And then use it like:
var rootObject = new RootObject
{
OtherSerializedObjects = new object[]{}
};
var serializer = new XmlSerializer(typeof(RootObject));
var stringWriter = new StringWriter();
var ns = RootObject.GetAdditionalNamespaces();
var settings = new XmlWriterSettings() { Indent = true, IndentChars = " " }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
{
serializer.Serialize(xmlWriter, rootObject, ns);
}
Console.WriteLine(stringWriter.ToString());
Example fiddle.
Namespace needs to be the entire namespace, not the shortened version.
[XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
In my testing it automatically used xsi.

CSV Helper not writing to file

I've been stuck trying to get the CSV Helper to write to a file. When I run DownloadRegistrantsCsv it downloads the file with the proper name and everything else, but it never writes anything to it.
public async Task<Stream> GetDownloadStreamAsync(int id)
{
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream);
var streamReader = new StreamReader(memoryStream);
var csvHelper = new CsvHelper.CsvWriter(streamWriter);
csvHelper.WriteRecord(new EventRegistrant { FirstName = "Max" });
await memoryStream.FlushAsync();
memoryStream.Position = 0;
return memoryStream;
}
public async Task<ActionResult> DownloadRegistrantsCsv(int id)
{
var #event = await _service.GetAsync(id, true);
if (#event == null)
return HttpNotFound();
var stream = await _service.GetDownloadStreamAsync(id);
return File(stream, "application/txt", "test" + ".csv");
}
I've also tried just using the documentation for the CSV Helper and I can't even get that to write. Here's what I've got for that...
// Copyright 2009-2015 Josh Close and Contributors
// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
// http://csvhelper.com
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Web.Script.Serialization;
using CsvHelper.Configuration;
using CsvHelper.TypeConversion;
namespace CsvHelper.Example
{
class Program
{
private const string columnSeparator = ":";
static void Main(string[] args)
{
//ReadRawFieldsByIndex();
//ReadRawFieldsByName();
//ReadFieldsByIndex();
//ReadRecordsNoAttributes();
//ReadRecordsWithAttributes();
//ReadAllRecords();
//WriteRawFields();
//WriteFields();
WriteRecordsNoAttributes();
//WriteRecordsWithAttributes();
WriteAllRecords();
Console.ReadKey();
}
public static void ReadRawFieldsByIndex()
{
Console.WriteLine("Raw fields by index:");
using (var reader = new CsvReader(new StreamReader(GetDataStream(true, true))))
{
while (reader.Read())
{
Console.Write(reader.GetField(0) + columnSeparator);
Console.Write(reader.GetField(1) + columnSeparator);
Console.Write(reader.GetField(2) + columnSeparator);
Console.WriteLine(reader.GetField(3));
}
}
Console.WriteLine();
}
public static void ReadRawFieldsByName()
{
Console.WriteLine("Raw fields by name:");
using (var reader = new CsvReader(new StreamReader(GetDataStream(true, true))))
{
while (reader.Read())
{
Console.Write(reader.GetField("String Column") + columnSeparator);
Console.Write(reader.GetField("Int Column") + columnSeparator);
Console.Write(reader.GetField("Guid Column") + columnSeparator);
Console.Write(reader.GetField("Does Not Exist Column") + columnSeparator);
Console.WriteLine(reader.GetField("Custom Type Column"));
}
}
Console.WriteLine();
}
public static void ReadFieldsByIndex()
{
Console.WriteLine("Fields by index:");
var customTypeTypeConverter = new CustomTypeTypeConverter();
using (var reader = new CsvReader(new StreamReader(GetDataStream(true, true))))
{
while (reader.Read())
{
Console.Write(reader.GetField<string>(0) + columnSeparator);
Console.Write(reader.GetField<int>("Int Column") + columnSeparator);
Console.Write(reader.GetField<Guid>(2) + columnSeparator);
Console.WriteLine(reader.GetField<CustomType>(3, customTypeTypeConverter));
}
}
Console.WriteLine();
}
public static void ReadRecordsNoAttributes()
{
Console.WriteLine("Records no attributes:");
using (var reader = new CsvReader(new StreamReader(GetDataStream(true, false))))
{
while (reader.Read())
{
Console.WriteLine(reader.GetRecord<CustomObject>());
}
}
Console.WriteLine();
}
public static void ReadRecordsWithAttributes()
{
Console.WriteLine("Records with attributes:");
using (var reader = new CsvReader(new StreamReader(GetDataStream(true, true))))
{
reader.Configuration.RegisterClassMap<CustomObjectWithMappingMap>();
while (reader.Read())
{
Console.WriteLine(reader.GetRecord<CustomObjectWithMapping>());
}
}
Console.WriteLine();
}
public static void ReadAllRecords()
{
Console.WriteLine("All records:");
using (var reader = new CsvReader(new StreamReader(GetDataStream(true, false))))
{
var records = reader.GetRecords<CustomObject>();
foreach (var record in records)
{
Console.WriteLine(record);
}
}
Console.WriteLine();
}
public static void WriteRawFields()
{
Console.WriteLine("Write raw fields");
using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var streamReader = new StreamReader(memoryStream))
using (var writer = new CsvWriter(streamWriter))
{
writer.WriteField("String Column");
writer.WriteField("Int Column");
writer.WriteField("Guid Column");
writer.WriteField("Custom Type Column");
writer.NextRecord();
writer.WriteField("one");
writer.WriteField((1).ToString());
writer.WriteField(Guid.NewGuid().ToString());
writer.WriteField((new CustomType { First = 1, Second = 2, Third = 3 }).ToString());
writer.NextRecord();
memoryStream.Position = 0;
Console.WriteLine(streamReader.ReadToEnd());
}
Console.WriteLine();
}
public static void WriteFields()
{
Console.WriteLine("Write fields");
using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var streamReader = new StreamReader(memoryStream))
using (var writer = new CsvWriter(streamWriter))
{
writer.WriteField("String Column");
writer.WriteField("Int Column");
writer.WriteField("Guid Column");
writer.WriteField("Custom Type Column");
writer.NextRecord();
writer.WriteField("one");
writer.WriteField(1);
writer.WriteField(Guid.NewGuid());
writer.WriteField(new CustomType { First = 1, Second = 2, Third = 3 });
writer.NextRecord();
memoryStream.Position = 0;
Console.WriteLine(streamReader.ReadToEnd());
}
Console.WriteLine();
}
public static void WriteRecordsNoAttributes()
{
Console.WriteLine("Write records no attributes:");
var records = new List<CustomObject>
{
new CustomObject
{
CustomTypeColumn = new CustomType
{
First = 1,
Second = 2,
Third = 3,
},
GuidColumn = Guid.NewGuid(),
IntColumn = 1,
StringColumn = "one",
},
new CustomObject
{
CustomTypeColumn = new CustomType
{
First = 4,
Second = 5,
Third = 6,
},
GuidColumn = Guid.NewGuid(),
IntColumn = 2,
StringColumn = "two",
},
};
using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var streamReader = new StreamReader(memoryStream))
using (var writer = new CsvWriter(streamWriter))
{
foreach (var record in records)
{
writer.WriteRecord(record);
}
memoryStream.Position = 0;
Console.WriteLine(streamReader.ReadToEnd());
}
Console.WriteLine();
}
public static void WriteRecordsWithAttributes()
{
Console.WriteLine("Write records with attributes:");
var records = new List<CustomObjectWithMapping>
{
new CustomObjectWithMapping
{
CustomTypeColumn = new CustomType
{
First = 1,
Second = 2,
Third = 3,
},
GuidColumn = Guid.NewGuid(),
IntColumn = 1,
StringColumn = "one",
},
new CustomObjectWithMapping
{
CustomTypeColumn = new CustomType
{
First = 4,
Second = 5,
Third = 6,
},
GuidColumn = Guid.NewGuid(),
IntColumn = 2,
StringColumn = "two",
},
};
using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var streamReader = new StreamReader(memoryStream))
using (var writer = new CsvWriter(streamWriter))
{
foreach (var record in records)
{
writer.WriteRecord(record);
}
memoryStream.Position = 0;
Console.WriteLine(streamReader.ReadToEnd());
}
Console.WriteLine();
}
public static void WriteAllRecords()
{
Console.WriteLine("Write all records with attributes:");
var records = new List<CustomObjectWithMapping>
{
new CustomObjectWithMapping
{
CustomTypeColumn = new CustomType
{
First = 1,
Second = 2,
Third = 3,
},
GuidColumn = Guid.NewGuid(),
IntColumn = 1,
StringColumn = "one",
},
new CustomObjectWithMapping
{
CustomTypeColumn = new CustomType
{
First = 4,
Second = 5,
Third = 6,
},
GuidColumn = Guid.NewGuid(),
IntColumn = 2,
StringColumn = "two",
},
};
using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var streamReader = new StreamReader(memoryStream))
using (var writer = new CsvWriter(streamWriter))
{
writer.Configuration.RegisterClassMap<CustomObjectWithMappingMap>();
writer.WriteRecords(records as IEnumerable);
memoryStream.Position = 0;
Console.WriteLine(streamReader.ReadToEnd());
}
Console.WriteLine();
}
public static MemoryStream GetDataStream(bool hasHeader, bool hasSpacesInHeaderNames)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
if (hasHeader)
{
var header = hasSpacesInHeaderNames
? "String Column,Int Column,Guid Column,Custom Type Column"
: "StringColumn,IntColumn,GuidColumn,CustomTypeColumn";
writer.WriteLine(header);
}
writer.WriteLine("one,1,{0},1|2|3", Guid.NewGuid());
writer.WriteLine("two,2,{0},4|5|6", Guid.NewGuid());
writer.WriteLine("\"this, has a comma\",2,{0},7|8|9", Guid.NewGuid());
writer.WriteLine("\"this has \"\"'s\",4,{0},10|11|12", Guid.NewGuid());
writer.Flush();
stream.Position = 0;
return stream;
}
public class CustomType
{
public int First { get; set; }
public int Second { get; set; }
public int Third { get; set; }
public override string ToString()
{
var serializer = new JavaScriptSerializer();
return serializer.Serialize(this);
}
}
public class CustomTypeTypeConverter : ITypeConverter
{
public string ConvertToString(TypeConverterOptions options, object value)
{
var obj = (CustomType)value;
return string.Format("{0}|{1}|{2}", obj.First, obj.Second, obj.Third);
}
public object ConvertFromString(TypeConverterOptions options, string text)
{
var values = ((string)text).Split('|');
var obj = new CustomType
{
First = int.Parse(values[0]),
Second = int.Parse(values[1]),
Third = int.Parse(values[2]),
};
return obj;
}
public bool CanConvertFrom(Type type)
{
throw new NotImplementedException();
}
public bool CanConvertTo(Type type)
{
throw new NotImplementedException();
}
}
public class CustomObject
{
public CustomType CustomTypeColumn { get; set; }
public Guid GuidColumn { get; set; }
public int IntColumn { get; set; }
public string StringColumn { get; set; }
public override string ToString()
{
var serializer = new JavaScriptSerializer();
return serializer.Serialize(this);
}
}
public class CustomObjectWithMapping
{
public CustomType CustomTypeColumn { get; set; }
public Guid GuidColumn { get; set; }
public int IntColumn { get; set; }
public string StringColumn { get; set; }
public string IgnoredColumn { get; set; }
//public override string ToString()
//{
// var serializer = new JavaScriptSerializer();
// return serializer.Serialize(this);
//}
}
public sealed class CustomObjectWithMappingMap : CsvClassMap<CustomObjectWithMapping>
{
public CustomObjectWithMappingMap()
{
Map(m => m.CustomTypeColumn).Name("Custom Type Column").Index(3).TypeConverter<CustomTypeTypeConverter>();
Map(m => m.GuidColumn).Name("Guid Column").Index(2);
Map(m => m.IntColumn).Name("Int Column").Index(1);
Map(m => m.StringColumn).Name("String Column").Index(0);
}
}
}
}
Can anyone point me to what I might be missing or doing wrong?
If you have a DataTable you can convert it to a Comma Separated Value list of strings like this...
/// <summary>
/// Creates a comma separated value string from a datatable.
/// </summary>
public static string ToCSV(DataTable table)
{
StringBuilder csv = new StringBuilder();
for(int i = 0; i < table.Columns.Count ;i++) // process the column headers
{
if (i > 0)
csv.Append(",");
csv.Append(_FormatToCSVField(table.Columns[i].ColumnName));
}
if (table.Columns.Count > 0)
csv.Append("\r\n");
for (int i = 0; i < table.Rows.Count; i++) // process the row data
{
for (int j = 0; j < table.Columns.Count; j++) // process each field in the data row.
{
if (j > 0)
csv.Append(",");
csv.Append(_FormatToCSVField(table.Rows[i][j].ToString()));
}
csv.Append("\r\n");
}
return csv.ToString();
}
private static string _FormatToCSVField(string unformattedField)
{
return "\"" + unformattedField.Replace("\"", "\"\"") + "\"";
}
Or if you didn't have a DataTable; take take your created comma separated value (CSV) list of string "row1 column 1, row1 column2, row1 column3, \r\n, row2, colum1... etc..."
and save it to a CSV File, like this...
//Your CSV String
string WhatToWrite = "row1 column 1, row1 column2, row1 column3, \r\n";
//Convert your CSV String to byte[]
byte[] PutWhatToWriteIntoBytes = Encoding.GetEncoding("iso-8859-1").GetBytes(WhatToWrite);
//Write the byte[] to CSV readable by excel
string filename = "WhatYouWantToCallYourFile" + ".csv";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", filename.ToString());
Response.Clear();
Response.BinaryWrite(PutWhatToWriteIntoBytes);
Response.End();
Its really hard to follow all your code. What exactly is it that you are trying to write to a CSV...Get that; check if it is good. then write to the file. determine if you are writing an empty string, or if the writing is losing the string
Flushing the stream writer worked for me if you still want to use the CSV Helper

get missing attributes in XML from XmlSerializer

how I can check if an attribute or an element is missing in my xml, when I deserialize an Object from Xml?
XmlSerializer fill missing values with their defaults, but how I can know whether it is the default value or it's missing in the Xml?
I have to know this, because if I publish a new version of my program and have added values to my objects, I want to show a prompt with new (missing) values to the user. He have to know the circumstances.
[Serializable]
public class Dummy
{
public int MyInteger { get; set; }
public string MyString { get; set; }
public double MyDouble { get; set; }
public bool MyBool { get; set; }
public Dummy()
{
//Missing values in the xml would filled up with these values
MyInteger = default(int);
MyString = default(string);
MyDouble = default(double);
MyBool = default(bool);
}
}
class Program
{
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(Dummy));
Dummy dummy = new Dummy(){ MyInteger = 1, MyBool = false, MyDouble = 3.4, MyString="dummy"};
StringBuilder sb = new StringBuilder();
using(StringWriter writer = new StringWriter(sb))
serializer.Serialize(writer, dummy);
/*sb contains:
* <?xml version="1.0" encoding="utf-16"?>
* <Dummy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
* <MyInteger>1</MyInteger>
* <MyString>dummy</MyString>
* <MyDouble>3.4</MyDouble>
* <MyBool>false</MyBool>
* </Dummy>
*/
//xml without MyDouble
string xml = #" <Dummy>
<MyInteger>1</MyInteger>
<MyString>dummy</MyString>
<MyBool>false</MyBool>
</Dummy>";
Dummy readDummy;
using (StringReader reader = new StringReader(xml))
readDummy = (Dummy)serializer.Deserialize(reader);
/*readDummy contains:
* MyInteger = 1,
* MyString = "dummy",
* MyDouble = 0,
* MyBool = false
*/
}
}
Update
Thank you Yeldar Kurmangaliyev for the Schema-Validation.
My current Problem is that the exception which was thrown by the Schema-Validator let me access only MyBool and not the missing value MyDouble.
The Exception-Message contains the name of the property MyDouble, but should I extract the property name from the Exception-Message? It feels very dirty.
Here is the updated code:
[Serializable]
public class Dummy
{
public int MyInteger { get; set; }
public string MyString { get; set; }
public double MyDouble { get; set; }
public bool MyBool { get; set; }
public Dummy()
{
//Missing values in the xml would filled up with these values
MyInteger = default(int);
MyString = default(string);
MyDouble = default(double);
MyBool = default(bool);
}
}
class Program
{
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(Dummy));
string xml = #" <Dummy>
<MyInteger>1</MyInteger>
<MyString>dummy</MyString>
<MyBool>false</MyBool>
</Dummy>";
Dummy readDummy;
XmlReaderSettings settings = new XmlReaderSettings() { ValidationType = ValidationType.Schema };
settings.Schemas.Add(GetXmlSchemas(typeof(Dummy)).First());
settings.ValidationEventHandler += (s, e) =>
{
//I got an exception with the sender "MyBool". How I can reach the variable "MyDouble" which is missing?
};
using (StringReader reader = new StringReader(xml))
using (XmlReader xmlReader = XmlReader.Create(reader, settings))
readDummy = (Dummy)serializer.Deserialize(xmlReader);
}
public static XmlSchemas GetXmlSchemas(Type type)
{
var schemas = new XmlSchemas();
var exporter = new XmlSchemaExporter(schemas);
var mapping = new XmlReflectionImporter().ImportTypeMapping(type);
exporter.ExportTypeMapping(mapping);
return schemas;
}
}
You can use XmlReaderSettings class for initializing and using XmlReader over a StringReader. However, you will need an XSD schema.
That's a proper way to validate XML on deserializing.
Take a look at XmlReaderSettings. Maybe, you will find an easier way to do this :)
string xml = #" <Dummy>
<MyInteger>1</MyInteger>
<MyString>dummy</MyString>
<MyBool>false</MyBool>
</Dummy>";
Dummy readDummy;
XmlSchemaSet schemas = null; // here is your schema
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add(schemas);
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += (s, e) =>
{
throw e.Exception; // Here you go
};
using (StringReader reader = new StringReader(xml))
using (XmlReader xmlReader = XmlReader.Create(reader, settings))
readDummy = (Dummy)serializer.Deserialize(xmlReader);

Serialization Fail on list of lists using DataContractSerializer

I have some class that has a property of type List<object> I need to serialize that class to XML file using DataContractSerializer.
The serialization fails on ArgumentException when the object is a List<T>/IEnumerator<T>exception message:
Invalid name character in
'System.Collections.Generic.List`1[[MyProj.Result, MyProj,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
Here is the code sample that fails
The Class that takes the List<object>
[DataContract(IsReference = true)]
public class RecoveryMethodData
{
[DataMember]
public List<object> Parameters { get; set; }
public RecoveryMethodData()
{
Parameters = new List<object>();
}
public static void SerializeToFile(RecoveryMethodData recoveryMethodData, string fileName)
{
var encoding = Encoding.UTF8;
using (var fileWriter = new XmlTextWriter(fileName, encoding))
{
fileWriter.Formatting = Formatting.Indented;
// use SharedTypeResolver for deserializing assistance.
var serializer = new DataContractSerializer(typeof(RecoveryMethodData), null, int.MaxValue, false, true, null, new SharedTypeResolver());
serializer.WriteObject(fileWriter, recoveryMethodData);
}
}
}
Here is the usage:
private void TestSerialization()
{
var methodData = new RecoveryMethodData();
var result = new Result() {Message = "wow", Pass = true, FileName = "somefile "};
methodData.Parameters.Add(result);
methodData.Parameters.Add(true);
var list1 = new List<Result>();
list1.Add(new Result(){FileName = "in list1", Message = "in l 1"});
list1.Add(new Result(){FileName = "in list2", Message = "in l 2"});
methodData.Parameters.Add(list1);
RecoveryMethodData.SerializeToFile(methodData,#"C:\serialization_result.xml");
}
public class Result
{
public string Message { get; set; }
public string FileName { get; set; }
}
If I do not add list1 into the methodData.Parameters there is no problem serializing the methodDatad object.
One big limitation is that I can't know in advance which kind of objects will be added to the Parameters property (that is why it is a list of objects)
In order to DataContractSerializer to serialize an object, it shall know the types of all datamembers. In your case, you do not define a specific type but an object type. Try changing the definition of
public List<object> Parameters { get; set; }
to something like:
public List<IMyObject> Parameters { get; set; }
Note that, all of your objects which you are trying to add to the parameters list shall inherit IMyObject interface.
Update: I refactored your code up to some point (still in a bad shape) and it seems working, please have a try;
public class Tester
{
public Tester()
{
this.TestSerialization();
}
public void SerializeToFile(RecoveryMethodData recoveryMetaData,string fileName)
{
var encoding = Encoding.UTF8;
using (var fileWriter = new XmlTextWriter(fileName, encoding))
{
fileWriter.Formatting = Formatting.Indented;
// use SharedTypeResolver for deserializing assistance.
var serializer = new DataContractSerializer(typeof(RecoveryMethodData),new List<Type>(){typeof(bool),typeof(Result),typeof(List<Result>)});
serializer.WriteObject(fileWriter,recoveryMetaData);
}
}
private void TestSerialization()
{
var methodData = new RecoveryMethodData();
var result = new Result() { Message = "wow", Pass = true, FileName = "somefile " };
methodData.Add(result);
methodData.Add(true);
var list1 = new List<Result>();
list1.Add(new Result() { FileName = "in list1", Message = "in l 1" });
list1.Add(new Result() { FileName = "in list2", Message = "in l 2" });
methodData.Add(list1);
SerializeToFile(methodData, #"C:\serialization_result.xml");
}
}
public class Result
{
public string Message { get; set; }
public string FileName { get; set; }
public bool Pass { get; set; }
}
public class RecoveryMethodData : List<object>
{
}

How to decode a JSON string using C#?

I'm looking for an example code/lib to decode a JSON string using C#.
To encode I can do this:
var data = new Dictionary<string,string>();
data.Add("..", "...");
var json_encoded = new JavaScriptSerializer().Serialize(data);
but how do I decode?
var json_decoded = ??
You can do this:
var data = new Dictionary<string, string>();
data.Add("foo", "baa");
JavaScriptSerializer ser = new JavaScriptSerializer();
var JSONString = ser.Serialize(data); //JSON encoded
var JSONObj = ser.Deserialize<Dictionary<string, string>>(JSONString); //JSON decoded
Console.Write(JSONObj["foo"]); //prints: baa
This will take JSON and convert it to a strongly typed class of which you specify (T)
public static T Deserialize<T>(string json)
{
var obj = Activator.CreateInstance<T>();
using(var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serializer = new DataContractJsonSerializer(obj.GetType());
obj = (T) serializer.ReadObject(ms);
return obj;
}
}
This will take a class and serialize it as JSON
public static string Serialize<T>(T obj)
{
var serializer = new DataContractJsonSerializer(obj.GetType());
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.Default.GetString(ms.ToArray());
}
}
Note: In the first example you will need to have a backing class to specify what type T is. So if you told it that T is of type User you would need to have this specified somewhere:
public class User
{
public string Username { get; set; }
public string Firstname { get; set; }
}

Categories

Resources