Can't set settings on XmlTextReader? - c#

I need to set the MaxCharactersFromEntities on the XmlTextReader, this is my code so far :
xmlDocument = new XmlDocument();
xmlTextReader = new XmlTextReader(fileInfo.FullName);
xmlTextReader.Settings = new XmlReaderSettings();
xmlTextReader.Settings.MaxCharactersFromEntities = 0;
var vr = new XmlValidatingReader(xmlTextReader);
vr.ValidationType = ValidationType.None;
vr.EntityHandling = EntityHandling.ExpandEntities;
xmlDocument.Load(vr);
The Settings property is read-only so it can´t be set and its null? How is this supposed to work?

You're supposed to pass XmlReaderSettings instance upon construction of the XmlReader instance in the first place, rather than updating the reader's Settings property later -which is impossible as the property doesn't have setter- :
var xmlDocument = new XmlDocument();
//create XmlReaderSettings first
var settings = new XmlReaderSettings();
settings.MaxCharactersFromEntities = 80; //0 doesn't make sense here, as it's the default value
//create XmlReader later, passing the pre-defined settings
var xmlReader = XmlReader.Create(fileInfo.FullName, settings);
//the rest of the codes remain untouched
var vr = new XmlValidatingReader(xmlReader);
vr.ValidationType = ValidationType.None;
vr.EntityHandling = EntityHandling.ExpandEntities;
xmlDocument.Load(vr);

You should use XmlReader.Create(string, XmlReaderSettings) instead to create your reader instance.
From the MSDN reference:
Starting with the .NET Framework 2.0, we recommend that you use the
System.Xml.XmlReader class instead.
The idea is to use the Create(...) factory method of the base class XmlReader instead of instantiating the derived class directly. Also see the factory method pattern for additional info.
The rest of your code remains unaffected since XmlValidatingReader takes an XmlReader in the constructor.
So you should end up with somehting like:
xmlDocument = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings();
settings.MaxCharactersFromEntities = 0;
XmlReader reader = XmlReader.Create(fileInfo.FullName, settings);
var vr = new XmlValidatingReader(reader);
vr.ValidationType = ValidationType.None;
vr.EntityHandling = EntityHandling.ExpandEntities;
xmlDocument.Load(vr);

Related

"DTD is prohibited" exception when transforming XML file

I've created a custom HTMLHelper which is supposed to render parsed XML. The method takes the XML and the path to an XSL file and should return HTML.
When I access the page, I get the error
XmlException: For security reasons DTD is prohibited in this XML document. To enable DTD processing set the DtdProcessing property on XmlReaderSettings to Parse and pass the settings into XmlReader.Create method.
As you can see in my code below, I'm setting DtdProcessing toParse in the XmlReaderSettings (as the exception suggests), which I thought would resolve the issue. On closer inspection, the exception is occurring at the line:
transformObj.Load(xsltPath);
But I can't see how I can pass XmlReaderSettings to that method so as to set the DtdProcessing property. The only overloads of XslCompiledTransform.Load which accept a settings object expect a XsltSettings object, which doesn't have a DtdProcessing property.
The full method is as follows:
public static IHtmlContent RenderXml(this IHtmlHelper htmlHelper, string xml, string xsltPath)
{
XsltArgumentList args = new XsltArgumentList();
// Create XslCompiledTransform object to load and compile XSLT file.
XslCompiledTransform transformObj = new XslCompiledTransform();
transformObj.Load(xsltPath);
// Create XMLReaderSetting object to assign DtdProcessing, Validation type
XmlReaderSettings xmlSettings = new XmlReaderSettings();
xmlSettings.DtdProcessing = DtdProcessing.Parse;
xmlSettings.MaxCharactersFromEntities = 1024; // Prevent DoS attacks
xmlSettings.ValidationType = ValidationType.DTD;
// Create XMLReader object to Transform xml value with XSLT setting
XmlReader reader = XmlReader.Create(new StringReader(xml), xmlSettings);
using (reader)
{
StringWriter writer = new StringWriter();
transformObj.Transform(reader, args, writer);
// Generate HTML string from StringWriter
HtmlString htmlString = new HtmlString(writer.ToString());
return htmlString;
}
}
And in my view I'm using:
#Html.RenderXml(ViewBag.XML as string, ViewBag.XSL as string);
I've reviewed the advice in the answers to this question but as far as I can tell I've already taken the steps suggested. The accepted answer to this MSDN question seems to hint at an answer but I haven't been able to work out how to make use of it.
If the XSLT uses or references a DTD, pass an XmlReader with the necessary XmlReaderSettings to the Load method, i.e. use the overload https://learn.microsoft.com/en-us/dotnet/api/system.xml.xsl.xslcompiledtransform.load?view=netframework-4.8#System_Xml_Xsl_XslCompiledTransform_Load_System_Xml_XmlReader_ with
using (XmlReader xsltReader = XmlReader.Create(xsltPath, new XmlReaderSettings() { DtdProcessing = DtdProcessing.Parse }))
{
transformObj.Load(xsltReader);
}

Review that the XML parsed here is from a trusted source, otherwise set settings.DtdProcessing to System.Xml.DtdProcessing.Prohibit or .Ignore

