Converting SOAP XMLString to C# object - c#

[Question Modified] I am completely new to XML and am calling a web service(WCF). The request is expected to be in the below format:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:CreateLead>
<!--Optional:-->
<tem:xDoc>
<lead>
<![CDATA[<CreateLead>
<FIRSTNAME>John</FIRSTNAME>
<LASTNAME>Doe</LASTNAME>
<MOBILE>9999999999</MOBILE>
<EMAIL>john#doe.com</EMAIL>
<SOURCE>Website</SOURCE>
<SUBSOURCE>Blog</SUBSOURCE>
<WEBREMARKS></WEBREMARKS>
<TIMETOCALL>26/02/2018 18:40:15 PM</TIMETOCALL>
<FAILEDSTEP>Step 1</FAILEDSTEP>
<FOILIONO>123</FOILIONO>
<SCHEMECODE>123</SCHEMECODE>
<AMOUNT>100</AMOUNT>
<REGEVENT></REGEVENT>
<FEEDBACK></FEEDBACK>
</CreateLead>
]]>
</lead>
</tem:xDoc>
</tem:CreateLead>
</soapenv:Body>
</soapenv:Envelope>
I have created the proxy class and the below is the signature of the method to be called:
public System.Xml.XmlElement CreateLead(System.Xml.XmlElement xDoc)
{
return base.Channel.CreateLead(xDoc);
}
I am passing the complete SOAP as a string literal and converting it into an XMLElement and am getting a proper response. I wish to pass it as a C# object. Is there a way to create a class according to my above SOAP request?
I tried copying the XML and using Visual Studio's paste special to Paste XML as class but it is somehow not creating an exact replica of the above mentioned SOAP XML.
I need it to be completely similar to the above SOAP format.
Please help.

Related

Implement SOAP 1.2 service in asp.net core

I'm trying to implement OCPP 1.5 under ASP.Net Core 2.2. The standard makes use of SOAP 1.2. The issue comes from poor interpretation of the MessageHeader attribute. Properties with MessageHeader should be in header, but they are not.
Source code: https://github.com/delianenchev/OcppDemo
I use SoapCore under ASP.Net Core. My initialization looks like this:
var transportBinding = new HttpTransportBindingElement();
var textEncodingBinding = new TextMessageEncodingBindingElement(MessageVersion.Soap12WSAddressingAugust2004, System.Text.Encoding.UTF8);
var customBinding = new CustomBinding(transportBinding, textEncodingBinding);
app.UseSoapEndpoint<ISampleService>("/SOAP/service.wsdl", customBinding, SoapSerializer.DataContractSerializer);
My demo model with the MessageHeader and MessageBodyMember attributes.
[MessageContract]
public class MessageModelRequest
{
[MessageHeader]
public string Id { get; set; }
[MessageBodyMember]
public string Name { get; set; }
[MessageBodyMember]
public string Email { get; set; }
}
I test API with SoapUI.
This is my API under ASP.NET core with SoapCore.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/" xmlns:mod="http://schemas.datacontract.org/2004/07/Models">
<soap:Header/>
<soap:Body>
<tem:TestMessageModel>
<!--Optional:-->
<tem:inputModel>
<!--Optional:-->
<mod:Email>?</mod:Email>
<!--Optional:-->
<mod:Id>1</mod:Id>
<!--Optional:-->
<mod:Name>?</mod:Name>
</tem:inputModel>
</tem:TestMessageModel>
</soap:Body>
</soap:Envelope>
Correct API from WCF project for IIS.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header>
<tem:Id>34</tem:Id>
</soapenv:Header>
<soapenv:Body>
<tem:MessageModelRequest>
<!--Optional:-->
<tem:Email>3</tem:Email>
<!--Optional:-->
<tem:Name>4</tem:Name>
</tem:MessageModelRequest>
</soapenv:Body>
</soapenv:Envelope>
Well, judging by the source code of SoapCore it seems to support message headers for reading the SOAP message as it uses MessageEncoder for that purpose which knows exactly how to read a SOAP message, but when it comes to serializing a response in your case it uses a native DataContractSerializer for writing the body that ignores any message contract attributes you have on your class and furthermore it doesn't have any part for writing header, just the message body.
So I guess you need to implement the header support in response messages by yourself.
First of all, add IgnoreMemberAttribute (or XmlIgnoreAttribute if you switch to SoapSerializer.XmlSerializer) on the properties you intend to add to your response message header so that data contract serializer doesn't add them to the body of the message.
Finally, you will need to locate the properties decorated with MessageHeader attribute manually and add them to your header. Luckily SoapCore has multiple options for doing that as suggested here.
As alternative if you plan to include the source of SoapCore in your solution, you could easily achieve the goal somewhere along these lines. It's easy to do so because at this place you have the full control of the message and the response you got from your service method. With the aid of reflection, you can easily find the properties of responseObject which need to be moved to the header and just forward them to responseMessage.Headers.
I know it's a bit nasty, but well... this is the price of using SOAP in .NET Core.
In .NET 6, you can, for example, do the following to switch to SOAP 1.2 (a.k.a. soap12):
// In Program.cs ...
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// ...
app.UseSoapEndpoint<IMyServiceContract>("/MyService.asmx", new SoapEncoderOptions()
{
// Use SOAP version 1.2 (aka Soap12)
MessageVersion = MessageVersion.Soap12WSAddressingAugust2004
// - OR -
MessageVersion = MessageVersion.Soap12WSAddressing10
}, caseInsensitivePath: true);
That will result in:
<wsdl:definitions xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" ...>

