WCF Request Formatting - c#

I am converting a legacy web service to a WCF service. This service currently is being used by front end application. But as of now the front end is not going to consume the new WCF service so instead we plan on rerouting the request to our new service. The catch here is that the new WCF service should be able handle the old input request and should be able to send back the response in the exact same format.
When I generate a wsdl and add it in the soapUI project. The Body is getting wrapped inside a tag with the method name ("UserVerification" is the Operation contract name), is there any way to handle this with out using message contracts(I am using legacy types for input parameters so cant change them)
Right now it is coming like this:
<soapenv:Body>
<wes:UserVerification>
<!--Optional:-->
<wes:userVerificationRequest wes:Direction="Request" >
</wes:userVerificationRequest>
</wes:UserVerificatio>
</soapenv:Body>
I want it to be like this
<soapenv:Body>
<wes:UserVerificationRequest wes:Direction="Request" >
</wes:UserVerificationRequest>
</soapenv:Body>

WCF by default uses the 'Wrapped' message style. If you want to be able to control how messages are serialized, you can define explicit messages by decorating with the MessageContractAttribute. With explicit message contracts, you can set the IsWrapped property to false.
In your case I think that EchoRequest and EchoResponse shouldn't be DataContracts at all, but rather MessageContracts. They look a lot like MessageContracts to me.
Using Message Contracts

Related

Read SOAP XML message sent as HTTP message body

I have a 3rd party that is sending SOAP XML messages, as the HTTP message body (using HTTP Post). I need to write a program to accept / process these messages.
I have a specification document which contains 2 WSDL definitions - GetTransaction and CutOff.
I am trying to use Postman to send a test message. Content-Type is set to application/xml and the body is set to raw / XML.
I am using C#, ASP.Net (4.7.2), the code is in a Class Library. I have a Controller (ApiController) with:
[HttpPost]
[ValidationAttributes.RequireHttps]
public HttpResponseMessage Service(XmlDocument reqData)
but reqData is always null. I have tried different types instead of XmlDocument.
Now if probably a good time to say that this is all new to me - I've not created a program to accept SOAP messages before.
Should I be creating a WCF Service Application (rather than a .Net Framework Class Library)?
I've tried adding the WSDL "definitions" but they don't seem to produce anything useful. E.g. there is reference to a "GetTransaction" method, but it has a parameter list of about 150 items!?
I have found quite a lot of stuff via Google but it always seems to be about sending, rather than receiving, SOAP messages.
I appreciate that I have not really included much code to look at, but I feel like I've started from the wrong place. So, any basic guidance, suggestions or links to tutorial sites would be most welcome.

Return XML when consuming a secure web service

I am currently trying to consume a generated report as a webservice to integrate some data into our system. Because the service itself is generated, the response can change frequently as things are added to it. While the endpoint and response may change, the request body will always be the same (taken from soapui):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<Execute_Report>
</Execute_Report>
</soapenv:Body>
</soapenv:Envelope>
I'm trying to figure out a way to make the above request for any endpoint (different reports) and allow for changes in the response. Ideally, I want to just return the raw XML of the response as I can allow for change easier with how I handle the XML if I'm not being tied to a data contract.
It is also worth noting that the service uses WS-Security and a Username/Password is passed as part of the request.
I've used WCF and the files generated from svcutil work great when I don't expect the service to change frequently. However because these webservices are generated change is expected, and if I can get away from it, I don't want to be at the mercy of re-generating a new file with svcutil whenever things change, or have to generate a file (and maintain) for all the different generated webservices.
At the end of the day the question is: How do I consume a webservice and return the raw XML while still being able to apply WS-Security to the request?
I kept searching around and found this answer:
.NET client authentication and SOAP credential headers for a CXF web service
This allowed me to do what I was after.

How to prepare web service and its classes based on example soap message

