I'm just looking for some advice from someone more experienced than me really (wont be hard).
The following code...
XmlSerializer serializer = new XmlSerializer(typeof(Installation));
using (var sw = new StringWriter()) {
using (var xw = XmlWriter.Create(sw)) {
serializer.Serialize(xw, Installation);
}
xmlResult = sw.ToString();
}
has the following report in the code analysis...
CA2202 Do not dispose objects multiple times Object 'sw' can be
disposed more than once in method
'Views_Commissioning_installationSubsidyForm.SaveInstall(string)'. To
avoid generating a System.ObjectDisposedException you should not call
Dispose more than one time on an object.: Lines:
766 nc1_DealerPortal installationSubsidyForm.aspx.cs 766
Can anyone explain how I'm disposing of 'sw' more than once? What am I doing wrong here?
StringWriter will be disposed by the XmlWriter, so by having 2 using statements it will get disposed twice change you code as below:
XmlSerializer serializer = new XmlSerializer(typeof(Installation));
var sw = new StringWriter())
using (var xw = XmlWriter.Create(sw))
{
serializer.Serialize(xw, Installation);
xmlResult = sw.ToString();
}
Related
I have a strange issue with my XmlDocument class.
I write some XML file with it, which works great.
And I have Save() method:
public void Save()
{
var xwSettings = new XmlWriterSettings
{
Encoding = new UTF8Encoding(false),
Indent = true,
IndentChars = "\t"
};
using (XmlWriter xw = XmlWriter.Create(new FileStream(this.FilePath, FileMode.Create), xwSettings))
{
XmlDocument.WriteTo(xw);
}
}
Like everyone sees, I'm using "using" which should give the xml free :)
But if I try to read this file directly after calling Save() I get the exception:
The process can not access the file "___.xml", because it's already in use by another process.
Can someone explain that to me and give me a solution for it?
Kind regards
You are not disposing your file stream. Try changing your code like this.
using (var xmlStream = new FileStream(this.FilePath, FileMode.Create))
{
using (XmlWriter xw = XmlWriter.Create(xmlStream, xwSettings))
{
var xDoc = new XmlDocument();
xDoc.WriteTo(xw);
}
}
I'm currently trying to serialize a class into XML to be posted to php web service.
Whenever I did the normal serialization using XMLSerializer, XML declaration is always appear in the first line of the XML document (similar as to <?xml ....?>). I tested the XML and unable to get it working because the endpoint does not accept XML declaration and I can't do anything about it.
I'm unfamiliar with XML Serialization in C# to be honest.
Therefore, I used XMLWriter to do this as below :-
private string SerializeClassToString(GetRiskReport value)
{
var emptyNS = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var ser = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using (var stream = new StringWriter())
{
using (var writer = XmlWriter.Create(stream, settings))
{
ser.Serialize(writer, value, emptyNS);
return stream.ToString();
}
}
}
Result for the Namespace is
<GetRiskReport FCRA=\"false\" ReturnResultsOnly=\"false\" Monitoring=\"false\">
... and I'm able to omit the XML Declaration, however I'm being introduced with 2 new problem.
I got \r\n for new line and I have escaped double quote such as ReturnResultsOnly=\"false\" Monitoring=\"false\" which is also unable processed by the endpoint.
I would like to ask is that does anyone can give me an idea on how to change the XmlWriterSetting to omit XML Declaration, avoid \r\n and also avoid escaped double quotes \"
Thanks for your advice in advance.
Simon
Try with following settings
settings.NewLineHandling = NewLineHandling.None;
settings.CheckCharacters = false;
private void SerializeClassToString(GetRiskReport value)
{
var emptyNS = new XmlSerializerNamespaces(new[]{XmlQualifiedName.Empty});
var ser = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
string path = 'your_file_path_here'
if (File.Exists(path)) File.Delete(path);
FileStream stream = File.Create(path);
using (var writer = XmlWriter.Create(stream, settings))
{
ser.Serialize(writer, value, emptyNS);
return;
}
}
There was no way to avoid ms bug or thier intensional specification about xmlserializing.It's easier and faster to use filestream object.
This question already has answers here:
CA2202, how to solve this case
(12 answers)
Closed 8 years ago.
When I wrap IDisposable objects in usings like this I get the code analysis warning Code analysis error CA2202: Do not dispose objects multiple times, http://msdn.microsoft.com/en-us/library/ms182334.aspx
using (StringWriter textWriter = new StringWriter())
{
using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.Serialize(xmlWriter, value);
}
return textWriter.ToString();
}
This however doesn't return any errors
using (StringWriter textWriter = new StringWriter())
{
XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings);
serializer.Serialize(xmlWriter, value);
return textWriter.ToString();
}
Also when doing this the xmlWriter dispose will trigger CA2202
StringWriter textWriter = null;
XmlWriter xmlWriter = null;
try
{
textWriter = new StringWriter();
xmlWriter = XmlWriter.Create(textWriter, settings);
serializer.Serialize(xmlWriter, value);
return textWriter.ToString();
}
finally
{
if (textWriter != null)
textWriter.Dispose();
// The xmlWriter dispose will trigger CA2202
if (xmlWriter != null)
xmlWriter.Dispose();
}
Which pattern shall I use? It seems strange to not dispose disposable elements.
Ath the end of the inner using statement XmlWriter is being disposed. When this happens the textWriter element is also disposed because XmlWriter internally disposes object it wraps.
Since Dispose should be idempotent (repeatable calls does not have side effects) I wouldn't worry about this warning.
A simple google find this answer: https://stackoverflow.com/a/8096857/2027232
The problem isn't because of the nested usings. They're fine and generally recommended. The problem here is that XmlReader will dispose the TextReader if you pass an XmlReaderSettings with CloseInput == true, but the CA2202 rule isn't smart enough that your code won't go down that branch. Keep your nested usings, and suppress the CA2202 violation as a false positive. If you want to be extra careful, use an XmlReaderSettings with CloseInput set to false, but that is the default value, so it's not strictly necessary.
BTW, there are similar CA2202 problem scenarios for a variety of stream and reader types. Unfortunately, they're not all the same as this one, so the best case handling can differ depending on which type is cause the problem.
I have become confused due to all of the samples using DataContractSerializer only handling one single object. I have a collection of objects, let's call it List<Ticket> tickets. I can get a the DataContractSerializer to write each object using a foreach (var ticket in tickets), but afterward I need to run a transform on the XML in order to be sure it is properly formatted. However, when using the Transform method of a XmlCompiledTransform I continue receiving the error "Unexpected end of file while parsing Name has occurred. Line 447, position 28."
Below is my code, all constructive criticism is welcome.
using (var ms = new MemoryStream())
{
using (var writer = XmlWriter.Create(ms, settings))
{
var ser = new DataContractSerializer(tickets.GetType());
writer.WriteStartDocument(true);
writer.WriteStartElement("Tickets");
foreach (var ticket in tickets)
{
ser.WriteObject(writer, ticket);
}
writer.WriteEndElement();
writer.WriteEndDocument();
ms.Position = 0;
var xslt = new XslCompiledTransform();
xslt.Load(xsltFp);
using (var output = new FileStream(xmlFp, FileMode.Create))
{
xslt.Transform(XmlReader.Create(ms), null, output);
output.Position = 0;
}
}
}
I figured it out. At the end of the foreach loop, I needed to call writer.Flush();. This effectively flushes the stream buffer before we start writing another object.
I'm trying to serialize a very large IEnumerable<MyObject> using an XmlSerializer without keeping all the objects in memory.
The IEnumerable<MyObject> is actually lazy..
I'm looking for a streaming solution that will:
Take an object from the IEnumerable<MyObject>
Serialize it to the underlying stream using the standard serialization (I don't want to handcraft the XML here!)
Discard the in memory data and move to the next
I'm trying with this code:
using (var writer = new StreamWriter(filePath))
{
var xmlSerializer = new XmlSerializer(typeof(MyObject));
foreach (var myObject in myObjectsIEnumerable)
{
xmlSerializer.Serialize(writer, myObject);
}
}
but I'm getting multiple XML headers and I cannot specify a root tag <MyObjects> so my XML is invalid.
Any idea?
Thanks
The XmlWriter class is a fast streaming API for XML generation. It is rather low-level, MSDN has an article on instantiating a validating XmlWriter using XmlWriter.Create().
Edit: link fixed. Here is sample code from the article:
async Task TestWriter(Stream stream)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Async = true;
using (XmlWriter writer = XmlWriter.Create(stream, settings)) {
await writer.WriteStartElementAsync("pf", "root", "http://ns");
await writer.WriteStartElementAsync(null, "sub", null);
await writer.WriteAttributeStringAsync(null, "att", null, "val");
await writer.WriteStringAsync("text");
await writer.WriteEndElementAsync();
await writer.WriteCommentAsync("cValue");
await writer.WriteCDataAsync("cdata value");
await writer.WriteEndElementAsync();
await writer.FlushAsync();
}
}
Here's what I use:
using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.Text;
using System.IO;
namespace Utils
{
public class XMLSerializer
{
public static Byte[] StringToUTF8ByteArray(String xmlString)
{
return new UTF8Encoding().GetBytes(xmlString);
}
public static String SerializeToXML<T>(T objectToSerialize)
{
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings =
new XmlWriterSettings {Encoding = Encoding.UTF8, Indent = true};
using (XmlWriter xmlWriter = XmlWriter.Create(sb, settings))
{
if (xmlWriter != null)
{
new XmlSerializer(typeof(T)).Serialize(xmlWriter, objectToSerialize);
}
}
return sb.ToString();
}
public static void DeserializeFromXML<T>(string xmlString, out T deserializedObject) where T : class
{
XmlSerializer xs = new XmlSerializer(typeof (T));
using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(xmlString)))
{
deserializedObject = xs.Deserialize(memoryStream) as T;
}
}
}
}
Then just call:
string xml = Utils.SerializeToXML(myObjectsIEnumerable);
I haven't tried it with, for example, an IEnumerable that fetches objects one at a time remotely, or any other weird use cases, but it works perfectly for List<T> and other collections that are in memory.
EDIT: Based on your comments in response to this, you could use XmlDocument.LoadXml to load the resulting XML string into an XmlDocument, save the first one to a file, and use that as your master XML file. For each item in the IEnumerable, use LoadXml again to create a new in-memory XmlDocument, grab the nodes you want, append them to the master document, and save it again, getting rid of the new one.
After you're finished, there may be a way to wrap all of the nodes in your root tag. You could also use XSL and XslCompiledTransform to write another XML file with the objects properly wrapped in the root tag.
You can do this by implementing the IXmlSerializable interface on the large class. The implementation of the WriteXml method can write the start tag, then simply loop over the IEnumerable<MyObject> and serialize each MyObject to the same XmlWriter, one at a time.
In this implementation, there won't be any in-memory data to get rid of (past what the garbage collector will collect).