How Do I Change XML Prefix For WCF Client Request c#?

Due to requirements from a web service that I have no control over, I need to change my ns prefixes from the defaults of "s" and "h". The service provider has provided a .wsdl file for my service reference, however, they do not appear to have an online wsdl for metadata exchange. I have emailed them and they confirmed that the prefixes have to be specific values (right or wrong on their part, I have to make this work).
Can someone please tell me the easiest way to change these values? Is there something I can modify in Reference.cs? Do I have to implement some sort of message formatting logic into my requests to change the values just prior to sending out the request?
Every element in the XML has to have a prefix of a specific value (2 values total), or the WS will not accept the request and simply returns HTML in the response. When I copy the request captured in Fiddler, over to SOAP UI and update the prefixes to what they require, the request works fine when executed from Soap UI. I'm simply not finding any simple solutions to this seemingly simple problem for c# VS 2017 development platform.
Also worth noting, when I load the .wsdl file into Soap UI, Soap UI generates all of the ws operations and requests with the correct, desired prefixes that I need in my c# app. How does Soap UI know the exact prefixes to generate in the requests?
I need to modify this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:FooListHeader xmlns:h="http://foo.foo.com/Hello" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<h:FooList>
<h:FooStatement>
<h:Title>Foo</h:Title>
<h:Value>123</h:Value>
</h:FooStatement>
</h:FooList>
</h:FooListHeader>
</s:Header>
<s:Body>
<GetFooRequestType xmlns="http://foo.foo.com/Hello">
<MessageRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ConFooRequest/>
</MessageRequest>
</GetFooRequestType>
</s:Body>
</s:Envelope>
To something like this:
<soapenv:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:foo="http://foo.foo.com/Hello">
<soapenv:Header>
<foo:FooListHeader xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<foo:FooList>
<foo:FooStatement>
<foo:Title>Foo</foo:Title>
<foo:Value>123</foo:Value>
</foo:FooStatement>
</foo:FooList>
</foo:FooListHeader>
</soapenv:Header>
<soapenv:Body>
<foo:GetFooRequestType xmlns="http://foo.foo.com/Hello">
<foo:MessageRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<foo:ConFooRequest/>
</foo:MessageRequest>
</foo:GetFooRequestType>
</soapenv:Body>
</soapenv:Envelope>
Example c# code:
public GetYaddaYaddaResponseType CheckConnection()
{
Yadda client = new Yadda();
var msgRequest = new GetYaddaYaddaResponseType { ConnectionConfirmationRequest = new ConfirmConnectRequestType() };
List<Statement> statementList = new List<Statement>
{
new Statement { Name = "Yo", Value = "123" },
new Statement { Name = "Hey", Value = "123" },
};
var header = new StatementHeader
{
StatementList = statementList.ToArray()
};
var response = client.GetYaddaYaddaMessage(ref header, msgRequest);
return response;
}

Webservice response with nullable doubles is not deserialized properly

I'm calling a webservice from one of our partners. I have no problem calling it and I get a result.
The response has nullable doubles. In fiddler I see in the XML of the response these doubles have values, but somehow these fields do not get deserialized to my proxy class because these fields have the value null there.
This is a summary of the response xml I get, somehow the value in id27 does not get serialized, but the boolean in id26 does. Why?
<extras soapenc:arrayType="ns2:Extra[16]" xsi:type="soapenc:Array">
<extras href="#id1"/>
<extras href="#id2"/>
...
</extras>
...
<multiRef id="id1" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns6:Extra" xmlns:ns6="http://model.bookingservice.app.traserv.com"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<assignments xsi:type="ns6:Assignment" xsi:nil="true"/>
<category xsi:type="xsd:string">def_Surety</category>
...
<orderUnit xsi:type="xsd:string">Verblijf</orderUnit>
<payAtLocation href="#id26"/>
<price href="#id27"/>
<priceNotes xsi:type="xsd:string" xsi:nil="true"/>
...
</multiRef>
...
<multiRef id="id26" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="xsd:boolean" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">true</multiRef>
<multiRef id="id27" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:double" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">345.0</multiRef>
I found WCF clients and axis webservice do have these problems.
You can solve it in the proxy, which is obviously not nice because you have to edit generated classes. Or you can change the webservice, which is also a problem because you have not always control over that one.
Anyway I found these items about it:
http://www.tomergabel.com/GettingWCFAndApacheAxisToBeFriendly.aspx
Why won't .NET deserialize my primitive array from a web service?

