Writing to XML resource file through serialization - c#

So I'm writing a C# app that has a couple of XML files added as resources. I read from these XML files to populate objects in the code using XML serialization and it works perfectly. So I can access the files like so (I've left some code out, just have the important bits):
using TestApp.Properties;
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
StringReader sr = new StringReader(Resources.Maps);
mapTiles = (MapTiles)serializer.Deserialize(sr);
Now however, I'd like to do the opposite. I'd like to take some data and write it to these XML resource files. However, I seem to be running into trouble with this aspect and was hoping someone could see something I'm messing up or let me know what I need to do? Here's what I'm trying to do:
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
TextWriter writer = new StreamWriter(Resources.Maps);
serializer.Serialize(writer, tempGroup);
writer.Close();
When I run this code though, I get an error on the 2nd line that says ArgumentException was unhandled - Empty path name is not legal.
So if anyone has any thoughts I would greatly appreciate some tips. Thanks so much.

The exception is being raised because you are passing Resources.Maps into StreamWriter. StreamWriter is handling this as a string and assuming it is file path for the stream. But the file path is empty so it is throwing an exception.
To fix out the StreamWriter line you could specify a local temporary file instead of Resources.Maps or use StringWriter with the default constructor e.g. new StringWriter().
If you are writing .resx files then ResXResourceWriter is the class you need. It will also handle your stream writing too. See http://msdn.microsoft.com/en-us/library/system.resources.resxresourcewriter.aspx and http://msdn.microsoft.com/en-us/library/ekyft91f.aspx. The second page has examples on how to use the class but breifly you would call something like this:
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
using (StringWriter stringWriter = new StringWriter())
{
serializer.Serialize(stringWriter, tempGroup);
using (ResXResourceWriter resourceWriter = new ResXResourceWriter("~/App_GlobalResources/some_file.resx"))
{
resourceWriter.AddResource("Maps", stringWriter.ToString());
}
}
If you want to write out an assembly that has a dynamically created resource in it the you can emit a new assembly. In that case have a look here http://msdn.microsoft.com/en-us/library/8ye65dh0.aspx.

The StreamWriter constructor is throwing the exception because Resources.Maps is an empty string.
Check out the documentation on MSDN:
http://msdn.microsoft.com/en-us/library/fysy0a4b.aspx

Hmm, after trying some other things and doing even more research it appears that the problem is that you cannot write to a resource that is part of the application. Something to do with the resource being written into the assembly and therefore it's not writable. So I'll have to modify my approach and write the output to a different file.
Unless of course anyone does know differently. This is just what I've discovered so far. Thanks to those who had some ideas though, much appreciated.

Related

C# XmlTextWriter can't write to file

