How is the OperationContractAttribute.Action value is set? - wsdl

I'm using the "Add Service Reference" option in Visual Studio in order to create a proxy class using a WSDL file given to me by a third party.
I got 2 versions of the WSDL - we'll call them "OLD" and "NEW".
Even though the WSDL files suppose to be the same (the new one got updated methods version) , when creating the proxy classes I get a different values in the OperationContractAttribute.Action.
In the OLD wsdl it looks like that:
[System.ServiceModel.OperationContractAttribute(Action="http://webservices.amadeus.com/SATRQT_13_2_1A", ReplyAction="*")]
In the new wsdl it looks like that:
[System.ServiceModel.OperationContractAttribute(Action="http://xml.amadeus.com/AmadeusWebServicesPT/Air_MultiAvailabilityRequest", ReplyAction="http://xml.amadeus.com/AmadeusWebServicesPT/Air_MultiAvailabilityResponse")]
I can't figure it out from where the "Action" value is taken from.
In the old WSDL the value is valid , but in the new WSDL is completely wrong and I get an exception when trying to use the service in the WS
When I look in the OLD wsdl file i can see a "soapAction" with the same value; this seems to be where it's taken from. However in the NEW wsdl there is a value there exactly like in the OLD wsdl
<wsdl:operation name="Air_MultiAvailability">
<soap:operation soapAction="http://webservices.amadeus.com/SATRQT_13_2_1A" />
Can anyone direct to me to the right place?
Update
After reading some more on the "Action" element I realized that the value that I see in the NEW wsdl is the DEFAULT value (see https://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontractattribute.action(v=vs.110).aspx)
Now I need to understand WHY in the OLD wsdl file we get the Action value to be the correct one (I'm guessing from the soapAction defined in the wsdl file under the correct operation) and in the NEW wsdl there is no match and a default value is populated ?

ok found the problem!
in the WSDL file there were multiple "Operation" with the same name
<wsdl:portType name="WebServices">
<wsdl:operation name="DoSomething">
<wsdl:input message="ns:DoSomething_1_1" />
<wsdl:output message="ns:DoSomething_1_1" />
</wsdl:operation>
<wsdl:operation name="DoSomething">
<wsdl:input message="ns:DoSomething_2_2" />
<wsdl:output message="ns:DoSomething_2_2" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding type="ns:WebServices" name="WebServicesBinding">
<wsdl:operation name="DoSomething">
<soap:operation soapAction="http://webservices.my.com/DoSomething_1_1" />
</wsdl:operation>
<wsdl:operation name="DoSomething">
<soap:operation soapAction="http://webservices.my.com/DoSomething_2_2" />
</wsdl:operation>
</wsdl:binding>
the "DoSomething" got 2 version in this example 1.1 and 2.2
once i deleted\renamed ALL duplicated operations (i had multiple of them) the "Action" value was taken from the "soapAction" element
hope this will help someone in the future !

Related

Ruby(2.0) & Savon(2) SOAP client - returning nil SOAP operation

I am trying to integrate my rails app with SOAP based web-service.
Being a novice in SOAP, I referred this to get started.
My First step was to create a client using Savon:
client = Savon.client(wsdl: "https://xxxx.xxxx.xxxx/Reg/ABCRegService.svc?wsdl")
Now, when I do client.operations, I get a []
The wsdl looks something like this(I have masked value fields for security)
<wsdl:definitions name="some_name" targetNamespace="some_targetNamespace">
<wsdl:import namespace="some_Namespace1" location="some_nameService.svc?wsdl=wsdl0"/>
<wsdl:types>
<xsd:schema targetNamespace="some_targetNamespaceImports">
<xsd:import schemaLocation="http://example.net/some_name/some_Service.svc?xsd=xsd0" namespace="some_targetNamespace"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="some_name_RegisterTool_InputMessage">
<wsdl:part name="parameters" element="tns:RegisterTool"/>
</wsdl:message>
<wsdl:message name="some_name_RegisterTool_OutputMessage">
<wsdl:part name="parameters" element="tns:RegisterToolResponse"/>
</wsdl:message>
<wsdl:message name="UnregisterToolRequest">
<wsdl:part name="parameters" element="tns:UnregisterToolRequest"/>
</wsdl:message>
<wsdl:message name="UnregisterToolRequest_Headers">
<wsdl:part name="AuthenticationHeader" element="tns:AuthenticationHeader"/>
</wsdl:message>
<wsdl:message name="UnregistrationResult">
<wsdl:part name="parameters" element="tns:UnregistrationResult"/>
</wsdl:message>
<wsdl:portType msc:usingSession="false" name="some_name">
<wsdl:operation name="RegisterTool">
<wsdl:input wsaw:Action="some_targetNamespacesome_name/RegisterTool" message="tns:some_name_RegisterTool_InputMessage"/>
<wsdl:output wsaw:Action="some_targetNamespacesome_name/RegisterToolResponse" message="tns:some_name_RegisterTool_OutputMessage"/>
</wsdl:operation>
<wsdl:operation name="UnregisterTool">
<wsdl:input wsaw:Action="some_targetNamespacesome_name/UnregisterTool" name="UnregisterToolRequest" message="tns:UnregisterToolRequest"/>
<wsdl:output wsaw:Action="some_targetNamespacesome_name/UnregisterToolResponse" name="UnregistrationResult" message="tns:UnregistrationResult"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:service name="some_name">
<wsdl:port name="WSHttpBinding_some_name" binding="i0:WSHttpBinding_some_name">
<soap12:address location="https://example.net/Dcsome_name/some_nameService.svc"/>
<wsa10:EndpointReference>
<wsa10:Address>https://example.net/Dcsome_name/some_nameService.svc</wsa10:Address>
<Identity>
<Dns>localhost</Dns>
</Identity>
</wsa10:EndpointReference>
</wsdl:port>
</wsdl:service>
I looked into similar questions such as this. When I tried creating client in the suggested manner
client = Savon.client(
endpoint: 'proper_endpoint',
soap_action: "proper_soap_action",
namespace: 'proper_namespace',
convert_request_keys_to: :camelcase,
env_namespace: :soapenv
)
,I got:
:in `method_missing': Unknown global option: :soap_action (Savon::UnknownOptionError).
Any Ideas on how to get through this?
Environment:
OS:Windows 7(Installed rails using RailsInstaller)
Ruby version: 2.0.0
Savon: 2
Rails 4.1.8
Update:
I tried hitting the same WSDL from SOAPUI.
To make it work in SOAPUI,
I had to
set WS-Addressing property to true,
Check the checkbox for Add default wsa:to,
Use <![CDATA[]> to pass identifiers parameters.
Any leads on how to set these things in while creating Savon client?
Your process of retrieving operations of the wsdl is perfectly right. I checked the wsdl in 'Soap UI' & it seems like that the WSDL has some error. And this is why you are not getting any operations as the wsdl is not providing any definition.
Error loading [https://xx.xxxx.xxx/DcRegistration/DCRegistrationService.svc?wsdl=wsdl0]: java.io.IOException: Attempted read from closed stream
The issue was due to incorrect parsing of WSDL. In the wasabi gem, lib/parser.rb on line 136, the current XPATH search is:
wsdl:definitions/wsdl:binding/wsdl:operation', 'wsdl' => WSDL
However, the WSDL I am referring has elements organised differently and I had to tweak the above line to:
'wsdl:definitions/wsdl:portType/wsdl:operation', 'wsdl' => WSDL
Here is a link for the same issue in github: https://github.com/savonrb/savon/issues/702

How to compare two WSDL files located in separate Web servers

I'm using some legacy .asmx files. I need to compare if the WSDL from a Web Service located in Server A is exactly the same as WSDL in Server B.
The problem here is that when I get the ?wsdl as XML and perform the comparison (using WinMerge or C# code), then both files are going to be different.
For instance, if you look at this WSDL file : http://www.webservicex.net/globalweather.asmx?wsdl , you will find some information in the WSDL that belongs to this server exclusively :
<wsdl:service name="GlobalWeather">
<wsdl:port name="GlobalWeatherSoap" binding="tns:GlobalWeatherSoap">
<soap:address location="http://www.webservicex.net/globalweather.asmx"/>
</wsdl:port>
<wsdl:port name="GlobalWeatherSoap12" binding="tns:GlobalWeatherSoap12">
<soap12:address location="http://www.webservicex.net/globalweather.asmx"/>
</wsdl:port>
<wsdl:port name="GlobalWeatherHttpGet" binding="tns:GlobalWeatherHttpGet">
<http:address location="http://www.webservicex.net/globalweather.asmx"/>
</wsdl:port>
<wsdl:port name="GlobalWeatherHttpPost" binding="tns:GlobalWeatherHttpPost">
<http:address location="http://www.webservicex.net/globalweather.asmx"/>
</wsdl:port>
</wsdl:service>
So the location is going to be different between servers.
Do you know any approach to achieve this task? And yes, ideally I want to do via C# code, by getting the WSDL from both servers and comparing them.

Delphi XE2 HTTPRIO Unable to retrieve the URL endpoint for Service/Port

I am converting a Delphi 2007 program to Delphi XE2 and having a problem with the following error message:
Unable to retrieve the URL endpoint for service/port "/" from WSDL 'http://.....'
The service I am connecting to is written in Delphi 2007.
On 2007 it compiles and runs without problems.
On XE2 with the same code it falls over with the error.
I have tried re-importing the interface using the new WSDL importer with defaults set but no joy.
I have also tried setting the port and service names and the error persists. Not sure what info is of use but as far as I can tell it is connecting.
This is the operation of the method that I am using
<operation name="CheckRegistration">
<soap:operation soapAction="urn:ScubaUpdateWSIntf-IScubaUpdateWS#CheckRegistration" style="rpc"/>
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ScubaUpdateWSIntf-IScubaUpdateWS"/>
</input>
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ScubaUpdateWSIntf-IScubaUpdateWS"/>
</output>
</operation>
This is the message:
<message name="CheckRegistration10Request">
<part name="centreId" type="xs:int"/>
<part name="centreName" type="xs:string"/>
<part name="checkActiveOnly" type="xs:boolean"/>
</message>
<message name="CheckRegistration10Response">
<part name="return" type="xs:boolean"/>
</message>
Apart from importing the WSDL, throwing on an HTTPRIO and calling the method with
(HTTPRIO1 as IScubaUpdateWS).CheckRegistration(strtoint(tcentre),tcentreName,true);
I don't think I am doing anything else and as I say the same code works on Delphi 2007.
Solved. Well sort of!
Seems like Delphi XE2 is finding 2 services where as Delphi 2007 is finding one.
The program I am using is reading the WSDL location from the registry and setting it. On Delphi 2007 it is fine because it is taking the one and only service and making that selected port/service. On Delphi XE2 it is resetting the WSDL location has results in the port and service being cleared.
Thanks to #JohnEasley for pointing me in the right direction.
To solve I am now having to use the following code after changing the WSDL location.
Not sure it will work for every one as I am assuming the first entry is the one that is required
servicenames:=Tdomstrings.Create;
portnames:=Tdomstrings.Create;
HTTPRIO1.WSDLItems.GetServices(servicenames);
if servicenames.count>0 then
begin
HTTPRIO1.Service:=servicenames[0];
HTTPRIO1.WSDLItems.GetPortsForService(servicenames[0],portnames);
if portnames.count>0 then
HTTPRIO1.Port:=portnames[0];
end;
servicenames.clear;
servicenames.Free;
portnames.clear;
portnames.Free;
Thanks guys
in delphi 10.3 you must set "HTTPRIO1"'s property "Port" and "WSDLLocation" explicitly at runtime.
for sample in form "create" event:
HTTPRIO1.WSDLLocation:=defWSDL;
//HTTPRIO1.URL:=defURL;
//one of URL or WSDLLocation is enough.
HTTPRIO1.Service:=defSvc;
HTTPRIO1.Port:=defPrt;
Thanks

How to consume a webservice in MVC?

I am super new to MVC (in fact, this is my first assignment)
So, I have a good webservice running, functional, on my local machine
http://www.codetrials.local/wcf/UserServices.svc?wsdl
and In my MVC application, I added a service reference as usual, and then in my Model.cs I am trying this:
using (CodeTrials.UserServicesClient _client = new UserServicesClient())
{
UserWebsite = _client.GetUserWebsite(username);
}
but when I try to run this, I always get the exception endpoint not found. I can access this from my (different) asp.net project and it works just fine, same code and everything. After some digging around I found this answer I modified my above code to:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://www.codetrials.local/wcf/UserServices.svc");
using (CodeTrials.UserServicesClient _client = new UserServicesClient(binding, address))
{
UserWebsite = _client.GetUserWebsite(username);
}
but now, I get a new exception: There was no endpoint listening at http://www.codetrials.local/wcf/UserServices.svc?wsdl that could accept the message
So I am at my wits end.
I found a similar question but it's not what I am looking for.
Can you please guide me to the right path?
what am I not doing right?
should I shift the consuming of webservice from Model to Controller?
Thanks.
EDIT - This is my config file system.serviceModel section. I just copy pasted it from the WCF client test gui tool into web.config since it was not being generated by visual studio.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IUserServices" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://www.codetrials.local/wcf/UserServices.svc/wcf/UserServices.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IUserServices"
contract="IUserServices" name="BasicHttpBinding_IUserServices" />
</client>
</system.serviceModel>
Reposting from the comments since it turned out to be the answer. :) Turned out that web.debug.config was overwriting the web.config in this case.
Are you sure its in the right web.config then? VS should create it automatically when you add the service reference (it does for me at least). One gotcha is that a normal MVC app has two web.config files, there's a second one inside the Views folder by default. Other then that, I'm not really sure whats going on.
Your code shows you are using this URL: http://www.codetrials.local/wcf/UserServices.svc to access the service endpoint but your exception message says you are actually using http://www.codetrials.local/wcf/UserServices.svc?wsdl instead.
Check your MVC app web.config file for a serviceModel element. If you need to configure the WCF client in code then remove that entire element from the web.config file which may be where the wrong URL is coming from. If you do want to configure WCF from the web.config file, then remove your current code and use the following two lines to create the client and invoke the service:
var _client = new UserServicesClient("BasicHttpBinding_IUserServices");
UserWebsite = _client.GetUserWebsite(username);
where the something like the following section exists in your web.config serviceModel element:
<system.serviceModel>
<client>
<endpoint
name="BasicHttpBinding_IUserServices"
address="http://www.codetrials.local/wcf/UserServices.svc"
binding="basicHttpBinding"
contract="IUserServices" >
</endpoint>
</client>
<!-- rest of element snipped -->
Finally, you should not wrap the UserServicesClient instantiation in a using statement because of the reasons outlined in this post. WCF is a tricksty beast....
EDIT:
Based on the update with your config, your problem may be that the service URL is:
http://www.codetrials.local/wcf/UserServices.svc/wcf/UserServices.svc
The wcf/UserServices.svc seems to be duplicated.

Why WSDL introduce wsdl:message?

Why WSDL introduces wsdl:message? And message parts?
What the advantage they could bring over the direct using of the XSD in the operations parameters (input, output, fault)?
How they (wsdl messages with wsdl message parts) can be more abstract then XSD?
Why it is not organized for example that way:
<operation name="GetEndorsingBoarder">
<input type="xsd:string"/>
<output type="xsd:string, xsd:int, xsd:boolean"/>
<fault "type="xsd:string""/>
</operation>
I got it:
Messages not just specify operation's parameters.
Messages and theirs parts are referred in the bindings. It should be possible to bind different parts differently:
<message name="m1">
<part name="body" element="tns:GetCompanyInfo"/>
</message>
<message name="m2">
<part name="body" element="tns:GetCompanyInfoResult"/>
<part name="docs" type="xsd:string"/>
<part name="logo" type="tns:ArrayOfBinary"/>
</message>
<portType name="pt1">
<operation name="GetCompanyInfo">
<input message="m1"/>
<output message="m2"/>
</operation>
</portType>
<binding name="b1" type="tns:pt1">
<operation name="GetCompanyInfo">
<soap:operation soapAction="http://example.com/GetCompanyInfo"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<mime:multipartRelated>
<mime:part>
<soap:body parts="body" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="docs" type="text/html"/>
</mime:part>
<mime:part>
<mime:content part="logo" type="image/gif"/>
<mime:content part="logo" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
</output>
</operation>
</binding>
I have missed this since "non SOAP 'literal'" bindings are so uncommon.
A XSD describes the DATA aspects, for example data aspects of webservice call whereas the WSDL describes the purpose of the web services (method calls). You cannot typically figure out the method calls from your data alone.
Check out Cheeso and Marc answers on Generating a WSDL from an XSD file
EDIT: source
The message describes the data being exchanged between the web services' provider and consumer and each web service has two messages:
1) input: parameters of the web service
2) output: return data from the web service
Each message has zero or more part parameters (one for each parameter of the web service's function) Each part parameter associates with a concrete type defined in the types container element.
<message name="SayHelloRequest">
<part name="firstName" type="xsd:string"/>
</message>
<message name="SayHelloResponse">
<part name="greeting" type="xsd:string"/>
</message>
Here, two message elements are defined. The first represents a request message SayHelloRequest, and the second represents a response message SayHelloResponse.
Each of these messages contains a single part element. For the request, the part specifies the function parameters; in this case, we specify a single firstName parameter. For the response, the part specifies the function return values; in this case, we specify a single greeting return value.

Resources