ASP .NET Core write to XML-file - c#

In ASP .NET Core, I am trying to add some XML-Element with attributes to an existing XML file.
In ASP NET 4.5, I would have used the code below to make this working:
string path = Server.MapPath("~/Data/foo.xml");
XDocument xdoc = XDocument.Load(path);
//Do stuff with XElement and XAttributes...
xdoc.Save(path);
But with ASP .NET Core, I cannot use Server.MapPath(), So I get the complete path with IHostingEnvironment instead: (Read more here )
Running the complete code below on ASP .NET Core will result in "Cannot convert from String to System.IO.Stream" when trying to run "xdoc.Save(pathToDataFile);" ??
var contentRoot = hostingEnvironment.ContentRootPath;
string pathToDataFile = contentRoot + "\\Data\\foo.xml";
XDocument xdoc = XDocument.Load(pathToDataFile);
//Do stuff with XElement and XAttributes...
xdoc.Save(pathToDataFile);
Why is "xdoc.Save()" not working in ASP .NET Core but working fine in .NET 4.5?

APIs available in .NET Core are a subset of the ones available in the full .NET framework. In some areas, you'll find that pretty much everything from .NET 4.5 is available in .NET Core, but that's not always the case.
In your case, if you have a look with Visual Studio at what overloads of the Save method are available, you'll find these ones:
public void Save(Stream stream);
public void Save(TextWriter textWriter);
public void Save(XmlWriter writer);
public void Save(Stream stream, SaveOptions options);
public void Save(TextWriter textWriter, SaveOptions options);
The reason why you have a compilation error is now pretty clear. In .NET Core, there's no overload accepting a string that defines the file path where the document should be saved.
You'll have to create a write-enabled Stream pointing to the desired path first and pass that Stream to the Save method. You can have a look at the full .NET framework implementation for reference.

I had the same issue, and FileStream works for me.
FileStream fileStream = new FileStream("file.xml", FileMode.Create);
XmlWriterSettings settings = new XmlWriterSettings() { Indent = true};
XmlWriter writer = XmlWriter.Create(fileStream, settings);
Remember to use the following lines of code to prevent the file from being truncated.
writer.Flush();
fileStream.Flush();

Related

Encoding issues with .net core 2