I got an example soap message:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/ xmlns:web="http://com.theirdomain/webservice">
<soapenv:Header/>
<soapenv:Body>
<web:Transaction>
<web:ID>123</web:ID>
<web:order>221x</web:order>
<web:trans>112-ax-21</web:trans>
<web:date>2013-01-01</web:date>
<web:title>Example title</web:title>
<web:amount>
<web:value>10.05</web:value>
<web:currency>USD</web:currency>
</web:amount>
<web:status>status</web:status>
<web:customer>
<web:address>Berlin</web:address>
<web:account>12345678901234567890123456</web:account>
</web:cusweb:customeromerData>
<web:docHash>HASHMD5</web:docHash>
</web:Transaction>
</soapenv:Body>
</soapenv:Envelope>
I need a tool or a way to quickly create a classic ASP.NET XML WebService with method NewTransaction which accepts a Transaction object. I would like to know if there is a way to quickly create class (or classes) that reflect the given soap. In the result my webservice address will be given to the other company from which they will generate WSDL and they want to call NewTransaction method with Transaction object defined in WSDL.
You can generate a WSDL and then generate a service and datacontracts from that WSDL.
It seems to be easier to just type the few properties and the single method you have in there in a new WCF Service project and fire it up. It's SOAP 1.1 so use basicHttpBinding.

Delphi SOAP Envelope and WCF

I am working on a system that provides a soap interface. One of the systems that are going to use the interface is coded in Delphi 7. The web service is developed with WCF, basic http binding, SOAP 1.1.
If I use SOAP UI (JAVA), the service works properly. But Delphi seems to do special things here ;)
This is how the message looks like in SOAP UI:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.xxx.de/xxx">
<soapenv:Header/>
<soapenv:Body>
<ser:GetCustomer>
<!--Optional:-->
<ser:GetCustomerRequest> <!-- this is a data contract -->
<ser:Id>?</ser:Id>
</ser:GetCustomerRequest>
</ser:GetCustomer>
</soapenv:Body>
</soapenv:Envelope>
I am not a delphi developer , but I developed a simple test client to see what's going wrong. This what Delphi sends as a SOAP envelope.
<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" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:NS2="http://services.xxx.de/xxx">
<NS1:GetCustomer xmlns:NS1="http://services.xxx.de/xxx">
<GetCustomerRequest href="#1"/>
</NS1:GetCustomer>
<NS2:GetCustomerRequest id="1" xsi:type="NS2:GetCustomerRequest">
<Id xsi:type="xsd:int">253</Id>
</NS2:GetCustomerRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
WCF throws an error that is in German language... ;)
Es wurde das Endelement "Body" aus Namespace "http://schemas.xmlsoap.org/soap/envelope/" erwartet. Gefunden wurde "Element "NS2:GetCustomerRequest" aus Namespace "http://services.xxx.de/xxx"". Zeile 1, Position 599.
Means something like
The Body was expected. But instead the Element "NS2:GetCustomerReques" was found.
Now my questions is: Can I somehow change the way Delphi creates the envelope? Or are the ways to make WCF work with such message formats? Any help is greatly appreciated!
Contrary to what some people here seem to be implying, Delphi is not sending invalid SOAP, it is simply sending RPC/Encoded SOAP. It's very easy to recognize from all the xsi:type attributes. RPC/Encoded is not WS-I compliant but it is still valid SOAP.
WCF, by default, uses the Document/Literal/Wrapped SOAP format, which Delphi 7 can't handle at all on the server side and you have to make some adjustments on the client side.
The simplest solution is to simply tell Delphi to use the Document/Literal style. You do that by turning on soLiteralParams in the THttpRio.Converter.Options. This tells Delphi not to "unwind" the parameters as you are seeing. The "Document" aspect is something that the Delphi WSDL importer can usually figure out so you shouldn't need to worry about that.
The other solution is to tell the WCF service to use RPC/Encoded style, which you can do by adding the following attributes to the service:
[ServiceContract]
[XmlSerializerFormat(Style = OperationFormatStyle.Rpc,
Use = OperationFormatUse.Encoded)]
public interface IMyService
{
// etc.
}
The second is not recommended because, as I mentioned earlier, RPC/Encoded is not WS-I compliant, but nevertheless most SOAP toolkits do recognize it, so I list it here as a possibility.
I just did one of these, and I ended up with a series of stringreplace calls to alter my XML output to strip the in-line namespaces out and make it look like SoapUI's format. Yes it takes a lot of manual hacking to do that.
ex:
After you create the RIO, call your own BeforeExecute proc:
...
EEUPSERTRIO.OnBeforeExecute := self.RIO_BeforeExecute;
...
procedure TMyWrapper.RIO_BeforeExecute(const MethodName: string; var SOAPRequest: WideString);
{
Since Delphi isn't very good at SOAP, we need to fix the request so that the namespaces are correct.
Basically, you take what Delphi gives you and try it in SoapUI.
If yours doesn't work and SoapUI's version does, make yours look like theirs.
}
...
Now strip out the in-line Namespaces:
SOAPRequest := StringReplace(SOAPRequest,' xmlns:NS1="http://services.xxx.de/xxx"','',[rfReplaceAll,rfIgnoreCase]);
...
Lots of these.
Then you'll replace the soap header with one that contains the namespaces that you want.
SOAPRequest := StringReplace(SOAPRequest,'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"','xmlns:ns1="http://services.xyzcorp.com/xyz/EnterpriseEmployeeService_1_0" '+'xmlns:ns1="http://schemas.xyzcorp.com/TLOIntegration_HRO_Preview/TLOIntegration_1_0" ',[]);
Then you can re-inject good ones:
ReplaceTag(SOAPRequest,'<metaData>','ns1:');
ReplaceTag(SOAPRequest,'<trackingId>','ns1:');
ReplaceTag(SOAPRequest,'<srcSystem>','ns1:');
Lastly, you can easily capture your Delphi output by re-consuming the WSDL with SoapUI and having it host a mockservice. Then point your app to it as the endpoint, and it'll capture the ouput.
Or, you can use Fiddler as a proxy, to capture requests.
Delphi and Java frameworks use different name space. One way to make if compatible is to intercept the raw xml and change all the "NS2" to whatever the deserializer expects
Cheers

