I have 2 web services. One web service takes in an object of type A. When using the "Add Service Reference" in Visual Studio, it creates a class called AType.
My second web service's input method (called x(...)) actually takes in a parameter of type A but for some reason the WSDL is incorrect and declares it as ##any.
<any namespace="##any" processContents="lax" minOccurs="1" maxOccurs="1">
This means that in my code, I would have to create an XmlElement from an XmlDocument:
private static XmlDocument doc = new XmlDocument();
XmlElement e = doc.CreateElement("some-name", "some-uri");
Is there a way I can convert AType into an XmlElement? Do I have to go back to string first?
As an alternative I am thinking of merging my two web service WSDL files...
I finally found that the following code does exactly what I am looking for:
public static XmlElement Serialize(MyObject someClassInstance)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
XmlDocument doc = new XmlDocument();
XPathNavigator nav = doc.CreateNavigator();
XmlWriter writer = nav.AppendChild();
serializer.Serialize(writer, someClassInstance);
writer.WriteEndDocument();
writer.Flush();
writer.Close();
return doc.DocumentElement;
}
Related
I'm trying to load xml file using Xelement.Load() method and in case of some files, I get "ditaarch" is an undeclared prefix exception. The content of such troublesome xml's are similar to this simplified version:
<?xml version="1.0" encoding="UTF-8"?>
<concept ditaarch:DITAArchVersion="1.3">
<title>Test Title</title>
<menucascade>
<uicontrol>text</uicontrol>
<uicontrol/>
</menucascade>
</concept>
I've tried to follow suggestions to manually add or ignore "ditaarch" namespace using xml namespace manager:
using (XmlReader reader = XmlReader.Create(#"C:\test\example.xml"))
{
NameTable nameTable = new NameTable();
XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(nameTable);
nameSpaceManager.AddNamespace("ditaarch", "");
XmlParserContext parserContext = new XmlParserContext(null, nameSpaceManager, null, XmlSpace.None);
XElement elem = XElement.Load(reader);
}
But it leads to same exception as before. Most probably the solution is trivial but I just can't see it :(
If anyone would be able to point me in the right direction, I would be most grateful.
The presented markup is not namespace well-formed XML so I don't think XElement or XDocument is an option as it doesn't support colons in names. You can parse it with a legacy new XmlTextReader("foo.xml") { Namespaces = false } however.
And you could use XmlDocument instead of XDocument or XElement and check for any empty elements with e.g.
XmlDocument doc = new XmlDocument();
using (XmlReader xr = new XmlTextReader("example.xml") { Namespaces = false })
{
doc.Load(xr);
}
Console.WriteLine("Number of empty elements: {0}", doc.SelectNodes("//*[not(*)][not(normalize-space())]").Count);
I've to make an upgrade mechanism which will update an XML documents(To another xml document).
The signature of the method that I've to respect is :
public XmlDocument Update(XmlDocument sourceDocument){...}
What would be the most efficient way to apply an XSLT file on this?
I was expecting to be able to use the XslTransform class, but it only accept stream and XmlWriter as parameter for the output.
So I know that I could do something like:
public XmlDocument Update(XmlDocument sourceDocument){
XslTransform myXslTransform = new XslTransform();
myXslTransform.Load("myXsl.xsl");
MemoryStream ms = new MemoryStream();
myXslTransform.Transform(sourceDocument, null, ms);
XmlDocument output = new XmlDocument();
output.Load(ms);
return output;
}
But I find this not very efficient(knowing that my XSLT will be to rename some nodes, add a node in-between, add a child). Is there a way to do better?
My "only" constraints are: Input/Output: XmlDocument, External XSLT to load.
If you want to use a System.Xml.XmlDocument with the current XSLT 1.0 implementation (XslCompiledTransform) that Microsoft offers then you can use
XmlDocument resultDocument = new XmlDocument();
using (XmlWriter xw = resultDocument.CreateNavigator().AppendChild()) {
XslCompiledTransform proc = new XslCompiledTransform();
proc.Load("myXsl.xsl");
proc.Transform(sourceDocument, null, xw);
xw.Close();
}
return resultDocument;
We had a security audit on our code, and they mentioned that our code is vulnerable to EXternal Entity (XXE) attack. I am using following code -
string OurOutputXMLString=
"<ce><input><transaction><length>00000</length><tran_type>Login</tran_type></transaction><user><user_id>ce_userid</user_id><subscriber_name>ce_subscribername</subscriber_name><subscriber_id>ce_subscriberid</subscriber_id><group_id>ce_groupid</group_id><permissions></permissions></user><consumer><login_details><username>UnitTester9</username><password>pDhE5AsKBHw85Sqgg6qdKQ==</password><pin>tOlkiae9epM=</pin></login_details></consumer></input></ce>"
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(OurOutputXMLString);
In the audit report they say that it's failing because an XML entity can contain URLs that can resolve outside of intended control. XML entity resolver will attempt to resolve and retrieve external references. If attacker-controlled XML can be submitted to one of these functions, then the attacker could gain access to information about an internal network, local filesystem, or other sensitive data.
To avoid this I wrote the following code but it doesn't work.
MemoryStream stream =
new MemoryStream(System.Text.Encoding.Default.GetBytes(OurOutputXMLString));
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.MaxCharactersFromEntities = 6000;
XmlReader reader = XmlReader.Create(stream, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
But I can see here that reader does not have any value to load into xmlDoc(XmlDocument).
Can anyone help where I am missing things?
External resources are resolved using the XmlResolver provided via XmlDocument.XmlResolver property. If your XML documents **should not contain any external resource **(for example DTDs or schemas) simply set this property to null:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.LoadXml(OurOutputXMLString);
If you want to filter where these URLs come from (for example to allow only certain domains) just derive your own class from XmlUrlResolver and override the ResolveUri() method. There you can check what the URL is and sanitize it (for example you can allow only URLs within your local network or from trusted sources).
For example:
class CustomUrlResovler : XmlUrlResolver
{
public override Uri ResolveUri(Uri baseUri, string relativeUri)
{
Uri uri = new Uri(baseUri, relativeUri);
if (IsUnsafeHost(uri.Host))
return null;
return base.ResolveUri(baseUri, relativeUri);
}
private bool IsUnsafeHost(string host)
{
return false;
}
}
Where IsUnsafeHost() is a custom function that check if the given host is allowed or not. See this post here on SO for few ideas. Just return null from ResolveUri() to save your code from this kind of attacks. In case the URI is allowed you can simply return the default XmlUrlResolver.ResolveUri() implementation.
To use it:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = new CustomUrlResolver();
xmlDoc.LoadXml(OurOutputXMLString);
For more details about how XML external resources are resolved just read Resolving External Resources on MS Docs. If your code is more complex than this example then you should definitely read Remarks section for XmlDocument.XmlResolver property.
So its better to use
new XmlDocument { XmlResolver = null };
Interestingly from .net 4.5.2 and 4.6, the default resolver behaves differently and does not use an XmlUrlResolver upfront implicitly to resolve any urls or locations as i seen.
//In pre 4.5.2 it is a security issue.
//In 4.5.2 it will not resolve any more the url references in dtd and such,
//Still better to avoid the below since it will trigger security warnings.
new XmlDocument();
Setting the XmlReaderSettings.DtdProcessing to DtdProcessing.Prohibit works totally fine in .NET 4.7.2. Here is what i used to test.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE demo
[
<!ELEMENT demo ANY >
<!ENTITY % extentity SYSTEM "https://www.hl7.org/documentcenter/public/wg/structure/CDA.xsl">
%extentity;
]>
<test>
Some random content
</test>
Saved the above content in a file and read the file from the following fragment of c# code.
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.MaxCharactersFromEntities = 6000;
//The following stream should be the filestream of the above content.
XmlReader reader = XmlReader.Create(stream, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
I get the following exception.
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.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseDoctypeDecl()
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
at System.Xml.XmlDocument.Load(XmlReader reader)
I've created a [WebMethod] on ASP.NET Web Service which reads XML documents from different web services (ASP.NET and PHP services).
Once the documents are read, they are merged into a XML and returned.
The method can successfully read XML documents from each web service but when I try to append second XML into first one, I get ArgumentException and a message like this The node to be inserted is from a different document context. I can't find a problem, can it be something to do with the source of document? but then both document are exactly same (have same elements).
Why ArgumentException? What am I missing?
[WebMethod]
public XmlDocument getRestaurants(String search_keywords)
{
XmlDocument xmlDom1 = new XmlDocument();
xmlDom1 = getRestaurantFromAspNetWS(search_keywords);
XmlTextReader myXmlTextReader =
new XmlTextReader
("http://some-iss.green.com/username/search.php?s=" + search_keywords);
XmlDocument xmlDom2 = new XmlDocument();
xmlDom2.Load(myXmlTextReader);
foreach (XmlElement xmlNode in xmlDom2.DocumentElement.ChildNodes)
{
//trying to append childNodes of xmlDom2 into xmlDom1
//and this is where i get ArgumentException
xmlDom1.DocumentElement.AppendChild(xmlNode);
}
return xmlDom1;
}
You need to import the node with importNode()
something like this:
xmlDom1.DocumentElement.importNode(xmlNode, true);
Can you write it like this?
public XElement getRestaurants(String search_keywords)
{
XElement result = getRestaurantFromAspNetWS(search_keywords);
XmlTextReader myXmlTextReader = new XmlTextReader
("http://some-iss.green.com/username/search.php?s=" + search_keywords);
XElement reader = XElement.Load(myXmlTextReader);
foreach (XElement child in reader.Elements())
result.Add(child);
return result;
}
The real trick is getting your custom getRestaurantFromAspNetWS function to return a XElement instead of a XmlDocument, as you didn't provide us with that function, I can't help you there.
I am using a class library which represents some of its configuration in .xml. The configuration is read in using the XmlSerializer. Fortunately, the classes which represent the .xml use the XmlAnyElement attribute at which allows me to extend the configuration data for my own purposes without modifying the original class library.
<?xml version="1.0" encoding="utf-8"?>
<Config>
<data>This is some data</data>
<MyConfig>
<data>This is my data</data>
</MyConfig>
</Config>
This works well for deserialization. I am able to allow the class library to deserialize the .xml as normal and the I can use my own XmlSerializer instances with a XmlNodeReader against the internal XmlNode.
public class Config
{
[XmlElement]
public string data;
[XmlAnyElement]
public XmlNode element;
}
public class MyConfig
{
[XmlElement]
public string data;
}
class Program
{
static void Main(string[] args)
{
using (Stream fs = new FileStream(#"c:\temp\xmltest.xml", FileMode.Open))
{
XmlSerializer xser1 = new XmlSerializer(typeof(Config));
Config config = (Config)xser1.Deserialize(fs);
if (config.element != null)
{
XmlSerializer xser2 = new XmlSerializer(typeof(MyConfig));
MyConfig myConfig = (MyConfig)xser2.Deserialize(new XmlNodeReader(config.element));
}
}
}
I need to create a utility which will allow the user to generate a new configuration file that includes both the class library configuration as well my own configuration, so new objects will be created which were not read from the .xml file. The question is how can I serialize the data back into .xml?
I realize that I have to initially call XmlSerializer.Serialize on my data before calling the same method on the class library configuration. However, this requires that my data is represented by an XmlNode after calling Serialize. What is the best way to serialize an object into an XmlNode using the XmlSerializer?
Thanks,
-kevin
btw-- It looks like an XmlNodeWriter class written by Chris Lovett was available at one time from Microsoft, but the links are now broken. Does anyone know of an alternative location to get this class?
So you need to have your class contain custom configuration information, then serialize that class to XML, then make that serialized XML into an XML node: is that right?
Could you just take the string created by the XMLSerializer and wrap that in it's own XML tags?
XmlSerializer xs = new XmlSerializer(typeof(MyConfig));
StringWriter xout = new StringWriter();
xs.Serialize(xout, myConfig);
XmlDocument x = new XmlDocument();
x.LoadXml("<myConfig>" + xout.ToString() + "</myConfig>");
Now x is an XmlDocument containing one element, "<myconfig>", which has your serialized custom configuration in it.
Is that at all what you're looking for?
It took a bit of work, but the XPathNavigator route does work... just remember to call .Close on the XmlWriter, .Flush() doesn't do anything:
//DataContractSerializer serializer = new DataContractSerializer(typeof(foo));
XmlSerializer serializer = new XmlSerializer(typeof(foo));
XmlDocument doc = new XmlDocument();
XPathNavigator nav = doc.CreateNavigator();
XmlWriter writer = nav.AppendChild();
writer.WriteStartDocument();
//serializer.WriteObject(writer, new foo { bar = 42 });
serializer.Serialize(writer, new foo { bar = 42 });
writer.WriteEndDocument();
writer.Flush();
writer.Close();
Console.WriteLine(doc.OuterXml);
One solution is to serialize the inner object to a string and then load the string into a XmlDocument where you can find the XmlNode representing your data and attach it to the outer object.
XmlSerializer xser1 = new XmlSerializer(typeof(Config));
XmlSerializer xser2 = new XmlSerializer(typeof(MyConfig));
MyConfig myConfig = new MyConfig();
myConfig.data = "My special data";
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
XmlWriter xw = new XmlTextWriter(sw);
xser2.Serialize(xw, myConfig);
XmlDocument doc = new XmlDocument();
doc.LoadXml(sb.ToString());
Config config = new Config();
config.data = "some new info";
config.element = doc.LastChild;
xser1.Serialize(fs, config);
However, this solution is cumbersome and I would hope there is a better way, but it resolves my problem for now.
Now if I could just find the mythical XmlNodeWriter referred to on several blogs!
At least one resource points to this as an alternative to XmlNodeWriter: http://msdn.microsoft.com/en-us/library/5x8bxy86.aspx. Otherwise, you could write MS using that form they have on the new MSDN Code Library replacement for GotDotNet looking for XmlNodeWriter.