Building an XML file iteratively with XmlWriter - c#

I want to be able to use XmlWriter (C#, .NET) to create an XML document with multiple calls to a method that generates XML and then a single call to a final method that closes everything off. When I try to call this method multiple times:
private void SiblingGenerator(List<XmlNode> XMLList, XmlWriter textWriter,
string newPath, FileInfo fi)
{
if (fi.Length == 0)
{
MessageBox.Show("file doesn't exist");
textWriter.WriteStartDocument();
textWriter.WriteStartElement("batch");
//...
}
// ...
}
...it returns an error saying that WriteStartDocument needs to be the first call.
It seems like the calls to the textWriter aren't actually being written because on each subsequent call the document starts over again.
Can anyone tell me why this is happening?

A XmlWriter is forward only and cannot be reused. You shouldn't call WriteStartDocument multiple times on the same instance of this class. Because it is an argument of your method it is the caller that must take care of handling the life-cycle of the writer.
using (var writer = XmlWriter.Create("foo.xml"))
{
SiblingGenerator(XMLList, writer, newPath, fi);
}
If you need to reuse the SiblingGenerator function multiple times then you might want to externalize the call of the WriteStartDocument method:
using (var writer = XmlWriter.Create("foo.xml"))
{
writer.WriteStartDocument();
SiblingGenerator(XMLList, writer, newPath, fi);
SiblingGenerator(XMLList, writer, newPath, fi);
...
writer.WriteEndDocument();
}

Any kind of "writer" object like TextWriter, XmlWriter, etc do some level of buffering as does the underlying stream which is entirely out of its control. In other words, you can't rely on the length of the underlying file to determine whether or not prior calls to the writer have been made.
But specifically speaking, there is a Flush method available on many of the classes in System.IO such as Stream and TextWriter that can be used to push the buffered contents to disk but this makes for pretty fragile code, in my opinion.
You should maintain some other kind of state to determine whether or not you have already written the start of the document.

There are several things that can keep that method from working. The XmlWriter might not write the code to the stream directly, the FileStream might not write the data to the file directly, and the FileInfo object caches it's information, so you would have to make it update itself to get information that is up to date.
Instead of using a FileInfo object to check for this, you could just use a boolean variable to keep track of whether it's the first item or not.
Alternatively, just write the start of the document before going into the loop that calls this method.

I would guess that something else is wrong, that code should work. You're probably reusing a XmlWriter. If you declare the XmlWriter locally in the method do you still get the error?

Related

why is TextWriter logging to file incomplete?

I am attempting to follow this solution here to mirror my Console output to a log file as well, however, i noticed that the output to file gets cut off, so the full console output is not completely outputted in the file. Why is that? Is TextWriter limited to certain amount of lines?
private TextWriter txtMirror = new StreamWriter("mirror.txt");
// Write text
private void Log(string strText)
{
Console.WriteLine(strText);
txtMirror.WriteLine(strText);
}
p.s. the reason im using this solution is because I have Console.Writeline in functions as well that i call in the main(). so if i was to use this solution instead, i would have to open a using statement everywhere i have a Console.WriteLine()...which seems redundant
You can use the AutoFlush property System_IO_StreamWriter_Flush
Flushing the stream will not flush its underlying encoder unless you explicitly call Flush or Close. Setting AutoFlush to true means that data will be flushed from the buffer to the stream after each write operation, but the encoder state will not be flushed.
By the way, if you are instantiating your logger class many times, you are going to have many StreamWriter objects. Make sure you dispose them as per documentation
This type implements the IDisposable interface. When you have finished using the type, you should dispose of it either directly or indirectly. To dispose of the type directly, call its Dispose method in a try/catch block. To dispose of it indirectly, use a language construct such as using (in C#) or Using (in Visual Basic). For more information, see the "Using an Object that Implements IDisposable" section in the IDisposable interface topic.
Disposing the objects, makes sure that flush is called and any buffered information is written to the underlying object.
Example:
// Write text
private void Log(string strText)
{
Console.WriteLine(strText);
using (StreamWriter txtMirror = new StreamWriter("mirror.txt")) {
txtMirror.WriteLine(strText);
}
}

XmlWriter - disposable

I am having trouble understanding the way XmlWriter works in C#. Take the following code as if it hypothetically was used somewhere.
StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = new UTF8Encoding(false);
settings.ConformanceLevel = ConformanceLevel.Document;
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(builder, settings);
// Do stuff
writer.Close();
Since XmlWriter is not used within an using statement, could this potentially result in an OutOfMemoryException due to it not being properly disposed?
Ultimately, the purpose of the Dispose() in this case is to allow the XmlWriter to assume ownership of whatever it is writing to - for example, if you create an XmlWriter over a Stream, calling Dispose() on the XmlWriter can (by default) flush the xml writer and then call Dispose() on the stream. This makes it easy to pass an XmlWriter to APIs without also having to pass them a chain of other objects they need to dispose when they're done (it could, for example, be an XmlWriter talking to a CompressionStream talking to a SslStream talking to a NetworkStream, etc).
In the general case, the purpose of the Dispose() on the final end thing is to close the underlying resource (which could be a file, a socket, a pipe, etc)
In this specific case, you're talking to a StringBuilder. The Dispose() here is basically a no-op, as there is no external resource. It'll just be collected by the GC either way, at some point in the future. As such, no: there is no memory leak problem here; the GC can see what you're doing.
So: in this case it won't make a functional difference, but: it is good practice to get into the habit of calling Dispose() (usually via using) when that is part of the API, as in many cases this is really, really important.
Its good to have using block, where it ensures calling the Dispose on any object that implements IDisposable.
using (XmlWriter writer = XmlWriter.Create(builder, settings))
{
//do stuff
}
The Dispose method for XmlWriter looks like-
protected virtual void Dispose(bool disposing)
{
if (this.WriteState != WriteState.Closed)
{
try
{
this.Close();
}
catch
{
}
}
}
It could potentially cause memory issues if there would be an exception in
// Do stuff
In this scenario, the Close method would not be executed.
Using statement is a syntactic sugar around try-finally blocks. It calls Dispose in finally block even there was an exception
XmlWriter.Dispose calls Close method behind the scene
according to c# docs
The using statement ensures that Dispose is called even if an exception occurs within the using block. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):
{
var font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
and close function is do the same thing
This method calls Dispose, specifying true to release all resources. You do not have to specifically call the Close method. Instead, ensure that every Stream object is properly disposed. You can declare Stream objects within a using block (or Using block in Visual Basic) to ensure that the stream and all of its resources are disposed, or you can explicitly call the Dispose method.

Using the using-statement with an already instantiated object

I have a very simple logging mechanism in my application which periodically writes a line to a file (a logging library would be overkill for my needs) which looks something like this:
private string logfile = #"C:\whatever.log";
public void WriteLine(string line)
{
using(FileStream fs = File.Open(logfile, FileMode.Append))
{
// Log Stuff
}
}
So any time I call that method, a new FileStream is created and disposed after logging is finished. So I considered using an already instantiated object to prevent the continuous creation of new objects:
private string logfile = #"C:\whatever.log";
private FileStream myStream = File.Open(logfile, FileMode.Append);
public void WriteLine(string line)
{
using(myStream)
{
// Log Stuff
}
}
However, the MSDN reference discourages this (last example), due to scope issues.
What does one do in that case? Is the overhead in my first example negligible?
The using statement doesn't do anything else than calling the Dispose() method of the object.
So considering your second example, after the first call to the WriteLine(string) method the filestream is disposed. So any other call, after the first one, to this Method will result in an exception.
Using the File.AppendText() method like Chris had suggested in the comment would be a way to go. But keep in mind, that using this or any other File... method will also open a stream and close and dispose it afterwards.
It will just result in less code.
The second approach does also dispose the stream every time you call WriteLine since you are also using the using-statement. MSDN discourages from this approach because the variable myStream does still "exist" even if the object is disposed. So that is more error-prone.
If you often need to use this method you should cosider to use the using "outside" or use a try-catch-finally:
var myLogger = new MyLogger();
try
{
// here is your app which calls myLogger.WriteLine(...) often
}
catch(Exception ex)
{
// log it
}
finally
{
myLogger.Dispose(); // myLogger is your Log class, dispose should call myStream.Dispose();
}
The overhead might not be negligible, but that might be beside the point.
When you are using using, the creation, acquisition of resource and the disposing of the used resources is nicely scoped. You know where it starts, where it's used, and where it's finished.
If you go for the second scenario, you know where it starts (it's when the containing class is created), but after that, you have no platform-guaranteed way to control where it's used, and where (if at all) the resources are disposed.
You can do this yourself if this is critical code, and your containing class implements the IDisposable pattern properly, but this can be tricky and not for the faint of heart :)
However, you stated in the question "a logging library would be overkill for my needs", so I think you are fine with the minimal overhead. IMHO, you should be fine with one of the ready-made File methods, like File.AppendAllText:
public void WriteLine(string line)
{
//add an enter to the end
line += Environment.NewLine;
File.AppendAllText(logfile, line);
}
or File.AppendAllLines:
public void WriteLine(string line)
{
File.AppendAllLines(logfile, new []{line});
}

Sending console output to multiple writers

I have an application that needs to redirect the output to Console.Write and Console.Writeline to somewhere else.
To elaborate further, my code starts a process at certain intervals. This proces is not written by me, or the company I work for, and I do not have source-code access.
I capture that output from that process because I need to know when I check up on the logs later if something has failed, and stuff like that, so I've redirected the output to a text-file like this:
String filename = "the-log-file-with-a-datetime-stamp.txt";
FileStream filestream = new FileStream(filename, FileMode.Create);
streamwriter = new StreamWriter(filestream);
streamwriter.AutoFlush = true;
Console.SetOut(streamwriter);
Console.SetError(streamwriter);
That works fine, sort of, but I would like to be able to redirect to more than one place, like I know redirect to a streamwriter.
Lets say for arguments sake I want it to redirect to the streamwriter AND write the line in a table in a database, and also show it in console, should someone have manually run the program.
How would I go about that?
Can I implement my own TextWriter and handle it there, and if so, how?
Please let me know if I can clarify further.
The simplest way would be to do as you suggested and write your own TextWriter-derived class. You could then use it to write to multiple other TextWriter instances.
Documentation for TextWriter says, in its "Notes to inheritors":
A derived class must minimally implement the TextWriter.Write(Char) method to make a useful instance of TextWriter.
So your derived TextWriter class would look something like:
public class MultiTextWriter: TextWriter
{
private List<TextWriter> _writers = new List<TextWriter>();
public void AddWriter(TextWriter writer)
{
_writers.Add(writer);
}
public override void Write(char ch)
{
foreach (var writer in _writers)
{
try
{
writer.Write(ch);
}
catch (ObjectDisposedException)
{
// handle exception here
}
catch (IOException)
{
// handle exception here
}
}
}
}
And to use it...
MultiTextWriter Writer = new MultiTextWriter();
StreamWriter sw1 = new StreamWriter(...);
StreamWriter sw2 = new StreamWriter(...);
Writer.AddWriter(sw1);
Writer.AddWriter(sw2);
Console.SetOut(Writer);
Console.SetError(Writer);
Note that my class and examples are pretty minimal. In particular, you'll need to add code that closes the individual streams. And you'll have to decide how you want to handle write errors.
You can override other TextWriter write methods if you want to potentially get better performance, but it's quite possible that just overriding the Write(char) method will perform well enough. It will depend on how much data is going out and how many different destinations.
Redirect the output to a MemoryStream, and monitor it (cycle+sleep). Upon arrival of data, send it to wherever you need.
You can create a CompositeStream class derived from the Stream class which will support only writing. And in overridden Write method you can write to any number of underlying streams.
Example of solution: Write your own class that derives from TextWriter which will echo the output to a StreamWriter and your other place.

Optional output file in console application - make StreamWriter global

I'm writing a console application which is looking up information about SSIS packages in SQL Server. I have it working and writing to a .csv file. I just added in the ability to pass command line switches for servername, foldername and outputfile. If an output file is not specified, I'd just like to output to the console, which I'm already doing.
The way I've handled the file writing seems awkward, and is probably wrong.
In my main method I create a StreamWriter. I need to write the entire output of the program to this file. I explore folders under my specified folder by recursively calling a function.
I pass the StreamWriter object along in all calls - it is a parameter in functions which don't use it, so it can be passed to the one that does. It seems like I should be able to make it a global variable, but I see that c# doesn't have globals and "if you are using a global, you are probably doing it wrong".
I'd planned on revisiting this issue eventually after plugging away at this little utility for a while, but I now have the problem that all the functions want the StreamWriter object - and if I make it optional, then it won't be there for the functions. And it also seems c# doesn't do optional arguments.
I'm sure you can tell I'm no c# expert and only dabble when I need to. Thanks for your assistance.
You want to use a singleton pattern to refer to the StreamWriter you're using. The singleton is a way to "simulate" the functionality of global variables, without having the problems of them.
Essentially, what the singleton provides is a class-specific instance of a resource you want to be shared among many different parts in your application. The resource is accessed through the a static class instance.
Effectively, what you'll want to do is to define a class which has as a public static member the StreamWriter that you'll want to use; in that way, any method that you use in the rest of your code can get access to that SAME instance of the StreamWriter by accessing it from the containing class (without needing to create an instance of the class, because it's static).
Something like
public static class CsvWriter
{
private static StreamWriter _writer = new StreamWriter(...);
public static StreamWriter Writer
{
get { return _writer; }
}
}
Some variation is possible, the main item is the static property here. It's like a global but not (entirely) as bad.
Are all the functions of the same class? You can make a class variable (a field) and access it from all the methods of the class. If not you can always create a new public class with a static field.
I you can use Console.SetOut for this:
static void Main(string[] args)
{
StreamWriter writer = new StreamWriter(#"c:\path\file.ext");
try
{
Console.SetOut(writer);
Console.WriteLine("One");
Console.WriteLine("Two");
Console.WriteLine("Three");
}
catch (Exception ex)
{
Console.WriteLine("That went wrong.");
}
finally
{
writer.Dispose();
}
}

Categories

Resources