How to retrieve a collection out of an SOAP message

I'm using a webservice for render company information based on a special company number.
But i can not get data out of the response SOAP message.
You can see an example of the response soap message. (I left out some company information the tags).
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<businessGetDossierV3Response xmlns="http://www.webservices.nl/soap/">
<out>
<paging>
<curpage>1</curpage>
<perpage>10</perpage>
<numpages>1</numpages>
<numresults>1</numresults>
<maxresults>100</maxresults>
</paging>
<results>
<item>
<DossierNo></DossierNo>
<SubDossierNo></SubDossierNo>
<ChamberNo></ChamberNo>
<Legalformcode></Legalformcode>
<LegalformcodeText></LegalformcodeText>
<Tradename45></Tradename45>
<EstablishmentPostcode></EstablishmentPostcode>
<EstablishmentCity></EstablishmentCity>
<EstablishmentStreetname></EstablishmentStreetname>
<EstablishmentHouseNo></EstablishmentHouseNo>
<CorrespondencePostcode></CorrespondencePostcode>
<CorrespondenceCity></CorrespondenceCity>
<CorrespondenceStreetname></CorrespondenceStreetname>
<CorrespondenceHouseNo></CorrespondenceHouseNo>
</item>
</results>
</out>
</businessGetDossierV3Response>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
! this is the result i see on the demo client !
But this is my code in C#
nl.webservices.ws1.BusinessDossierV3PagedResult result = null;
result = myserviceBusiness.businessGetDossierV3(KVKnr, "0000", 1);
I want to do something like this (but with the results instead of paging part)
int page = result.paging.numpages;
Then I should be like this I suppose
string city = result.results.item.CorrespondenceCity;
But this is giving a fault message
So in Visual studio 2010, i can only retrieve the data in the paging part of the xml and put it into a textbox, but not from results part. Is this because the result part is some kind of Collection?
So yes, how can i put the data from the tags EstablishmentPostcode and EstablishmentCity in a textbox on my default page?
thanks in advance
You could try adding your SOAP service as a web reference to the project. http://msdn.microsoft.com/en-us/library/tydxdyw9.aspx
If you don't want to do this and would rather work on the XML directly you could use xpath to get access to all the item elements in your results element.
http://www.stardeveloper.com/articles/display.html?article=2009031001&page=1
One thing to be careful of when using xpath is that you use the correct xml namespace for the node you're trying to select.
Ben

Problem deserializing soap message on call back

I am implementing a WCF .NET service that is called back by another service.
The soap message that the call back service sends back is below
The SOAP Message
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:getAccountBalance soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://service.company.x.y">
<param0 xsi:type="xsd:string">123-K</param0>
<param1 xsi:type="xsd:string">551003</param1>
<param2 xsi:type="xsd:string">123</param2>
<param3 xsi:type="xsd:string">1231</param3>
<param4 xsi:type="xsd:string">ug</param4>
<param5 xsi:type="xsd:string">x</param5>
<param6 xsi:type="xsd:string">1.0</param6>
</ns1:getAccountBalance>
</soapenv:Body>
</soapenv:Envelope>
The WCF contract to receive the messae
[OperationContract(Action="")]
AccountEnquiryResponse getAccountBalance(String param0, String param1, String param2, String param3, String param4, String param5, String param6);
The service implilmentation
[ServiceBehavior(Namespace = "http://service.company.x.y")]
public class MyService:IService
{
public AccountEnquiryResponse getAccountBalance(String param0, String param1, String param2, String param3, String param4, String param5, String param6)
{
return new AccountEnquiryResponse
The problem
When the call back returns the WCF service is unable to deserialize the SOAP message parameters - they are all null
A soap message that works
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<getAccountBalance xmlns="http://service.company.x.y">
<param0>123</param0>
<param1>123</param1>
<param2>uid</param2>
<param3>pwd</param3>
<param4>en</param4>
<param5>ug</param5>
<param6>1.0</param6>
</getAccountBalance>
</s:Body>
</s:Envelope>
My conclusion
The difference between the SOAP message that works and the one that does not work are the properties soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" and xsi:type="xsd:string on the parameters and .NET is unable to deserialize the object properly because of them.
Is that true?
What can i do to solve this problem?
PS. the service that calls me back is a third party application written in JAVA and I have no control over the message format that is sent back to my application.
Please advise
Does .Net have an attribute for setting a namespace on the AccountEnquiryResponse object? That will solve both your problems.
If you're the server, what did the client use to generate their stubs? Did you give them a wsdl? or point them to your running server? If you gave them a wsdl, did you use that same wsdl to generate your service interface?
This looks realy like two sides not using the same interface. XML is really rather picky about fully qualified names.

Categories