I have a problem with the XmlTextWriter class, I can't write to a file.
It is a console application I'm creating and the function looks like this.
private void WriteXML()
{
Console.WriteLine("Writing");
using (XmlTextWriter writer = new XmlTextWriter("DataW.xml", System.Text.Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
writer.WriteComment("This is a comment");
writer.WriteStartElement("WeeklyReview");
writer.WriteStartElement("DateTime");
writer.WriteStartAttribute("DateTime","09/04/2018 05:00");
writer.WriteElementString("Activity", "At Theodor");
writer.WriteElementString("Social", "Not Theodor,Theodor");
}
}
The result I'm getting is just a file with nothing in it. And in VS 2017 the file is shown with a white background and nothing in it.
The file I'm writing to is in the solution explorer and located in the same place as the file I'm reading from (which works).
I'm guessing the issue you're seeing is that the XML file created is blank or incomplete. If so, add a using statement around your code like so:
using (XmlTextWriter writer = new XmlTextWriter("DataW.xml", System.Text.Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
writer.WriteComment("This is a comment");
writer.WriteStartElement("Weekly Review"); //NB: A space in an element name!
writer.WriteStartElement("DateTime");
writer.WriteStartAttribute("09/04/2018 05:00"); //NB: a value given as an attribute name (consider: WriteAttributeString)!
writer.WriteElementString("Activity", "At Theodor");
writer.WriteElementString("Social", "Not Theodor,Theodor");
}
The reason for the issue is the methods you're calling write to an underlying stream rather than to the file system. To ensure that data is written to the file system you need to call the Flush method. Flush is called automatically when the writer is closed/disposed (but not when it's finalized). The using statement ensures that your writer is always disposed of correctly, so will ensure that your stream is flushed to disk.
For any other issues, you'd likely have an exception thrown (e.g. were there file access issues writing to the target location). If you're receiving an exception, please share that message and we can recommend a solution for that.
ps. The XML created by this is given below / it's not valid XML, so you'll have other issues down the line. I'll leave those for you to resolve, or for you to ask as another question should you have issues there. In the meantime, you can get some hints from the example in the documentation: https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmltextwriter.writestartattribute?view=netframework-4.7.2
<?xml version="1.0" encoding="utf-8"?>
<!--This is a comment-->
<Weekly Review>
<DateTime 09/04/2018 05:00="">
<Activity>At Theodor</Activity>
<Social>Not Theodor,Theodor</Social>
</DateTime>
</Weekly Review>
I know the Question is old, but in VB.net i got the same result.
I had to call XmlTextWriter.Flush() at the End to get Content in my File.

Deserialize on the fly, or LINQ to XML

Working with C# Visual Studio 2008, MVC1.
I'm creating an xml file by fetching one from a WebService and adding some nodes to it. Now I wanted to deserialize it to a class which is the model used to strongtyped the View.
First of all, I'm facing problems to achieve that without storing the xml in the filesystem cause I don't know how this serialize and deserialize work. I guess there's a way and it's a matter of time.
But, searching for the previous in the web I came accross LINQ to XML and now I doubt whether is better to use it.
The xml would be formed by some clients details, and basically I will use all of them.
Any hint?
Thanks!!
You can save a XElement to and from a MemoryStream (no need to save it to a file stream)
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
document.Save(xw);
xw.Flush();
Then if you reset the position back to 0 you can deserialize it using the DataContractSerializer.
ms.Position = 0;
DataContractSerializer serializer = new DataContractSerializer(typeof(Model));
Model model = (model) serializer.ReadObject(ms);
There are other options for how serialization works, so if this is not what you have, let me know what you are using and I will help.
try this:
XmlSerializer xmls = new XmlSerializer(typeof(XElement));
FileStream FStream;
try
{
FStream = new FileStream(doctorsPath, FileMode.Open);
_Doctors = (XElement)xmls.Deserialize(FStream); FStream.Close();
FStream = new FileStream(patientsPath, FileMode.Open);
_Patients = (XElement)xmls.Deserialize(FStream)
FStream.Close();
FStream = new FileStream(treatmentsPath, FileMode.Open);
_Treatments = (XElement)xmls.Deserialize(FStream);
FStream.Close();
}
catch
{ }
This will load all of the XML files into our XElement variables. The try – catch block is a form of exception handling that ensures that if one of the functions in the try block throws an exception, the program will jump to the catch section where nothing will happen. When working with files, especially reading files, it is a good idea to work with try – catch.
LINQ to XML is an excellent feature. You can always rely on that. You don't need to write or read or data from file. You can specify either string or stream to the XDocument
There are enough ways to load an XML element to the XDocument object. See the appropriate Load functions. Once you load the content, you can easily add/remove the elements and later you can save to disk if you want.

How To Write To An Embedded Resource?

I keep getting the error "Stream was not writable" whenever I try to execute the following code. I understand that there's still a reference to the stream in memory, but I don't know how to solve the problem. The two blocks of code are called in sequential order. I think the second one might be a function call or two deeper in the call stack, but I don't think this should matter, since I have "using" statements in the first block that should clean up the streams automatically. I'm sure this is a common task in C#, I just have no idea how to do it...
string s = "";
using (Stream manifestResourceStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("Datafile.txt"))
{
using (StreamReader sr = new StreamReader(manifestResourceStream))
{
s = sr.ReadToEnd();
}
}
...
string s2 = "some text";
using (Stream manifestResourceStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("Datafile.txt"))
{
using (StreamWriter sw = new StreamWriter(manifestResourceStream))
{
sw.Write(s2);
}
}
Any help will be very much appreciated. Thanks!
Andrew
Embedded resources are compiled into your assembly, you can't edit them.
As stated above, embedded resources are read only. My recommendation, should this be applicable, (say for example your embedded resource was a database file, XML, CSV etc.) would be to extract a blank resource to the same location as the program, and read/write to the extracted resource.
Example Pseudo Code:
if(!Exists(new PhysicalResource())) //Check to see if a physical resource exists.
{
PhysicalResource.Create(); //Extract embedded resource to disk.
}
PhysicalResource pr = new PhysicalResource(); //Create physical resource instance.
pr.Read(); //Read from physical resource.
pr.Write(); //Write to physical resource.
Hope this helps.
Additional:
Your embedded resource may be entirely blank, contain data structure and / or default values.
A bit late, but for descendants=)
About embedded .txt:
Yep, on runtime you couldnt edit embedded because its embedded. You could play a bit with disassembler, but only with outter assemblies, which you gonna load in current context.
There is a hack if you wanna to write to a resource some actual information, before programm starts, and to not keep the data in a separate file.
I used to worked a bit with winCE and compact .Net, where you couldnt allow to store strings at runtime with ResourceManager. I needed some dynamic information, in order to catch dllNotFoundException before it actually throws on start.
So I made embedded txt file, which I filled at the pre-build event.
like this:
cd $(ProjectDir)
dir ..\bin\Debug /a-d /b> assemblylist.txt
here i get files in debug folder
and the reading:
using (var f = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Market_invent.assemblylist.txt")))
{
str = f.ReadToEnd();
}
So you could proceed all your actions in pre-build event run some exes.
Enjoy! Its very usefull to store some important information and helps avoid redundant actions.

How to inspect XML streams from the debugger in Visual Studio 2003

I've got to edit an XSLT stylesheet, but I'm flying blind because the XML input only exists fleetingly in a bunch of streams. I can debug into the code, but can't figure out how to get the contents of the streams out into text I can look at (and run through the XSLT manually while I'm editing them).
The code is part of a big old legacy system, I can modify it in a debug environment if absolutely necessary, but it runs in a windows service connected up to a bunch of MSMQs. So for various reasons I'd rather be able to use the debugger to see the XML without having to change the code first.
Code much simplified, is something like this: (C# - but remember it's .net 1.1 in VS 2003.)
This is the function that gets the XML as a stream, which is then fed into some sort of XSLT transform object. I've tried looking at the writer and xmlStream objects in the watch windows and the immediate window, but can't quite fathom how to see the actual XML.
private MemoryStream GetXml()
{
MemoryStream xmlStream;
xmlStream = new MemoryStream();
XmlWriter writer = new XmlTextWriter(xmlStream, Encoding.UTF8);
writer.WriteStartDocument();
//etc etc...
writer.WriteEndDocument();
writer.Flush();
xmlStream.Position = 0;
return xmlStream; //Goes off to XSLT transform thingy!
}
All help much appreciated.
You could simply add this expression to your watch window after the MemoryStream is ready:
(new StreamReader(xmlStream)).ReadToEnd();
Watch expressions don't need to be simple variable values. They can be complex expressions, but they will have side-effects. As you've noted, this will interrupt execution, since the stream contents will be read out completely. You could recreate the stream after the interruption with another expression, if you need to re-start execution.
This situation arises frequently when debuging code with streams, so I avoid them for simple, self-contained tasks. Unfortunately, for large systems, it's not always easy to know in advance whether you should make your code stream-oriented or not, since it depends greatly on how it will be used. I consider the use of streams to be a premature optimization in many cases, however.
OK, I've not succeeded in using the debugger without modifying the code. I added in the following snippet, which lets me either put a breakpoint in or use debugview.
private MemoryStream GetXml()
{
MemoryStream xmlStream;
xmlStream = new MemoryStream();
XmlWriter writer = new XmlTextWriter(xmlStream, Encoding.UTF8);
writer.WriteStartDocument();
//etc etc...
writer.WriteEndDocument();
writer.Flush();
xmlStream.Position = 0;
#if DEBUG
string temp;
StreamReader st=new StreamReader(xmlStream);
temp=st.ReadToEnd();
Debug.WriteLine(temp);
#endif
return xmlStream; //Goes off to XSLT transform thingy!
}
I'd still prefer to simply look at the xmlstream object in the debugger somehow, even if it disrupts the flow of execution, but in the meantime this is the best I've managed.

Exception when trying to deserialize a xml file

Im trying to deserialize an XML file with XmlSerializer, however im getting this exception:
"There is an error in XML document (1,
2)" The innerexception is:
"<Mymessage
xmlns='http://MyMessages/'> was not
expected."
Which is the very first line in the XML file. my guess is that it has something to do with the xmlns.
I tried to ask Google, and then tried to add the following line to my code
[XmlRoot("MyMessage", Namespace="'http://MyMessages/")]
But I still get the same exception.
In the constructor of the XmlSerializer i needed to specify a default namespace, after doing that everything worked just fine
Please provide the full XML file code to help understand the issue better.
Also put this as the first line in the xml file and see if this solves the issue
<?xml version="1.0" encoding="utf-8"?>
Further to CruelIO's response, I resolved the error by adding:
[XmlRoot("RenderResult", Namespace = "http://mynamespace.uri.org")]
to the class that I was trying to deserialize. e.g: the serialization code was:
RenderResult result;
using (var memoryStream = new MemoryStream(data))
{
var xmlSerializer = new XmlSerializer(typeof(RenderResult));
result = (RenderResult)xmlSerializer.Deserialize(memoryStream);
}
and my class looked like this:
[XmlRoot("RenderResult", Namespace = "http://mynamespace.uri.org")]
public class RenderResult
{
}
It sounds like you have a borked xml file. Easy ways to find out:
try loading it into an xml viewer
or just make sure it has a .xml extension and load in VS or IE
or run xsd.exe over it
If they complain, then the xml is certainly corrupt.
If they work fine, and display your data, then you probably have the serialization attributes wrong. Try using xsd.exe with the "/classes" switch to see what it would do with it...

Categories