I am attempting to wrap a newer .net ASMX webservice so that it can be used by an older classic asp application. To do this I found some code to send the soap requests. However in my testing it seems that none of my parameters are reaching the server.
The Server Test Code
<WebMethod()> _
Public Function Ping1(str As String)
If str <> "" Then
Return str
Else
Return "False"
End If
End Function
The xml being sent:
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<Ping1 xmlns="http://tempuri.org">
<str>asdf</str>
</Ping1>
</soap12:Body>
</soap12:Envelope>
The page keeps returning "False" but as far as I can tell, this should be the right format to send parameters. Any help would be appreciated.
As demonstrated in this other question you should set proper headers when consuming the service:
oXmlHTTP.setRequestHeader "Content-Type", "application/soap+xml; charset=utf-8"
oXmlHTTP.setRequestHeader "SOAPAction", "http://ourNameSpace/Ping1"
Note that you can't use tempuri.org namespace, you have to also set your own namespace.
Related
Having a difficult time. Finding examples on, How to access an external web service using marklogic? (maybe my search terms are wrong? i also tried xdmp:http-get, xdmp:http-post, post http request, mash-up, orchestrate).
I first need to understand, How difficult (hopefully easy) it will be for me to write a script in MarkLogic to access one external (non-ML) web service and display the response before I proceed with combining results from 3 different web services (is the correct term for this mash-up?) in one page using ML.
An example using ML will be most appreciated. I have seen celsius to fahrenheit conversion examples, also stock quotes request and response but not in ML. I do not know how or where to start. Can you point me to right direction please. Eager to learn using ML for web services.
many thanks.
I'd say there are examples here: http://docs.marklogic.com/xdmp:http-post
But for the sake of completeness, let me add these as well:
Based on:
http://www.w3schools.com/xml/tempconvert.asmx?op=FahrenheitToCelsius
SOAP 1.1:
let $envelop :=
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<FahrenheitToCelsius xmlns="http://www.w3schools.com/xml/">
<Fahrenheit>100</Fahrenheit>
</FahrenheitToCelsius>
</soap:Body>
</soap:Envelope>
return
xdmp:http-post(
"http://www.w3schools.com/xml/tempconvert.asmx",
<options xmlns="xdmp:http">
<headers>
<Content-Type>text/xml; charset=utf-8</Content-Type>
<SOAPAction>"http://www.w3schools.com/xml/FahrenheitToCelsius"</SOAPAction>
</headers>
</options>,
$envelop
)
SOAP 1.2:
let $envelop :=
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<FahrenheitToCelsius xmlns="http://www.w3schools.com/xml/">
<Fahrenheit>100</Fahrenheit>
</FahrenheitToCelsius>
</soap12:Body>
</soap12:Envelope>
return
xdmp:http-post(
"http://www.w3schools.com/xml/tempconvert.asmx",
<options xmlns="xdmp:http">
<format xmlns="xdmp:document-get">xml</format>
<headers>
<Content-Type>application/soap+xml; charset=utf-8</Content-Type>
</headers>
</options>,
$envelop
)
HTTP POST:
let $body := text {
string-join(
("Fahrenheit=" || encode-for-uri(string(100))),
"&"
)
}
return
xdmp:http-post(
"http://www.w3schools.com/xml/tempconvert.asmx/FahrenheitToCelsius",
<options xmlns="xdmp:http">
<headers>
<Content-Type>application/x-www-form-urlencoded</Content-Type>
</headers>
</options>,
$body
)
HTH!
We connect with multiple (20-30) third-party web services within our C# Batch Application. We are attempting to find the best way to call these web services dynamically (without generating proxy or using wsdl). All the third party agencies endpoints or URL's will be configured in database table. Client app will check the URL at run-time and make a service call. We are not worried about async calls it’s all synchronized process.
SQL Table : Client-configuration
Client URL Method IsActive
A http://serverhost/ClientA/Service1.svc Submit 1
B http://serverhost/ClientB/Service2.asmx Submit 1
The only issue is we are not sure about the third party service implementation is WCF or asmx. I have read few articles online to use HttpWebRequest to call web services dynamically (without generating proxies/wsdl.)
Is this the best way to implement this or any concerns I need to think of?
Please see below ex:
public static void CallWebService(string xml)
{
var _Url = "http://serverhost/ClientA/Service1.svc";
var _action = "http://serverhost/ClientA/Service1.svc/Submit";
try
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] data = encoder.GetBytes(xml);
XmlDocument soapEnvelopeXml = CreateSoapEnvelope(xml);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(_Url);
webRequest.Headers.Add("SOAPAction", _action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.ContentLength = data.Length;
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
Stream webStream = webRequest.GetRequestStream();
webStream.Write(data, 0, data.Length);
webStream.Close();
WebResponse response = webRequest.GetResponse();
Stream responseStream = response.GetResponseStream();
using (StreamReader sr = new StreamReader(responseStream))
{
string s = sr.ReadToEnd();
}
}
catch (Exception ex)
{
responseStream = ex.Response.GetResponseStream();
}
}
Here is the details shared by one of the client.
http://setup.localhost.com/ClientA/Service1.asmx
Operation : Submit
SOAP 1.1
The following is a sample SOAP 1.1 request and response. The placeholders shown need to be
replaced with actual values.
POST /ClientA/Service1.asmx HTTP/1.1
Host: setup.localhost.com
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://setup.localhost.com/Submit"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Submit xmlns="http://setup.localhost.com/">
<eCitXML>string</eCitXML>
<eCitPdf>base64Binary</eCitPdf>
<eCitKey>string</eCitKey>
</Submit>
</soap:Body>
</soap:Envelope>
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<SubmitResponse xmlns="http://setup.localhost.com/">
<SubmitResult>string</SubmitResult>
</SubmitResponse>
</soap:Body>
</soap:Envelope>
SOAP 1.2
The following is a sample SOAP 1.2 request and response. The placeholders shown need to be
replaced with actual values.
POST /ClientA/Service1.asmx HTTP/1.1
Host: setup.localhost.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-
envelope">
<soap12:Body>
<Submit xmlns="http://setup.localhost.com/">
<eCitXML>string</eCitXML>
<eCitPdf>base64Binary</eCitPdf>
<eCitKey>string</eCitKey>
</Submit>
</soap12:Body>
</soap12:Envelope>
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-
envelope">
<soap12:Body>
<SubmitResponse xmlns="http://setup.localhost.com/">
<SubmitResult>string</SubmitResult>
</SubmitResponse>
</soap12:Body>
</soap12:Envelope>
I think your question could be rephrased as
Is there a generic method to call any SOAP 1.1 or 1.2 web service operation without prior knowledge of the service operation except for the SOAP action and URL?
I'm assuming that all the third party web services expose a common operation which accepts and returns the same types.
If this is the case then providing you model the service operation contract correctly you could use ChannelFactory to call all the services.
Calling WCF services is straightforward in this manner, but to call asmx services you'd need to do a bit more work. So your client code would need to know if the service was asmx or wcf, and moreover, if wcf, whether the service is soap 1.1 or 1.2.
I must say I'm struggling to understand what advantage you will have once you have achieved this. I can see the value if you owned all the 20+ services you were calling, but this clearly is not the case.
Granted, you won't have a ton of nasty generated service reference code, but the whole point of WSDL is it allows for machine generated service contracts. If the third party services make any breaking changes you'll need to manually synchronize these inside your client code, rather than just regenerating the client.
I am invoking an opportunity service, but ending with the following Error.
SOAP Response:
<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>Client</faultstring><detail><ErrorCode>SBL-ODU-01007</ErrorCode><ErrorMessage>The HTTP request did not contain a valid SOAPAction header
The value of the header was:
document/urn:crmondemand/ws/ecbs/opportunity/10/2004:OpportunityQueryPage</ErrorMessage></detail></soap:Fault></soap:Body></soap:Envelope>
I am using apache http client to invoke this service.
SOAP Request Msg:
<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns=\"urn:crmondemand/ws/ecbs/opportunity/10/2004\" xmlns:quer=\"urn:/crmondemand/xml/Opportunity/Query\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2002/07/secext\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"> <soapenv:Header><wsse:Security><wsse:UsernameToken><wsse:Username>XXXXXX</wsse:Username><wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">XXXXXXX</wsse:Password></wsse:UsernameToken></wsse:Security></soapenv:Header><soapenv:Body><ns:OpportunityQueryPage_Input><quer:ListOfOpportunity pagesize=\"100\" startrownum=\"1\" recordcountneeded=\"5\"><quer:Opportunity searchspec=\"[Owner] LIKE '*'\"><quer:Description sortorder=\"ASCE\"></quer:Description><quer:AccountName sortorder=\"ASCE\"></quer:AccountName><quer:cActual_Booking_ValueTCV_Mn></quer:cActual_Booking_ValueTCV_Mn></quer:Opportunity></quer:ListOfOpportunity></ns:OpportunityQueryPage_Input></soapenv:Body></soapenv:Envelope>
My Invocation URL:
https://secure-ausomxapa.crmondemand.com/Services/Integration
I am not able to find exactly where is the error. Kindly Help to fix this issue.
Here is an example which works for activities:
soapAction: '"document/urn:crmondemand/ws/ecbs/activity/10/2004:ActivityQueryPage"',
data: '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ActivityQueryPage_Input xmlns="urn:crmondemand/ws/ecbs/activity/10/2004"><ListOfActivity pagesize="20" xmlns="urn:/crmondemand/xml/Activity/Query"><Activity searchspec= "[Id] = \''+myTextBox.val()+'\'"><Id></Id><Subject></Subject><Type></Type><Priority></Priority><Description></Description><CommentsAction></CommentsAction><OwnerFullName></OwnerFullName><DelegatedBy></DelegatedBy></Activity></ListOfActivity></ActivityQueryPage_Input></soap:Body></soap:Envelope>',
callback: function (data) {}
For some reason SourceGear provide an undocumented Web service on their installations. They actually ask developers to use the API instead because the Web service is kinda messy, but this is a problem in my case because I cannot use this API on a Perl environment, so their solution for my specific case is to use the Web service.
This shouldn't be a problem. Using SOAP::Lite I have connected to several Web services in the past in the same way. But the lack of documentation is a major chaos if you don't know where the SOAP calls can be made. I only have an XML to decipher where to and how to make these calls. It would be great if a real SOAP genius could help me out in this.
This is an example of the login call and the expected response:
Request
POST /fortress/dragnetwebservice.asmx HTTP/1.1
Host: velecloudserver
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.sourcegear.com/schemas/dragnet/LoginPlainText"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<LoginPlainText xmlns="http://www.sourcegear.com/schemas/dragnet">
<strLogin>string</strLogin>
<strPassword>string</strPassword>
</LoginPlainText>
</soap:Body>
</soap:Envelope>
Response
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<LoginPlainTextResponse xmlns="http://www.sourcegear.com/schemas/dragnet">
<LoginPlainTextResult>int</LoginPlainTextResult>
<strAuthTicket>string</strAuthTicket>
</LoginPlainTextResponse>
</soap:Body>
</soap:Envelope>
I'm looking for a way to be able to assemble this somehow. This is my Perl example:
my $soap = SOAP::Lite -> uri ('http://velecloudserver/fortress/dragnetwebservice.asmx') -> proxy('http://velecloudserver/fortress/dragnetwebservice.asmx/LoginPlainText');
my $som = $soap->call('LoginPlainText', SOAP::Data->name('LoginPlainText')->value(
\SOAP::Data->value([
SOAP::Data->name('strLogin')->value( 'admin' ),
SOAP::Data->name('strPassword')->value('Adm1234'),
]))
);
Any tip would be appreciated.
Start by pointing wget/curl/lwp/etc. at http://velecloudserver/fortress/dragnetwebservice.asmx?WSDL
and see if you get a WSDL file back.
If you do, then compare it to the four types listed in the SOAP::Lite POD.
Your Request example looks like the Docment/Literal form, so you might end up writing something like this:
use SOAP::Lite;
my $soap = SOAP::Lite->new( file => 'http://velecloudserver/fortress/dragnetwebservice.asmx?WSDL');
$soap->on_action( sub { "urn:dragnetservice#LoginPlainText" });
$soap->autotype(0);
$soap->default_ns('urn:LoginPlainText');
my $som = $soap->call("LoginPlainText",
SOAP::Data->name('strLogin')->value( 'admin' ),
SOAP::Data->name('strPassword')->value('Adm1234'),
);
die $som->fault->{ faultstring } if ($som->fault);
print $som->result, "\n";
If you don't get WSDL back, I'd try replacing the constructor call with:
my $soap = SOAP::Lite->new( proxy => 'http://velecloudserver/fortress/dragnetwebservice.asmx');
The last time I worked with SOAP::Lite, I wrote a short program similar to the one above, and I ran it under the debugger. Before I executed the $soap->call() line, I peeked at the guts of the $soap object and looked at the request payload to see if the XML matched some working XML that I had by using the soapUI.org java client.
I had to read the POD a couple of times, and I dug into the source to figure our how some of the methods like default_ns() affected the generated XML. Once I did that, it all made a lot more sense.
Note: SOAP::Lite likes to die() when it fails. Wrap your calls in an eval{} for production use.
Has anyone gotten Bing Map Web Services (formerly Virtual Earth Web Services) working with Delphi?
Based on my experiences so far (both using Delphi and Visual Studio C#), I'm about ready to give up on it and go with the MapPoint Web Service until a future version of Bing Maps Web Services comes out. However, I thought I'd post a question here as a last resort...
I imported the Token Service and Geocode Services WSDL documents.
I was successfully able to get a token from the token service, but have been unable to get the Geocode service to work at all. It always returns the following error message:
The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
I noticed Delphi wasn't specifying a value for the SOAPAction header, so I tried specifying "http://staging.dev.virtualearth.net/webservices/v1/geocode/contracts/IGeocodeService/Geocode" and got the following error message instead:
The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.
Below is my Delphi code and the raw XML being sent, then the raw XML being sent by a similar call from Microsoft's sample C# code. There are several differences in the XML, but I'm not sure what difference(s) is the key.
var
Service: IGeocodeService;
Request: Geocode;
Response: GeocodeResponse3;
ResponseIndex: Integer;
Token: WideString;
Filters: ArrayOfFilterBase;
begin
Token := GetToken;
Service := GetIGeocodeService;
Request := Geocode.Create;
try
Request.request := GeocodeRequest.Create;
Request.request.Credentials := GeocodeService.Credentials.Create; // Freed by GeocodeRequest class
Request.request.Credentials.Token := Token;
Request.request.Query := AddressEdit.Text;
Request.request.Options := GeocodeOptions.Create;
SetLength( Filters, 1 );
Filters[ 0 ] := ConfidenceFilter.Create;
ConfidenceFilter( Filters[ 0 ] ).MinimumConfidence := GeocodeService.High_;
Request.request.Options.Filters := Filters;
Response := Service.Geocode( Request );
try
for ResponseIndex := Low( Response.GeocodeResult.Results ) to High( Response.GeocodeResult.Results ) do
begin
OutputMemo.Lines.Add( Response.GeocodeResult.Results[ ResponseIndex ].DisplayName );
end;
finally
Response.Free;
end;
finally
Request.Free;
end;
end;
<?xml version="1.0"?>
<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://dev.virtualearth.net/webservices/v1/geocode/contracts" xmlns:NS3="http://dev.virtualearth.net/webservices/v1/geocode" xmlns:NS4="http://dev.virtualearth.net/webservices/v1/common">
<NS1:Geocode xmlns:NS1="http://dev.virtualearth.net/webservices/v1/geocode/contracts">
<parameters href="#1"/>
</NS1:Geocode>
<NS2:Geocode id="1" xsi:type="NS2:Geocode">
<request href="#2"/>
</NS2:Geocode>
<NS3:request id="2" xsi:type="NS3:GeocodeRequest">
<Credentials href="#3"/>
<Options href="#4"/>
<Query xsi:type="xsd:string">Some Address</Query>
</NS3:request>
<NS4:Credentials id="3" xsi:type="NS4:Credentials">
<Token xsi:type="xsd:string">cbYkKgNlrsGnZbn3HRP7Xp5LJMv3RR_5qECwgB792COfY3EPmviaDpZ4mmD3fDP1Osc6fWUkTptog7bfgM73bA2</Token>
</NS4:Credentials>
<NS3:Options id="4" xsi:type="NS3:GeocodeOptions">
<Filters xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="NS3:FilterBase[1]">
<item href="#5"/>
</Filters>
</NS3:Options>
<NS3:ConfidenceFilter id="5" xsi:type="NS3:ConfidenceFilter">
<MinimumConfidence xsi:type="NS4:Confidence">High</MinimumConfidence>
</NS3:ConfidenceFilter>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<Geocode xmlns="http://dev.virtualearth.net/webservices/v1/geocode/contracts">
<request xmlns:a="http://dev.virtualearth.net/webservices/v1/geocode" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Credentials xmlns="http://dev.virtualearth.net/webservices/v1/common">
<ApplicationId i:nil="true"/>
<Token>pezCDpJoxdCG63NQdJUGkTrYYalnuSQDwuIC9FvheFAd9MIPO75qX9n7il0dx3eTEHlN2877PzN1_6YbQDL5tg2</Token>
</Credentials>
<Culture i:nil="true" xmlns="http://dev.virtualearth.net/webservices/v1/common"/>
<ExecutionOptions i:nil="true" xmlns="http://dev.virtualearth.net/webservices/v1/common"/>
<UserProfile i:nil="true" xmlns="http://dev.virtualearth.net/webservices/v1/common"/>
<a:Address i:nil="true" xmlns:b="http://dev.virtualearth.net/webservices/v1/common"/>
<a:Options>
<a:Count i:nil="true"/>
<a:Filters>
<a:FilterBase i:type="a:ConfidenceFilter">
<a:MinimumConfidence>High</a:MinimumConfidence>
</a:FilterBase>
</a:Filters>
</a:Options>
<a:Query>1 Microsoft Way, Redmond, WA</a:Query>
</request>
</Geocode>
</s:Body>
</s:Envelope>
My best guess is that Delphi seems to be producing too many Geocode elements - there doesn't appear to be any thing that corresponds to NS2:Geocode in the C# produced XML. If you can intercept the XML and change it so that it looks like this, who knows - it might work:
...
<NS1:Geocode xmlns:NS1="http://dev.virtualearth.net/webservices/v1/geocode/contracts">
<parameters href="#2"/>
</NS1:Geocode>
<NS3:request id="2" xsi:type="NS3:GeocodeRequest">
...
The other problem could be that the Bing service doesn't support the way Delphi organizes the SOAP request.
It that doesn't work, perhaps you can find another SOAP library you can use with Delphi - perhaps resorting to wrapping a library with a C or COM interface.
I have exatctly the same problem. I run Delphi 2006, used WSDLImp.exe in command mode; needed version 11.0 of 2006 to get the import work. What do you use? We have the intention to try RemObjects, version 6. Any guess if that would work better?
Cheers,
Lars