This code works as expected in .net framework but not in .net core 2
The file in.txt contains "Düsseldorf"
in .net framework the output is "Düsseldorf"
in .net core the output is "D�sseldorf"
(I've tried all the other Encodings out of desperation already... no one works)
string infile = #"C:\in.txt", outFile = #"C:\out.txt";
var inStr = new StreamReader(infile, Encoding.Default);
var outStr = new StreamWriter(outFile, false, Encoding.Default);
while (!inStr.EndOfStream)
{
outStr.WriteLine(inStr.ReadLine());
}
outStr.Flush();
inStr.Dispose();
outStr.Dispose();
Any Ideas why it's not working?
According to the official MSDN page the default encoding is not fixed - it depends on the OS settings. If you know which encoding the file has, specify it!
EDIT:
Then try print the encoding details (like name) from the .net framework one that works. Then specify the same in .net core 2. Do not rely on the default one. This page MSDN, List of encodings in the code sample contains a list of encodings that are supported.
UPDATE by gsharp:
I had to reference the NuGet Package System.Text.Encoding.CodePages, register them and use it
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var enc1252 = Encoding.GetEncoding(1252);
var inStr = new StreamReader(infile, enc1252);
var outStr = new StreamWriter(outFile, false, enc1252);

XmlDocument missing Load method in .Net Core?

I'm creating a Console App, .Net Core 1.1, and am trying to read an XML file. I brought in the System.Xml.XmlDocument nuGet package, created an XmlDocument, and then attempted to load using the file name. To my surprise, there is no overload for Load(string). See the attached image from the object browser. Is this permanently gone? I tried finding documentation, but was unsuccessful and mainly just found information like here
using System;
using System.Xml;
using System.Xml.Linq;
namespace ReadingXmlDemo
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
string content =
doc.Load("Example.xml");
The XmlDocument.Load(string) method is part of .NET Core 2.0 and .NET Standard 2.0. For .NET Core 1.*, you'll need to use the Load(Stream) method and pass it FileStream obtained via File.Open.
You can check the availability of the method at API .NET Catalog for System.Xml.XmlDocument.Load(String)
see simple exemple:
string sourceFileXML = #"c:\temp\file.xml";
var xml = new XmlDocument();
using (var sr = new StreamReader(sourceFileXML)) {
xml.Load(sr);
}

Porting XmlTextReader to XmlReader with same behaviour

I want to port some C# code with the full .NET Framework as target into Silverlight-compatible code.
One of the problems I've encountered is that in the original code, an instance of XmlTextReader is used:
var xmlReader = new XmlTextReader(streamReader) {
WhitespaceHandling = WhitespaceHandling.None,
xmlResolver = null
};
However, in Silverlight, only XmlReader is available. Therefore, I'm wondering how to convert from the original XmlTextReader.
In the documentation of XmlTextReader, it's stated that
In the .NET Framework version 2.0 release, the recommended practice is to create XmlReader instances using the XmlReader.Create method. This allows you to take full advantage of the new features introduced in this release. For more information, see Creating XML Readers.
This supports the theory that a port should be possible.
How does the initialization of a XmlReader has to look like to process the XML files exactly the same as the XmlTextReader instance mentioned above?
var settings = new XmlReaderSettings {
...
}
var xmlReader = XmlReader.Create(streamReader, settings);
Its not possible to replicate this entirely. Silverlight XmlReader does not support ignoring significant whitespace. This therefore is close:-
var settings = new XmlReaderSettings { IgnoreWhitespace = true, XmlResolver = null };
I think you should just go with that and see what happens.

XSLT version 2.0 transformation problem with C#

Hi I've got several XSLT 2.0 files. I need to transform these with C#..
I use the following code I got from this site: http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=63
public bool Transform(string XMLPath, string XSLPath, string newXMLname){
try{
XPathDocument myXMLPath = new XPathDocument(XMLPath); //load the Xml doc
XslCompiledTransform myXSLTrans = new XslCompiledTransform();
myXSLTrans.Load(XSLPath); //load the Xsl
XmlTextWriter myWriter = new XmlTextWriter(newXMLname, null); //create the output stream
myXSLTrans.Transform(myXMLPath, null, myWriter); //do the actual transform of Xml ---> fout!!??
myWriter.Close() ;
return true;
}catch(Exception e){
return false;
}
}
But it doesn't work.. I think it's because I use XSLT version 2.0.
Is there a code/way to do this? Because there is no way to change my XSLT files to version 1.0...
Thanks in advance!
The two XSLT 2.0 processors that are designed to work in the .NET environment are Saxon.NET and XQSharp.
The XslCompiledTransform and XslTransform processors that come as part of .NET only implement XSLT 1.0.
Natively .Net Framework doesn't support XSLT 2.0. I would suggest to use XSLT 1.0, but if you can't, then use third party component, for example Saxon.

What's the most streamlined way of performing a XSLT transformation in ASP.NET?

In other words, is there a faster, more concise way of writing the following code:
//Create an object for performing XSTL transformations
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(HttpContext.Current.Server.MapPath("/xslt/" + xsltfile.Value), new XsltSettings(true, false), new XmlUrlResolver());
//Create a XmlReader object to read the XML we want to format
//XmlReader needs an input stream (StringReader)
StringReader sr = new StringReader(node.OuterXml);
XmlReader xr = XmlReader.Create(sr);
//Create a StringWriter object to capture the output from the XslCompiledTransform object
StringWriter sw = new StringWriter();
//Perform the transformation
xslt.Transform(xr, null, sw);
//Retrieve the transformed XML from the StringWriter object
string transformedXml = sw.ToString();
UPDATE (thanks for all the answers so far!):
Sorry for my vagueness: by "faster" and more "concise" I mean, am I including any unnecessary steps? Also, I would love a more "readable" solution if someone has one. I use this code in a small part of a web application I'm developing, and I'm about to move it to a large part of the application, so I want to make sure it's as neat as can be before I make the move.
Also, I get the XML from a static class (in a separate data access class library) which communicates with a database. I also manipulate the transformed XML string before shipping it off to a web page. I'm not sure if the input/response streams are still viable in this case.
One more thing: the XML and the XSLT supplied may change (users of the application can make changes to both), so I think I would be forced to compile each time.
Here's code I did for my ASP.NET, which is very similar to yours:
XDocument xDoc = XDocument.Load("output.xml");
XDocument transformedDoc = new XDocument();
using (XmlWriter writer = transformedDoc.CreateWriter())
{
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(XmlReader.Create(new StreamReader("books.xslt")));
transform.Transform(xDoc.CreateReader(), writer);
}
// now just output transformedDoc
If you have a large XSLT you can save the overhead of compiling it at runtime by compiling the XSLT into a .NET assembly when you build your project (e.g. as a post-build step). The compiler to do this is called xsltc.exe and is part of Visual Studio 2008.
In order to load such a pre-compiled XSLT you will need .NET Framework 2.0 SP1 or later installed on your server (the feature was introduced with SP1).
For an example check Anton Lapounov's blog article:
XSLTC — Compile XSLT to .NET Assembly
If pre-compiling the XSLT is not an option you should consider caching the XslCompiledTransform after it is loaded so that you don't have to compile it everytime you want to execute the transform.
Don't have time to do a full example, but some notes:
XML is not the same as System.String. Get it from the class library as XDocument or XmlDocument; finish with it as XDocument or XmlDocument.
You can use the ASP.NET Cache to store the compiled XSL, with a cache dependency on when the .XSLT file changes.
Don't convert the XML to a string then back to XML. Use node.CreateNavigator().ReadSubTree().
Similarly, use XPathNavigator.AppendChild to get an XmlWriter that will write into an XML Document.
Since you mention ASP.NET, the question is whether you can use the response stream directly for your transform output and whether you can use the input stream directly if it is a POST...
I'd rewrite the code like this:
string path = HttpContext.Current.Server.MapPath("/xslt/" + xsltfile.Value);
XmlReader reader = CreateXmlReader(node.OuterXml);
string transformedXml = Transform(path, reader);
private XmlReader CreateXmlReader(string text)
{
StringReader reader = new StringReader(text);
return XmlReader.Create(reader);
}
private string Transform(string xsltPath, XmlReader source)
{
XsltCompiledTransform transformer = new XsltCompiledTransform();
transformer.Load(
xsltPath,
new XsltSettings(true, false),
new XmlUrlResolver());
StringWriter writer = new StringWriter();
transformer.Transform(source, null, writer);
return writer.ToString();
}
The reason why I'd rewrite the code like this is because each block of code now has one and only one purpose. This makes it easier to read and understand. Additionally, the code requires less comments because a lot of information can be inferred from the names of the function and its parameters.

Categories