WCF proxy generated from WSDL, proxy method returns null

I've generated a WCF proxy from a WSDL file, but now when I call the proxy methods, they return null. I've enabled message logging, and can see that the messages from the server are correctly returned.
I've checked the answer of this question, but in my case at least the name of the returned object was the same in the message and in the WSDL. I still believe the problem has to do with the WSDL file, since it is not fetched the usual way through the "?wsdl" URL (it is a 3rd party webservice), but was given separately.
The return type of the method is just a string.
Has anyone else had similar problems, and what was the corresponding solution, if any? What is the most likely source of the problem?
Re-edit:
It is a RPC/Encoded web service. As written, I can see the SOAP response through message logging, but WCF seems not to be able to parse the information.
The message part of the response from the service looks like this:
<ns1:ServiceResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="the target namespace">
<ns1:ReturnValue xsi:type="xsd:string">
However, when inspecting the outgoing message from my client, it's different:
<ns1:ServiceRequest soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="the target namespace">
<RequestValue xsi:type="xsd:string" xmlns="">
So maybe the proxy expects the response to have the same namespace structure, and thus fails to parse it.
I've tried to change the type attribute to element in the wsdl message definitions, and adding some new elements in the types part of the wsdl definition, but then the svcutil chokes when generating the proxy, complaining that there's a clash between the inferred style document and specified style rpc.
From the WSDL specification, section 3.5:
If use is encoded, then each message part references an abstract type using the type attribute.
But then I'm a bit confused, since it doesn't seem to have been a problem in this question. What would be needed to make a similar change, with the restriction that it is a RPC/encoded service?
You'll have to give specifics about the Java service in order to resolve this. However, I suspect that the Java service is using message parts defined with the type attribute. These do not conform to WS-I Basic Profile 1 because there is ambiguity about which namespace should be used for the elements of the message. Some services will use the namespace of the type, while others will (correctly) use the namespace of the web service itself.
Using the element attribute removes the ambiguity, and is therefore preferred.
Please post a snippet of the WSDL containing one of the messages you're having trouble with. When you then compare the definition of the message with what you're seeing on the wire, and then compare that to the details of the proxy class that's meant to consume the message, I believe you'll see what I mean. The proxy class is expecting one namespace, but on the wire, a different namespace is being used.
We have had something similar when using a WCF client against a WSDL from a Java web service.
Our problem was that we could not see the data that was coming back from the service, it looked like the data was missing.
However, when we looked at what was going over the wire, the data was there.
The problem was that the WSDL had many types that inherited from other types. By default we would only see the information in the base type.
The solution was to cast the object to the type we expected, then all the fields appeared.

Categories

Resources