Rule:
Do not allow Dtd on XmlTextReader
Category:
Microsoft.Security.Xml
Check Id:
CA3054
Rule Description:
Prohibit DTD processing when using XmlTextReader on untrusted sources. Enabling DTD processing on the XML reader and using UrlResolver for resolving external XML entities may lead to information disclosure. Content from file system or network shares for
the machine processing the XML can be exposed to attacker. In addition, an attacker can use this as a DoS vector.
Rule File:
securityxmlrules.dll [14.0.0.0]
Help:
http://go.microsoft.com/fwlink/?LinkId=282614&clcid=0x409
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
StringReader stringReader = new StringReader(xml);
XmlTextReader reader = new XmlTextReader(stringReader);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlAttributeCollection attrs = doc.DocumentElement.Attributes;
if (!string.IsNullOrWhiteSpace(cookie))
{
string pagingcookie = GetPagingCookie(cookie);
if (!string.IsNullOrWhiteSpace(pagingcookie))
{
XmlAttribute pagingAttr = doc.CreateAttribute("paging-cookie");
pagingAttr.Value = pagingcookie;
attrs.Append(pagingAttr);
}
}
How to resolve this FxCop for SDL
You created a settings object but your XmlReader doesn't actually use it. You need to create an XmlReader with the settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
StringReader stringReader = new StringReader(xml);
XmlReader reader = XmlReader.Create(stringReader, settings);

XMLPrime XLST.Compile throwing a null exception

public static SqlXml XMLPrimeTransform(SqlXml inputDataXML, SqlXml inputTrasnformXML)
{
MemoryStream ms = new MemoryStream();
XmlReader inxml = inputDataXML.CreateReader();
XmlReader intrans = inputTrasnformXML.CreateReader();
XmlReaderSettings xmlreadersettings = new XmlReaderSettings { NameTable = intrans.NameTable };
XdmDocument document= new XdmDocument(inxml);
XmlPrime.XsltSettings xsltSettings = new XmlPrime.XsltSettings(intrans.NameTable) { ContextItemType = XdmType.Node };
var xslt = Xslt.Compile(intrans, xsltSettings);
//var xslt = Xslt.Compile(inputTrasnformXML.CreateReader());
var contextItem = document.CreateNavigator();
var settings = new DynamicContextSettings { ContextItem = contextItem };
xslt.ApplyTemplates(settings, ms);
return new SqlXml(ms);
}
I wrote the above code function to apply a xlst 2.0 stylesheet to xml and return the XML.
I tried to modify the XMLPrime example, but for some reason the line:
var xslt = Xslt.Compile(intrans, xsltSettings);
is throwing a NullReferenceException. Both intrans and xsltSettings are not null. Anyone have any luck trying to accomplish this with XMLPrime or any other library?
It may be a bug specific to the stylesheet you are loading. Try using a minimal stylesheet to see if that is the case. If you think it is a bug in XmlPrime, contact the developers and supply a Visual Studio solution which reproduces the problem.

Set two ObservableCollection equal, without losing WPF-Binding

I have a ObservableCollection of MediaFile
MediaControlClass.GetInstanze().MediaLibrary
I have a lot of WPF Bindings of this ObservableCollection.
In some case I have to refill this collection form a XML File. In the XML File are 20.000 MediaFiles. I tried two ways.
First way:
serializer = new XmlSerializer(typeof(System.Collections.ObjectModel.ObservableCollection<MediaFile>));
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
xmlReaderSettings.CheckCharacters = false;
using (XmlReader reader = XmlReader.Create(Environment.CurrentDirectory + "\\Notes.xml", xmlReaderSettings))
{
o = serializer.Deserialize(reader);
MediaControlClass.GetInstanze().MediaLibrary.Clear();
foreach (var i in (System.Collections.ObjectModel.ObservableCollection<MediaFile>)o)
MediaControlClass.GetInstanze().MediaLibrary.Add(i);
}
I added every MediaFile to the MediaControlClass.GetInstanze().MediaLibrary which was really to slow.
Second way:
serializer = new XmlSerializer(typeof(System.Collections.ObjectModel.ObservableCollection<MediaFile>));
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
xmlReaderSettings.CheckCharacters = false;
using (XmlReader reader = XmlReader.Create(Environment.CurrentDirectory + "\\Notes.xml", xmlReaderSettings))
{
o = serializer.Deserialize(reader);
MediaControlClass.GetInstanze().MediaLibrary = (System.Collections.ObjectModel.ObservableCollection<MediaFile>)o;
}
This is fast, but I have to rebind a lot of WPF Controls.
Is there some way to do this fast and without rebinding?
This is just a wild guess, but would raising a manual property changed notification help in the second case?
As for the first method, might be that it's slow because you're doing a typecast inside foreach and it casts on every loop?
I agree with dain. If you raise a OnPropertyChanged event in MediaLibrary setter, you should not have to move any binding.

Deprecated XML validation code problem C#

I'm trying to figure out how to correct his deprecated xml schema validation code.
public static bool ValidateXml(string xmlFilename, string schemaFilename)
{
⁞
//Forward stream reading access to data
XmlTextReader forwardStream = new XmlTextReader(xmlFilename);
//deprecated way of checking agaisnt a schema -- update.
//xmlreader class.
XmlValidatingReader validation = new XmlValidatingReader(forwardStream);
validation.ValidationType = ValidationType.Schema;
//XmlReader validator = new XmlReader.Create(
XmlSchemaCollection schemas = new XmlSchemaCollection();
schemas.Add(null, schemaFilename);
validation.Schemas.Add(schemas);
⁞
you need to use XmlReader and XmlReaderSettings instead of deprecated classes. Below is an example:
// Create the XmlSchemaSet class.
XmlSchemaSet sc = new XmlSchemaSet();
// Add the schema to the collection.
sc.Add("urn:bookstore-schema", "books.xsd");
// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas = sc;
settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
// Create the XmlReader object.
XmlReader reader = XmlReader.Create("booksSchemaFail.xml", settings);
// Parse the file.
while (reader.Read());
more details here: Validating XML Data with XmlReader

Categories

Resources