I'm trying to send a SOAP request to another group within my company. They have a service (with WSDL) created which is used by other groups. I'm trying to send the request though our database using UTL_HTTP, however every request I've sent returns a 400: Bad Request response.
The WSDL they have published looks like this:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions name="Query" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://tempuri.org/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">
<wsp:Policy wsu:Id="BasicHttpBinding_IQuery_policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false"/>
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Strict/>
</wsp:Policy>
</sp:Layout>
</wsp:Policy>
</sp:TransportBinding>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
<wsdl:types>
<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import schemaLocation="https://mydomain.com/MetWcfService/Query.svc?xsd=xsd0" namespace="http://tempuri.org/"/>
<xsd:import schemaLocation="https://mydomain.com/MetWcfService/Query.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
<xsd:import schemaLocation="https://mydomain.com/MetWcfService/Query.svc?xsd=xsd2" namespace="http://schemas.datacontract.org/2004/07/"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="IQuery_GetLatestValueForParameter_InputMessage">
<wsdl:part name="parameters" element="tns:GetLatestValueForParameter"/>
</wsdl:message>
<wsdl:message name="IQuery_GetLatestValueForParameter_OutputMessage">
<wsdl:part name="parameters" element="tns:GetLatestValueForParameterResponse"/>
</wsdl:message>
<wsdl:message name="IQuery_GetLatestValueForParameters_InputMessage">
<wsdl:part name="parameters" element="tns:GetLatestValueForParameters"/>
</wsdl:message>
<wsdl:message name="IQuery_GetLatestValueForParameters_OutputMessage">
<wsdl:part name="parameters" element="tns:GetLatestValueForParametersResponse"/>
</wsdl:message>
<wsdl:portType name="IQuery">
<wsdl:operation name="GetLatestValueForParameter">
<wsdl:input wsaw:Action="http://tempuri.org/IQuery/GetLatestValueForParameter" message="tns:IQuery_GetLatestValueForParameter_InputMessage"/>
<wsdl:output wsaw:Action="http://tempuri.org/IQuery/GetLatestValueForParameterResponse" message="tns:IQuery_GetLatestValueForParameter_OutputMessage"/>
</wsdl:operation>
<wsdl:operation name="GetLatestValueForParameters">
<wsdl:input wsaw:Action="http://tempuri.org/IQuery/GetLatestValueForParameters" message="tns:IQuery_GetLatestValueForParameters_InputMessage"/>
<wsdl:output wsaw:Action="http://tempuri.org/IQuery/GetLatestValueForParametersResponse" message="tns:IQuery_GetLatestValueForParameters_OutputMessage"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="BasicHttpBinding_IQuery" type="tns:IQuery">
<wsp:PolicyReference URI="#BasicHttpBinding_IQuery_policy"/>
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetLatestValueForParameter">
<soap:operation soapAction="http://tempuri.org/IQuery/GetLatestValueForParameter" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetLatestValueForParameters">
<soap:operation soapAction="http://tempuri.org/IQuery/GetLatestValueForParameters" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="Query">
<wsdl:port name="BasicHttpBinding_IQuery" binding="tns:BasicHttpBinding_IQuery">
<soap:address location="https://mydomain.com/MetWcfService/Query.svc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Now, plugging in the WSDL into WCF Test Client (from VS) tells me that the request envelope should look like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IQuery/GetLatestValueForParameter</Action>
</s:Header>
<s:Body>
<GetLatestValueForParameter xmlns="http://tempuri.org/">
<p xmlns:d4p1="http://schemas.datacontract.org/2004/07/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:ParameterName>TP02</d4p1:ParameterName>
<d4p1:SiteName>XXXX</d4p1:SiteName>
<d4p1:TowerName>2006TWR</d4p1:TowerName>
</p>
</GetLatestValueForParameter>
</s:Body>
</s:Envelope>
Processing that request through the WCF Test Client gives me the response I expect to see. So, I moved on to my PL/SQL procedure, which is currently a combination of some information I found online.
DECLARE
l_http_request UTL_HTTP.req;
l_http_response UTL_HTTP.resp;
l_buffer_size NUMBER(10) := 512;
l_line_size NUMBER(10) := 50;
l_lines_count NUMBER(10) := 80;
l_string_request VARCHAR2(4000);
l_line VARCHAR2(4000);
l_substring_msg VARCHAR2(4000);
l_raw_data RAW(4000);
l_clob_response CLOB;
BEGIN
utl_http.set_wallet('file:E:\Oracle\product\11.2.0\dbhome_1\BIN\owm\wallets');
utl_http.set_proxy(null);
l_string_request :=
'<SOAP-ENV:Envelope '
||' xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"'
||' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>'
||' <SOAP-ENV:Header>'
||' <Action SOAP-ENV:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">GetLatestValueForParameter</Action>'
||' </SOAP-ENV:Header>'
||' <SOAP-ENV:Body>'
||' <m:GetLatestValueForParameter xmlns:m="http://schemas.datacontract.org/2004/07/">'
||' <p xmlns:d4p1="http://schemas.datacontract.org/2004/07/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">'
||' <ParameterName>TP02</ParameterName>'
||' <SiteName>XXXX</SiteName>'
||' <TowerName>2006TWR</TowerName>'
||' </p>'
||' </m:GetLatestValueForParameter>'
||' </SOAP-ENV:Body>'
||'</SOAP-ENV:Envelope>';
UTL_HTTP.set_transfer_timeout(60);
l_http_request := UTL_HTTP.begin_request(url => 'https://mydomain.com/MetWcfService/Query.svc?wsdl', method => 'POST', http_version => UTL_HTTP.http_version_1_1);
UTL_HTTP.set_header(l_http_request, 'User-Agent', 'Mozilla/4.0');
UTL_HTTP.set_header(l_http_request, 'Content-Type', 'text/xml;charset=utf-8');
UTL_HTTP.set_header(l_http_request, 'SOAPAction');
UTL_HTTP.set_header(l_http_request, 'Content-Length', LENGTH(l_string_request));
<<request_loop>>
FOR i IN 0..CEIL(LENGTH(l_string_request) / l_buffer_size) - 1 LOOP
l_substring_msg := SUBSTR(l_string_request, i * l_buffer_size + 1, l_buffer_size);
BEGIN
l_raw_data := utl_raw.cast_to_raw(l_substring_msg);
UTL_HTTP.write_raw(r => l_http_request, data => l_raw_data);
EXCEPTION
WHEN NO_DATA_FOUND THEN
EXIT request_loop;
END;
END LOOP request_loop;
l_http_response := UTL_HTTP.get_response(l_http_request);
DBMS_OUTPUT.put_line('Response> status_code: "' || l_http_response.status_code || '"');
DBMS_OUTPUT.put_line('Response> reason_phrase: "' ||l_http_response.reason_phrase || '"');
DBMS_OUTPUT.put_line('Response> http_version: "' ||l_http_response.http_version || '"');
BEGIN
<<response_loop>>
LOOP
UTL_HTTP.read_raw(l_http_response, l_raw_data, l_buffer_size);
l_clob_response := l_clob_response || UTL_RAW.cast_to_varchar2(l_raw_data);
END LOOP response_loop;
EXCEPTION
WHEN UTL_HTTP.end_of_body THEN
UTL_HTTP.end_response(l_http_response);
END;
DBMS_OUTPUT.put_line('Response> length: "' || LENGTH(l_clob_response) || '"');
DBMS_OUTPUT.put_line(CHR(10) || '=== Print first ' || l_lines_count || ' lines of HTTP response... ===' || CHR(10) || CHR(10));
<<print_response>>
FOR i IN 0..CEIL(LENGTH(l_clob_response) / l_line_size) - 1 LOOP
l_line := SUBSTR(l_clob_response, i * l_line_size + 1, l_line_size);
DBMS_OUTPUT.put_line('[' || LPAD(i, 2, '0') || ']: ' || l_line);
EXIT WHEN i > l_lines_count - 1;
END LOOP print_response;
IF l_http_request.private_hndl IS NOT NULL THEN
UTL_HTTP.end_request(l_http_request);
END IF;
IF l_http_response.private_hndl IS NOT NULL THEN
UTL_HTTP.end_response(l_http_response);
END IF;
END;
/
The result ends up being:
Response> status_code: "400"
Response> reason_phrase: "Bad Request"
Response> http_version: "HTTP/1.1"
Response> length: ""
Based on this, I assume that there is either an issue with my XML syntax or the SOAP envelope. Any ideas where I've gone wrong?