I just can't find a simple answer to this simple question I have from Dr Google. I have the following serializing function which I put in a static module. It is called many times by my application to serialize lots of XML files. Will this cause memory to over grow? (Ignore the text write part of the code)
public static void SerializeToXML<T>(String inFilename,T t)
{
XmlSerializer serializer = new XmlSerializer(t.GetType());
string FullName = inFilename;
TextWriter textWriter = new StreamWriter(FullName);
serializer.Serialize(textWriter, t);
textWriter.Close();
textWriter.Dispose();
}
Will this cause memory to over grow?
No. There will be no memory over growing. static will let you call SerializeToXML method without create a new instance of the class. Not anything else.
So if you're calling this method many times, You even shrinking the memory usage with a static method.
Though you wrote to ignore the text write part, You should use using statement for unmanaged resources:
public static void SerializeToXML<T>(String inFilename,T t)
{
XmlSerializer serializer = new XmlSerializer(t.GetType());
string FullName = inFilename;
using (TextWriter textWriter = new StreamWriter(FullName))
{
serializer.Serialize(textWriter, t);
textWriter.Close();
}
}
Related
I need to change the behaviour of XmlWriter for my project to change the way that empty xml elements are serialised. Currently, my code uses XmlWriter and XmlSerializer like so:
public string Serialize(object o)
{
XmlWriterSettings settings = new XmlWriterSettings();
...
StringWriter stringWriter = new StringWriter();
XmlWriter xmlWriter = XmlWriter.Create(stringWriter, settings);
XmlSerializer serializer = new XmlSerializer(o.GetType());
serializer.Serialize(xmlWriter, o);
return stringWriter.ToString();
}
When serializing my xml, empty elements are being serialized to <emptyElement/>, but I need the xml to serialize empty elements to <emptyElement></emptyElement>. The best solution I've found for this was stated in this a Microsoft forum years ago: https://social.msdn.microsoft.com/Forums/en-US/979315cf-6727-4979-a554-316218ab8b24/xml-serialize-empty-elements?forum=xmlandnetfx
The faster and safer way of doing this is by writing your own subclass of the XmlWriter and give it to XmlSerializer.
YourXmlWriter would aggregate standard one and would translate all WriteEndElement() calls to WriteFullEndElement() calls.
I've tried writing my own subclass of XmlWriter, overriding the two methods I need to override:
public abstract class CustomXmlWriter : XmlWriter
{
public override void WriteEndElement()
{
WriteFullEndElement();
}
public override Task WriteEndElementAsync()
{
return WriteFullEndElementAsync();
}
}
In theory, I believe this should work. However, when trying to use the code, I'm coming up against a brick wall around XmlWriter.Create. I cannot cast the resulting XmlWriter to my CustomXmlWriter for obvious reasons, and I can't override the method as it's a static method.
How am I meant to deal with the static Create method? The only other way I can think of doing this is to scrap the idea of my own CustomXmlWriter, and to simply manipulate the string at the end of my method, but this feels very wrong. I don't know if what I'm trying to achieve is possible, or if there is a simple setting somewhere that I cannot seem to find anywhere.
Try following Regex as a temporary fix. The variable input can be the entire xml string and it will replace every occurrence. :
static void Main(string[] args)
{
string input = "<emptyElement/>";
string patternNullTag = #"\<(?'tagname'\w+)/\>";
string output = Regex.Replace(input, patternNullTag, ReplaceNullElement);
}
static string ReplaceNullElement(Match match)
{
string tagname = match.Value.Replace("<", "").Replace("/>", "");
string newElement = "<" + tagname + ">" + "</" + tagname + ">";
return newElement;
}
Background: I have been tasked with serialising C# objects into xml string. The xml string is then passed to webservice and are written to disk in xml file. The task of serialising needs to occur within 5 mins timeframe that the process gets. The consumer webservice only accepts string as xml.
I have been researching into various ways of creating xml string from xml serialiser, xmlwriter, xdocument, stringbuilder to write xml string, object to json to xml, linq to xml but I needed to know if anyone had experience of doing something similar. Main aim is to have a high performant xml string that is not so verbose and error prone like creating xml in string.
My object is Called Employee and has 18 string/date properties. The objects are created in memory and we get around 4000k objects in total once the process boots up. The process runs for 1 hour a day, loads data from data file and creates person objects. A number of functions are performed on the objects. Once objects are ready, they need to be serialised and data in xml is sent to webservice and is writren to xml file. So in short, these objects need to be serialised and saved to disk and sent to webservice.
Does anyone recommend any high performant yet easy to. Maintain approach? Apologies for not positing any code because I can create a class and add xml serialiser etc code but i dont think it will add any value at the moment as currently I am looking for past experiences plus i want to ensure i dont go on a wild goose chase and want to implement with right solution.
I have tried following serialiser code but it takes 10+ mins to serialise all 4000k objects.
public static bool Serialize<T>(T value, ref string serializeXml)
{
if (value == null)
{
return false;
}
try
{
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
StringWriter stringWriter = new StringWriter();
XmlWriter writer = XmlWriter.Create(stringWriter);
xmlserializer.Serialize(writer, value);
serializeXml = stringWriter.ToString();
writer.Close();
return true;
}
catch (Exception ex)
{
return false;
}
}
I have also tried caching serialiser but doesn't give any performance improvements
According to your requirement, speed is the most demanding part. We need to write a benchmark here. As mentioned in the comment, besides XmlSerializer, we can use DataContractSerializer for our purpose. There are several Q&A related to the difference between these two, e.g.:
DataContractSerializer vs XmlSerializer: Pros and Cons of each serializer
Linq to Xml VS XmlSerializer VS DataContractSerializer
Difference between DataContractSerializer vs XmlSerializer
Another options are manually write your XML either using StringBuilder or XmlWriter. Although in the requirement you mentioned:
Main aim is to have a high performant xml string that is not so verbose and error prone like creating xml in string
these three serializer is added for comparison. Of course, in the case of StringBuilder, the text must be escaped. Here, I used System.Security.SecurityElement.Escape. The object to be serialized looks like:
//Simple POCO with 11 String properties, 7 DateTime properties
[DataContractAttribute()]
public class Employee
{
[DataMember()]
public string FirstName { set; get; }
[DataMember()]
public string LastName { set; get; }
//...omitted for clarity
[DataMember()]
public DateTime Date03 { set; get; }
[DataMember()]
public DateTime Date04 { set; get; }
}
and all the properties have value (not null), assigned prior to calling the serializer. The serializer codes looks like:
//Serialize using XmlSerializer
public static bool Serialize<T>(T value, ref StringBuilder sb)
{
if (value == null)
return false;
try
{
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
using (XmlWriter writer = XmlWriter.Create(sb))
{
xmlserializer.Serialize(writer, value);
writer.Close();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return false;
}
}
//Serialize using DataContractSerializer
public static bool SerializeDataContract<T>(T value, ref StringBuilder sb)
{
if (value == null)
return false;
try
{
DataContractSerializer xmlserializer = new DataContractSerializer(typeof(T));
using (XmlWriter writer = XmlWriter.Create(sb))
{
xmlserializer.WriteObject(writer, value);
writer.Close();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return false;
}
}
//Serialize using StringBuilder
public static bool SerializeStringBuilder(Employee obj, ref StringBuilder sb)
{
if (obj == null)
return false;
sb.Append(#"<?xml version=""1.0"" encoding=""utf-16""?>");
sb.Append("<Employee>");
sb.Append("<FirstName>");
sb.Append(SecurityElement.Escape(obj.FirstName));
sb.Append("</FirstName>");
//... Omitted for clarity
sb.Append("</Employee>");
return true;
}
//Serialize using XmlSerializer (manually add elements)
public static bool SerializeManual(Employee obj, ref StringBuilder sb)
{
if (obj == null)
return false;
try
{
using (var xtw = XmlWriter.Create(sb))
{
xtw.WriteStartDocument();
xtw.WriteStartElement("Employee");
xtw.WriteStartElement("FirstName");
xtw.WriteString(obj.FirstName);
xtw.WriteEndElement();
//...Omitted for clarity
xtw.WriteEndElement();
xtw.WriteEndDocument();
xtw.Close();
}
return true;
}
catch(Exception ex)
{
Console.WriteLine(ex);
return false;
}
}
In the benchmark, 4M Employee objects are given as the argument and XML is written to preallocated StringBuilder (parameter ref StringBuilder sb). For DataContractSerializer and Manual XmlWriter, benchmark with Parallel.Invoke (3 parallel tasks) also performed. Required processing time for each serializer:
//Simple POCO with 11 String properties, 7 DateTime properties
XmlSerializer =00:02:37.8151125 = 157 sec: 100% (reference)
DataContractSerializer=00:01:10.3384361 = 70 sec: 45% (3-Parallel: 47sec = 30%)
StringBuilder =00:01:22.5742122 = 82 sec: 52%
Manual XmlWriter =00:00:57.8436860 = 58 sec: 37% (3-Parallel: 40sec = 25%)
Environment: .Net Framework 4.5.2, Intel(R) Core(TM) i5-3337U # 1.80GHz 1.80GHz, Windows 10, 6.0GB Memory. I expect StringBuilder will be the fastest, but it wasn't. Perhaps, the bottleneck is in System.Security.SecurityElement.Escape().
The conclusion: DataContractSerializer is within the requirement, processing time is 30-45% compared to XmlSerializer. The results may differs depend on the environment, and you should make your own benchmark.
I'm just being stupid here...thought this would be simple but got befuddled with my various attempts to make this work and all my online searches yielded nothing.
The first function (see below) is one of several that specifically serialize one type of object to an xml file and it works fine. I'm trying to consolidate/refactor because I have 3 objects so I have 6 functions - 3 to read and 3 to write the objects. I want to generalize and then move my functions into my business objects layer. So when I try to generalize it, I need to pass in the object as an unknown type and then handle that. In the first function, the type is known and like I said that works. So the second function (below) shows my latest attempt to generalize but I'm not doing it right. I want to pass in the object and the file path...
private void ReadEmailConfigurationXML()
{
XmlSerializer serializer = new XmlSerializer(typeof(EmailConfiguration));
System.IO.StreamReader file = new System.IO.StreamReader(DataFilePath + "Data/EmailConfiguration.xml");
EmailConfig = (EmailConfiguration)serializer.Deserialize(file);
file.Close();
}
private void ReadXMLFile(ref Object obj, string fullPath)
{
XmlSerializer serializer = new XmlSerializer(typeof(obj));
System.IO.StreamReader file = new System.IO.StreamReader(fullPath);
obj = (typeof(obj))serializer.Deserialize(file);
file.Close();
}
Use generics to handle the different types:
private T ReadXMLFile<T>(string fullPath) {
XmlSerializer serializer = new XmlSerializer(typeof(T));
System.IO.StreamReader file = new System.IO.StreamReader(fullPath);
T obj = (T)serializer.Deserialize(file);
file.Close();
return obj;
}
Usage:
EmailConfiguration conf =
ReadXMLFile<EmailConfiguration>(DataFilePath + "Data/EmailConfiguration.xml");
I have been using the traditional way of serializing content with the following code
private void SaveToXml(IdentifiableEntity IE)
{
try
{
XmlSerializer serializer = new XmlSerializer(IE.GetType());
TextWriter textWriter = new StreamWriter(IE.FilePath);
serializer.Serialize(textWriter, IE);
textWriter.Close();
}
catch (Exception e )
{
Console.WriteLine("erreur : "+ e);
}
}
private T LoadFromXml<T>(string path)
{
XmlSerializer deserializer = new XmlSerializer(typeof(T));
TextReader textReader = new StreamReader(path);
T entity = (T)deserializer.Deserialize(textReader);
textReader.Close();
return entity;
}
Though this approach does the trick, i find it a bit annoying that all my properties have to be public, that i need to tag the properties sometimes [XmlAttribute|XmlElement| XmlIgnore] and that it doesn't deal with dictionaries.
My question is : Is there a better way of serializing objects in c#, a way that with less hassle, more modern and easy to use?
First of all, I would suggest to use "using" blocks in your code.(Sample code)
If my understanding is OK, you are looking for a fast way to build your model classes that you will use during your deserialize/serialize operations.
Every Xml file is different and I don't know any generic way to serialize / deserialize them. At one moment you have to know if there will be an attribute, or elements or if any element can be null etc.
Assuming that you already have a sample XML file with a few lines which gives you general view of how it will look like
I would suggest to use xsd (miracle tool)
xsd yourXMLFileName.xml
xsd yourXMLFileName.xsd \classes
This tool will generate you every time model classes for the XML file you want to work it.
Than you serialize and deserialize easily
To deserialize (assuming that you'll get a class named XXXX representing root node in your xml)
XmlSerializer ser = new XmlSerializer(typeof(XXXX));
XXXX yourVariable;
using (XmlReader reader = XmlReader.Create(#"C:\yyyyyy\yyyyyy\YourXmlFile.xml"))
{
yourVariable= (XXXX) ser.Deserialize(reader);
}
To serialize
var serializer = new XmlSerializer(typeof(XXXX));
using(var writer = new StreamWriter(#"C:\yyyyyy\yyyyyy\YourXmlFile.xml"))
{
serializer.Serialize(writer, yourVariable);
}
How is the LINQ to XML X-DOM from the System.Xml.Linq namespace internally implemented? (XNode, XElement, etc.)
Is it utilizing standard high-performing one-way XmlReader/XmlWriter from the other XML namespaces or something else?
The reason I'm asking is that I'm trying to figure out in which circumstances could or should be used as performance is always a concern.
Using Reflector (or, when that's no longer free, ILSpy :); no I'm not an employee - just spreading the word surreptitiously!) it appears all the load/save methods channel through to XmlReader and XmlWriter.
For example - XElement's implementation of Load(Stream, LoadOptions) does this:
public static XElement Load(Stream stream, LoadOptions options)
{
XmlReaderSettings xmlReaderSettings = XNode.GetXmlReaderSettings(options);
using (XmlReader reader = XmlReader.Create(stream, xmlReaderSettings))
{
return Load(reader, options);
}
}
And it's a similar story for all the other static methods - including Parse.
But then there is the XStreamingElement constructor - however I can't find any real usage of it outside of the XElement class itself. Looks like this could be an optimised type for loading that, as yet, isn't used by much.
Equally, the Save and WriteTo methods ultimately use an XmlWriter instance - e.g:
public void Save(string fileName, SaveOptions options)
{
XmlWriterSettings xmlWriterSettings = XNode.GetXmlWriterSettings(options);
using (XmlWriter writer = XmlWriter.Create(fileName, xmlWriterSettings))
{
this.Save(writer);
}
}
So at least from a performance point of view they started with the right types :)