CDATA section as string using service reference - c#

Using c# and visual studio 2015
I'm working with an external webservice and I have build a service reference using a delivered WSDL. That is all working, and I can call the service, but I get a error because the request is not in correct format...
Part of the service definition is this:
<xsd:complexType name="GCTPLookupRequestType">
<xsd:sequence>
<xsd:element name="gctpMessage" type="xsd:string" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
The gctpMessage is a string element but is expected to contain a CDATA section like this:
<![CDATA[
<Gctp v="1.0">
<System r="CprSoeg">
<Service r="STAM+">
<CprServiceHeader r="STAM+">
<Key>
<Field r="PNR" v="0000000000"/>
</Key>
</CprServiceHeader>
</Service>
</System>
</Gctp>
]]>
If I append this as a string as expected to the gctpMessage property all seems fine, but when I inspect the request using Fiddler I se that it is all wrong:
<gctpMessage>
<![CDATA[<Gctp v="1.0"><System r="CprSoeg"><
Service r="STAM+"><CprServiceHeader r="STAM+"><Key><
Field r="PNR" v="0000000000"/></Key></CprServiceHeader></
Service></System></Gctp>]]>
</gctpMessage>
I know this is caused by the XML serializer enterpreting this as a string and therefore escapes the tags.
But how do I get around this? The WSDL has defined it as a string and I really want to use the service reference but I do not know how to handle this...
Changing the service is not an option.
Any suggestion would be appriciated :)

Just perfect dbc, it did the trick :)
Thanks for that..
[System.Xml.Serialization.XmlIgnore]
public string gctpMessage {
get {
return this.gctpMessageField;
}
set {
this.gctpMessageField = value;
this.RaisePropertyChanged("gctpMessage");
}
}
[System.Xml.Serialization.XmlElementAttribute(Order = 1, ElementName = "gctpMessage")]
public XmlNode[] CDataContent
{
get
{
var dummy = new XmlDocument();
return new XmlNode[] { dummy.CreateCDataSection(gctpMessage) };
}
set
{
if (value == null)
{
gctpMessage = null;
return;
}
if (value.Length != 1)
{
throw new InvalidOperationException(
String.Format(
"Invalid array length {0}", value.Length));
}
gctpMessage = value[0].Value;
}
}

Related

Error while validating XML

