Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a webservice from C# and sending unescaped xml

I am trying to integrate an application with a third party webservice. The signature of the method I have to call is something like this (generated by VS proxy generator):

string MyFoo(string param1, string param2, string param3, string someXml)

Now for the first 3 parameters there's no problem. The fourth parameter, as per vendor specifications, should contain "unescaped xml wrapped in a CDATA block", like this:

<![CDATA[<?xml version="1.0" encoding="utf-8"?><rootNode></rootNode>]]>

Now, c# escapes (as I would expect it to do) all the characters that must be escaped, mainly the "<" and ">" characters, even in the CDATA statement, resulting in something like this:

&lt;![CDATA[&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;rootNode&gt;&lt;/rootNode&gt;]]&gt;

As far as I know this is a correct behaviour, and there's no way to override it, as it could potentially generate a bad request (invalid soap message) and even a security issue.

Does anyone know if I'm missing out on something, not knowing something, or this is correct and the expectation of the third party webservice cannot be complied?

Thanks.

like image 351
Matteo Mosca Avatar asked Nov 02 '22 20:11

Matteo Mosca


2 Answers

I've been fiddling around the similar problem for > 2 days as of today. The only feasible solution that worked for me was to write service client (an interface and Client implementation) myself. This would be a problem if your service changes from time to time (you will not be able to regenerate/update your client with 3 clicks). Let me tell what I've done.

Simple and fast recipe:

  1. copy generated service client interface and name it something like IServiceClientExtended;
  2. in that interface change someXml parameter to XmlCDataSection someXml;
  3. in MyFoo method attributes change XmlSerializerFormatAttribute.Use to System.ServiceModel.OperationFormatUse.Literal from System.ServiceModel.OperationFormatUse.Encoded;
  4. Remove GeneratedCodeAttribute from that IServiceClientExtended attributes if you did not do that already;
  5. Create ServiceClient class (you can copy it from generated) and change interface it implements and inherits to ClientBase, IServiceClientExtended;
  6. Create all required methods (or copy it from generated) and change method signatures to suit that IServiceClientExtended interface (someXml should be XmlCDataSection, remember?);
  7. In your code, use that your created ServiceClient class with that someXml parameter converted to XmlCDataSection. You could do that like this:
XmlDocument doc = new XmlDocument();
var section = doc.CreateCDataSection(someXmlString);
string result = client.MyFoo(param1, param2, param3, section);
like image 90
V. Kasparavičius Avatar answered Nov 12 '22 21:11

V. Kasparavičius


V. Kasparavičius is right. But it is much simple, this just needs a little change in Reference.cs. The type of the parameter needs to be changed from string to XmlCDataSection.

private XmlCDataSection foo;

[System.Xml.Serialization.XmlElementAttribute(Order=2)]
public XmlCDataSection foo {
    get {
        return this.foo;
    }
    set {
        this.foo = value;
        this.RaisePropertyChanged("foo");
    }
}

And then add the parameter as XmlCDataSection

var xmlDocument = new XmlDocument(); var parameter = xmlDocument.CreateCDataSection("<foo></foo>");

like image 22
Pablo Carrasco Hernández Avatar answered Nov 12 '22 23:11

Pablo Carrasco Hernández