System.ArgumentNullException: value cannot be undefined
StackTrace:
at System.Xml.Linq.XAttribute..ctor(XName name, Object value)
at System.Xml.Schema.XNodeValidator.ValidateAttributes(XElement e)
at System.Xml.Schema.XNodeValidator.ValidateElement(XElement e)
at System.Xml.Schema.XNodeValidator.ValidateNodes(XElement e)
at System.Xml.Schema.XNodeValidator.ValidateElement(XElement e)
at System.Xml.Schema.XNodeValidator.Validate(XObject source, XmlSchemaObject partialValidationType, Boolean addSchemaInfo)
at System.Xml.Schema.Extensions.Validate(XDocument source, XmlSchemaSet schemas, ValidationEventHandler validationEventHandler, Boolean addSchemaInfo)
Source code:
var xmlPath = #"C:\XSDTEST\test.xml";
XDocument doc = XDocument.Load(xmlPath);
XmlSchemaSet xss = new XmlSchemaSet();
xss.Add("",#"C:\XSDTEST\test.xsd");
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.ValidationType = ValidationType.Schema;
xrs.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
xrs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
xrs.ValidationFlags |= XmlSchemaValidationFlags.ProcessIdentityConstraints;
xrs.Schemas = xss;
doc.Validate(xss, new ValidationEventHandler((s, args) => { }), true);
test.xsd:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Root">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Child1" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="Child2" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Child2" type="Child2ElemType"/>
<xsd:complexType name="Child2ElemType">
<xsd:attribute ref="align" default="left"/>
</xsd:complexType>
<xsd:attribute name="align" type="alignAttType"/>
<xsd:simpleType name="alignAttType">
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="left"/>
<xsd:enumeration value="right"/>
<xsd:enumeration value="center"/>
<xsd:enumeration value="justify"/>
<xsd:enumeration value="char"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
test.xml:
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///C:/XSDTEST/test.xsd">
<Child1/>
<Child2/>
</Root>
The problem: default="left":
<xsd:attribute ref="align" default="left"/>
I think the validation process tries to create an "align" attribute with a default value, but the XAttribute constructor gets null, not "left".
If I set default value at <xsd:attribute name="align" type="alignAttType" default="left"/> it works fine.
If I set default value at <xsd:attribute ref="align" default="left"/> I will get the error.
Can I disable the creation of attributes with default values during the validation process?
or
What are the settings for correctly handling the default values?
Based on the XSD, the "ref=" must be a "Qualified Name"
https://msdn.microsoft.com/en-us/library/ms256143(v=vs.110).aspx
The ref value must be a qualified name (QName)
Since you have an XSD without a namespace, it looks like the validator is not able to find the referenced attribute.
Also, take a look at this related SO question:
How to reference an attribute in xsd
in XML Schemas all global element, attribute or type definitions must be qualified
The following is the relevant Standard extract:
https://www.w3.org/TR/REC-xml-names/#defaulting
Default namespace declarations do not apply directly to attribute names
The namespace name for an unprefixed attribute name always has no value
The following link talks specifically about the unqualified global attributes
Unqualified XSD global attribute references
After loading schemas I founded temporary workaround:
foreach (XmlSchema schema in xss.Schemas())
{
foreach (System.Collections.DictionaryEntry ag in schema.AttributeGroups)
{
if (ag.Value is XmlSchemaAttributeGroup)
{
var attributeGroup = (XmlSchemaAttributeGroup)ag.Value;
foreach (var attributeOrGroup in attributeGroup.Attributes)
{
if (attributeOrGroup is XmlSchemaAttribute)
{
var attribute = (XmlSchemaAttribute)attributeOrGroup;
if (attribute.DefaultValue != null)
{
attribute.DefaultValue = null;
}
if (attribute.FixedValue != null)
{
attribute.FixedValue = null;
}
}
}
}
}
foreach (System.Collections.DictionaryEntry st in schema.SchemaTypes)
{
if (st.Value is XmlSchemaComplexType)
{
var c = (XmlSchemaComplexType)st.Value;
foreach (var g in c.Attributes)
{
if (g is XmlSchemaAttribute)
{
var attr = (XmlSchemaAttribute)g;
if (attr.DefaultValue != null)
{
attr.DefaultValue = null;
}
if (attr.FixedValue != null)
{
attr.FixedValue = null;
}
}
}
}
}
}

Connecting to Salesforce Problems C#

I am getting the following error and can not seem to figure out why.
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
Additional information: Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'iDdataPrep.SFDC.ListViewRecordColumn[]' to 'iDdataPrep.SFDC.ListViewRecordColumn'
error CS0030: Cannot convert type 'iDdataPrep.SFDC.ListViewRecordColumn[]' to 'iDdataPrep.SFDC.ListViewRecordColumn'
error CS0029: Cannot implicitly convert type 'iDdataPrep.SFDC.ListViewRecordColumn' to 'iDdataPrep.SFDC.ListViewRecordColumn[]'
error CS0029: Cannot implicitly convert type 'iDdataPrep.SFDC.ListViewRecordColumn' to 'iDdataPrep.SFDC.ListViewRecordColumn[]'
Here is my code:
public static void sfLogin()
{
string userName = "***";
string password = "***";
string securityToken = "***";
SFDC.SforceService sfdcBinding = null;
SFDC.LoginResult currentLoginResult = null;
sfdcBinding = new SFDC.SforceService();
try
{
currentLoginResult = sfdcBinding.login(userName, password);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
sfdcBinding = null;
MessageBox.Show(ex.Message);
}
catch(Exception ex)
{
sfdcBinding = null;
MessageBox.Show(ex.Message);
}
sfdcBinding.Url = currentLoginResult.serverUrl;
sfdcBinding.SessionHeaderValue = new SFDC.SessionHeader();
sfdcBinding.SessionHeaderValue.sessionId = currentLoginResult.sessionId;
}
Some .Net integrations with Salesforce do fail due to a bug in .NET's XmlSerializer as described in the this link.
The workaround is to add the following element to the Enterprise.WSDL.XML file:
<xsd:attribute name="tmp" type="xsd:string" />
in the ListViewRecord section. Your Enterprise.WSDL.XML should look like :
<complexType name="ListViewRecord">
<sequence>
<element name="columns" type="tns:ListViewRecordColumn" maxOccurs="unbounded"/>
</sequence>
<b>
<xsd:attribute name="tmp" type="xsd:string" />
</b>
</complexType>
Check out more in this link.
I just ran into this problem. Here is work around I used. Before you generate the proxy file from the wsdl (such as partner.wsdl), edit the file and add a dummy field to the ListViewRecord defintion.
<complexType name="ListViewRecord">
<sequence>
<element name="columns" type="tns:ListViewRecordColumn" minOccurs="1" maxOccurs="unbounded"/>
<element name="dummy" type="xsd:int"/>
</sequence>
</complexType>
When you generate the proxy file with wsdl.exe it will generate the classes ListViewRecord and ListViewRecordColumn correctly. Then delete the dummy field from the generated code and the classes and properties will be defined as they should be.
public partial class ListViewRecord {
private ListViewRecordColumn[] columnsField;
/// ** delete this member variable **
private int dummyField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("columns")]
public ListViewRecordColumn[] columns {
get {
return this.columnsField;
}
set {
this.columnsField = value;
}
}
/// ** delete this property **
public int dummy {
get {
return this.dummyField;
}
set {
this.dummyField = value;
}
}
}
There are two references to ListViewRecordColumn[][] in Reference.cs.
Change them both to ListViewRecordColumn[].

Xml Xsd Validation Fails (xs:anyType)

I have this XML file
<bookstore>
<test>
<test2/>
</test>
</bookstore>
and this XSD schema
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="bookstore" type="bookstoreType"/>
<xsd:complexType name="bookstoreType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="test" type="xsd:anyType" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
I intend to validate xml file from C# code.
There is a method that validate XML file:
// validate xml
private void ValidateXml()
{
_isValid = true;
// Get namespace from xml file
var defaultNamespace = XDocument.Load(XmlFileName).Root.GetDefaultNamespace().NamespaceName;
// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.Schemas.Add(defaultNamespace, XsdFileName);
settings.ValidationEventHandler += OnValidationEventHandler;
// Create the XmlReader object.
using(XmlReader reader = XmlReader.Create(XmlFileName, settings))
{
// Parse the file.
while (reader.Read()) ;
}
}
private void OnValidationEventHandler(object s, ValidationEventArgs e)
{
if (_isValid) _isValid = false;
if (e.Severity == XmlSeverityType.Warning)
MessageBox.Show("Warning: " + e.Message);
else
MessageBox.Show("Validation Error: " + e.Message);
}
I know, this XML file is valid. But my code reterns this Error:
Validation Error: Could not find schema information for the element 'test2'
Where is my mistake?
Thanks!!!
UPDATE: I assume your code matches the error you listed (I've tried your code on .NET 3.5SP1, and I wasn't able to reproduce your behaviour). The workaround below should work for sure (the error you're getting is consistent to a process contents clause strict as opposed to lax).
Replace <xsd:element name="test" type="xsd:anyType" /> with a complex content that allows for xsd:any, like this:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="bookstore" type="bookstoreType"/>
<xsd:complexType name="bookstoreType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="test">
<xsd:complexType>
<xsd:sequence>
<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Having "lax" will still yield a message; you could use "skip" if you want that message gone. Regardless, skip and lax in an xsd:any gives you what you need.

XmlDocument and getting specific Attributes using xPath

I have seen a couple of examples on here where Xpath is used in conjunction with XmlDocument to get a specific attribute from an XmlDocument Node.... Example
Console.WriteLine(xmlDocument.SelectSingleNode("//dataTemplateSpecification/templates/template/elements/element/#name").Value.ToString());
For some reason I am getting a "Object reference not set to an instance of an object." exception. Whenever I run across that particular line of code. I have a little test app that I have set up to test out different things before I put them into my main project...
Here is the code for that...
namespace ReadXml
{
class Program
{
static void Main(string[] args)
{
//string fulXmlPath = System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/templateExample.xml");
XDocument xDocument = XDocument.Load("C:\\Users\\derekww\\Documents\\XML Documents\\templateExample.xml");
XElement elem = xDocument.Element("dataTemplateSpecification"); ;
XmlDocument xmlDocument = new XmlDocument();
StreamReader file = new StreamReader("C:\\Users\\derekww\\Documents\\XML Documents\\templateExample.xml");
xmlDocument.Load(file);
//XmlDocument theDoc = new XmlDocument();
//using (var xmlReader = xDocument.CreateReader())
//{
// xmlDocument.Load(xmlReader);
//}
//Console.WriteLine(elem.ToString());
XmlNode xNode = xmlDocument.SelectSingleNode("//dataTemplateSpecification/templates/template/elements/element");
Console.WriteLine("WORK PLEASE!!!! {0}", xNode.Value.ToString());
//Console.WriteLine(xmlDocument.SelectSingleNode("//dataTemplateSpecification/templates/template/elements/element/#name").Value.ToString());
//Console.WriteLine("This better Work>>>> {0}", xmlDocument.Attributes["/dataTemplateSpecification/templates/template/elements/element/#name"].Value);
Console.ReadLine();
//Console.WriteLine("This better Work>>>> {0}", xmlDocument.SelectSingleNode("//dataTemplateSpecification/templates/template/elements/element/#name").Value);
//foreach (String AttVal in xmlDocument.SelectSingleNode("//dataTemplateSpecification/templates/template/elements/element/#name").Value)
{
//Console.WriteLine("This better Work>>>> {0}", AttVal);
}
}
}
}
Here is part of the XML that I used...
<?xml version="1.0" encoding="utf-8"?>
<dataTemplateSpecification id="id1" name="name1" xmlns="http://EADIS.upmc.com /DataTemplateSpecification.xsd">
<description xmlns="">
<html>text</html>
</description>
<templates xmlns="">
<template>
<elements>
<element id="element0" name="PatientId" display="Patient ID" dataType="String" value="0101010111111" visable="false" readOnly="true">
<validation>
<rules>
<rule id="0" test="#element0.value == ''">
<fail>
<html><b>Patient ID is null, value must be present</b></html>
</fail>
</rule>
</rules>
</validation>
</element>
</elements>
</template>
<templates>
I just showed you the part that you need to understand the xml structure. I assure you that it is well formed. I think I asked this question before but somehow or the other it didn't get posted (maybe I forgot, who knows). Any help with this would be greatly appreciated. If I come up with a reason for why it isn't working I will be sure to let you guys know.
Thank You.
Why can't you use this XPath:
xmlDocument.SelectSingleNode("//templates/template/elements/element/#name").Value
You need to specify the namespace of the XML file in your code.
See here for more info: How to select xml root node when root node has attribute?

What is the best way to create an XML document conforming to an XSD Schema?

I have an XSD and I have to generate an XML document to send to the customers of the company I work with. The documents I send will be validated against this XSD schema.
What is the best way to create a XML document conforming to a XSD Schema? I mean, I'm searching for best practices and the like. I'm new to this and while "Googling" around here and there, I found people using XmlTextWriter, DataSet.WriteXml, and others.
DataSet.WriteXml seems to not work well for me. This is what I did:
var ds = new DataSet();
ds.ReadXmlSchema(schemaFile);
ds.Tables["TableName"].Rows.Add("", "", 78, true, DateTime.Now);
...
ds.WriteXml("C:\\xml.xml");
I found it generates a node with NewDataSet, and the nodes are not in the proper order.
XmlTextWriter, I find it a bit long to do... but I will if there is no other choice.
What do you think is the best way to do this? Are there other approaches to do it?
I would put the schema here if it wasn't so long, and if it were relevant to the question.
The mainstream practice in .NET is to use XML Serialization.
In your case, I would do this:
run the xsd.exe too on .XSD to generate source code for classes (xsd /c)
build your app that utilizes those generated classes. Keep in mind you can extend those classes via the "partial classes" technique
in code, instantiate an XmlSerializer, and Serialize the class instances.
Example:
Given this schema:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Foo" nillable="true" type="Foo" />
<xs:complexType name="Foo">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Bar" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="Baz" type="UntypedArray" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="UntypedArray">
<xs:choice minOccurs="1" maxOccurs="unbounded">
<xs:element name="Type1" type="Type1" minOccurs="1" maxOccurs="1"/>
<xs:any namespace="##other" processContents="lax" minOccurs="1" maxOccurs="1"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="Type1" mixed="true">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Child" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
xsd.exe generates this source code:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)]
public partial class Foo {
private string barField;
private object[] bazField;
/// <remarks/>
public string Bar {
get {
return this.barField;
}
set {
this.barField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("", typeof(System.Xml.XmlElement), IsNullable=false)]
[System.Xml.Serialization.XmlArrayItemAttribute(typeof(Type1), IsNullable=false)]
public object[] Baz {
get {
return this.bazField;
}
set {
this.bazField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public partial class Type1 {
private string childField;
private string[] textField;
/// <remarks/>
public string Child {
get {
return this.childField;
}
set {
this.childField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public string[] Text {
get {
return this.textField;
}
set {
this.textField = value;
}
}
}
In your app you can instantiate a Foo and then serialize, like this:
Foo foo = new Foo();
// ...populate foo here...
var builder = new System.Text.StringBuilder();
XmlSerializer s = new XmlSerializer(typeof(Foo));
using ( var writer = System.Xml.XmlWriter.Create(builder))
{
s.Serialize(writer, foo, ns);
}
string rawXml = builder.ToString();
This example serializes into a string. Of course you can serialize to other XmlWriters, you can write out to a file, to any arbitrary stream, and so on.
Normally I tweak the serialization to omit the XML declaration, omit the default xml namespaces, and so on. Like this:
Foo foo = new Foo();
// ...populate foo here...
var builder = new System.Text.StringBuilder();
var settings = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
var ns = new XmlSerializerNamespaces();
ns.Add("","");
XmlSerializer s = new XmlSerializer(typeof(Foo));
using ( var writer = System.Xml.XmlWriter.Create(builder, settings))
{
s.Serialize(writer, foo, ns);
}
string rawXml = builder.ToString();
You can also do the reverse - map from an XML document to an in-memory object graph - using the XmlSerializer. Use the Deserialize method.
A post I wrote a while ago may be of interest to you. I had to work with BizTalk and found that generating my classes from an XSD and then serializing that class over the wire (wa-la XML) worked quite well!
http://blog.andrewsiemer.com/archive/2008/04/30/accepting-xmldocuments-from-biztalk-de-serializing-them-to-xsd-generated-serializable.aspx
This allows you to work with the data as a class and all the perks that go along with that. And it totally allows you to bypass the XML writers!
Such a great reference ..
http://msdn.microsoft.com/en-us/library/x6c1kb0s%28v=vs.110%29.aspx
I just generated classes with fields for csharp:
First you open visual studio command prompt (programs->visualStudio->visualstudioTools->VisualstudioCommandPrompt)
Then you change to the directory of your xsd file and then run the following command:
xsd /classes /fields /language:CS MyXSDSCHEMAFILE.xsd
(replace the MyXSDSCHEMAFILE.xsd with your xsd file name)
After your cs file is created, copy it into your project folder where all the other cs file are and add it to the project in visual studio by right clicking the project and adding existing item. Once that is completed go to your code segment where you want to use your class and initialize like this (classname is the class that was created in the cs file):
classname myvariablename = new classname(); // so easy :)
// now you just fill with content
myvariablename.whatever.andever.field = "JaWerHatDasErfunden";// you just set a field
then serialize as xml (tons of examples on the web )
Useful Hint:
Be aware that instantiation is not always part of the xsd created classes.
Make sure you create your objects properly to avoid Null Pointer exceptions.
You can create the XML and then run it through an Xml Schema Validator that I wrote.

Categories

Resources