accessing php soapservice from C# - c#

well i wanted to make a simple webservice that searches the db and return the data i know i can do it with mysql connector but this is just to learn how to use soaps here is the code for php soap server
require_once ('lib/nusoap.php');
$namespace = "http://localhost/webservice/index.php?wsdl";
$server = new soap_server();
$server->configureWSDL("DBQuery");
$server->wsdl->schemaTargetNamespace = $namespace;
$server->register(
'QueryMsg',
array('name'=>'xsd:string'),
array('return'=>'xsd:string'),
$namespace,
false,
'rpc',
'encoded',
'returns data from database');
function QueryMsg($query)
{
$con=mysqli_connect('localhost','root','','webserivce');
if (mysqli_connect_errno()) {
return "Failed to connect to MySQL: " . mysqli_connect_error();
}
if(!isset($query) or strpos(strtolower($query),'select')<=-1)
{
return "invalid order";
}
else
{
mysqli_real_escape_string($con,$query);
$result = mysqli_query($con,$query);
while($row = mysqli_fetch_array($result)) {
$data[] = $row;}
return json_encode($data);
}
}
// create HTTP listener
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
exit();
?>
it works when i try calling it from a php soap client but when i try adding this http:// localhost /webservice/index.php in visual studio as service refernce to consume it from C# application i get an error here it is
The HTML document does not contain Web service discovery information.
Metadata contains a reference that cannot be resolved: 'http://localhost/webservice/index.php'.
The content type text/xml; charset=ISO-8859-1 of the response message does not match the content type of the binding (application/soap+xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 700 bytes of the response were: '<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
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:Fault><faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode><faultactor xsi:type="xsd:string"></faultactor><faultstring xsi:type="xsd:string">Operation &apos;&apos; is not defined in the WSDL for this service</faultstring><detail xsi:type="xsd:string"></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>'.
The remote server returned an error: (500) Internal Server Error.
If the service is defined in the current solution, try building the solution and adding the service reference again.
solved : well it was easy actually there is two ways either use WCF and change encoding to ISO-8859-1
or change encoding of the web service itself by adding this line $server->soap_defencoding = 'UTF-8'; after creating the soap server

I would try adding the service WSDL with a tool like SOAP U.I. and see what kind of errors you get back from that. It's a little more agnostic than adding a web reference with C#, and might disclose more details about why at the client level you can't consume this.
I'm happy to help you troubleshoot this with a little more information. Are you running this service on the same machine where you're running the client from? If it's complaining about being unable to correlate the file http://localhost/webservice/index.php to something I wonder if the discovery process is trying to evaluate a file that can't be found. I.E. an import operation in your source WSDL that points to a URL the client can't resolve.

Related

How to set a proxy when using SoapPortClient?

I'm trying to execute a function using a Soap Port Client object (from an external WebService), and I need to set a proxy (address and credentials) for it. Because when I test the app (not on localhost), the WS functionality doesn't work.
Namespace.WebService.SoapPortClient foo = new Namespace.WebService.SoapPortClient();
short cod_error;
string des_error;
string url = "";
int fooNumber = 10;
url = foo.Execute(fooNumber, out cod_error, out des_error);
...code continues
In the above example, I need to set a proxy for 'foo'. I've tried with foo.Proxy but this property doesn't exists in the SoapPortClient.
Thank you all!
After reading your comments and problem I realized that you are talking about WCF.
Regards to your latest problem:
Now I'm getting the following error: The content type text/HTML of the response message does not match the content type of the binding (text/XML; charset=utf-8)
My first suggestion would be to check that the user you're running the WCF client under has access to the resource.
Can't say much since it's very hard to say something without seeing the config file or code in general.

How to consume SOAP service with custom header

I need to consume a SOAP service from a vendor. I had created a proxy service with the WSDL in visual studio, instantiated the client class, called the action method, and got the response. Everything works fine until the vendor asks for an access token in the soap envelop header. I am able to get the access token from them on another service call but how do I add it to the soap request header?
Here is the structure of the header from the vendor:
<SOAP:Header>
<SOAP-SEC:Security SOAP:mustUnderstand="1">
<wsse:SecuredKey ValueType="..." EncodingType="wsse:Base64Binary">
{ACCESS TOKEN}
</wsse:SecuredKey>
</SOAP-Sec:Security>
</SOAP:Header>
<SOAP:Body/>
</SOAP:Envelop>
By far the easiest way to do this is by using a string replace in a template. Store the message as a resource in your project (e.g. in Resources.resx or save as file and set set build action to embedded resource). The template looks like this:
<SOAP:Header>
<SOAP-SEC:Security SOAP:mustUnderstand="1">
<wsse:SecuredKey ValueType="..." EncodingType="wsse:Base64Binary">
{ACCESS TOKEN}
</wsse:SecuredKey>
</SOAP-Sec:Security>
</SOAP:Header>
<SOAP:Body/>
</SOAP:Envelop>
Load the template as string from your resource, then call the webservice to obtain an access token and do and replace {ACCESS TOKEN} with the actual access token. You can now send the soap message using e.g. System.Net.Http.HttpClient or System.Net.WebClient.
Example using WebClient
using (var client = new WebClient())
{
var result = client.UploadString("http://your.target/endpoint", yourXDocument.ToString(SaveOptions.DisableFormatting));
return XDocument.Parse(result);
}
The SaveOptions.DisableFormatting doesn't try to pretty print the XDocument which can be important when using a signed xml document with WS-Security. Not sure if that applies in your case.

C# SOAP client: sending generic XmlNode request

I have a C# project where I added a SOAP service reference, using the integrated visual studio functionality (right click -> add -> service reference)
The client classes are generated correctly without errors. However, the various methods of the service only accept a generic System.Xml.XmlNode as an input, rather than a structured object.
This should not be a problem in theory, since I have the complete XML file with the query that I need to perform. So I tried doing it like this:
NSIStdV20ServiceSoapClient client = new NSIStdV20ServiceSoapClient();
var getAllDataFlowQuery = File.ReadAllText(#"Query\get_all_dataflow.xml"); //file containing the query
XmlDocument doc = new XmlDocument();
doc.LoadXml(getAllDataFlowQuery);
var dataStructures = client.QueryStructure(doc); //this method accepts a System.Xml.XmlNode as parameter
However, this doesn't work, throwing
System.ServiceModel.FaultException: 'Error due to a non correct client message'
I thought initially that the query was incorrect, but I tried to perform the exact same query using SoapUI and it works perfectly! I even tried doing it with the exact XML returned by doc.InnerXml (just to be sure che XmlDocument object was not modifying the XML) and it works.
So basically it's only when calling the method from C# that it doesn't work.
If you want to try it out yourself, the service is freely accessible, the WSDL is here:
http://sdmx.istat.it/SDMXWS/NsiStdV20Service.asmx?WSDL
and you should try to call the QueryStructure method with the following payload:
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://ec.europa.eu/eurostat/sri/service/2.0"><soapenv:Header /><soapenv:Body><web:QueryStructure><!--Optional:--><web:Query><RegistryInterface xsi:schemaLocation="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message SDMXMessage.xsd" xmlns="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message" xmlns:common="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common" xmlns:compact="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/compact" xmlns:cross="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/cross" xmlns:generic="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/generic" xmlns:query="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/query" xmlns:structure="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure" xmlns:registry="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/registry" xmlns:utility="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/utility" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header><ID>JD014</ID><Test>true</Test><Truncated>false</Truncated><Name xml:lang="en">Trans46302</Name><Prepared>2001-03-11T09:30:47-05:00</Prepared><Sender id="BIS" /></Header><QueryStructureRequest resolveReferences="false"><registry:DataflowRef /></QueryStructureRequest></RegistryInterface></web:Query></web:QueryStructure></soapenv:Body></soapenv:Envelope>
As I said, this works perfectly in SoapUI, but doesn't work when calling the client method from C#
Well, it seems that the client generated by visual studio, even tho it accepts a XmlNode as input, creates some of the required outer structure itself (to be precise: all the outer nodes with the soapenv and web namespaces).
Which means I had to strip down the input XML to:
<?xml version="1.0" encoding="UTF-8"?><RegistryInterface xsi:schemaLocation="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message SDMXMessage.xsd" xmlns="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message" xmlns:common="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common" xmlns:compact="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/compact" xmlns:cross="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/cross" xmlns:generic="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/generic" xmlns:query="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/query" xmlns:structure="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure" xmlns:registry="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/registry" xmlns:utility="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/utility" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header><ID>JD014</ID><Test>true</Test><Truncated>false</Truncated><Name xml:lang="en">Trans46302</Name><Prepared>2001-03-11T09:30:47-05:00</Prepared><Sender id="BIS" /></Header><QueryStructureRequest resolveReferences="false"><registry:DataflowRef /></QueryStructureRequest></RegistryInterface>

Inject header into WCF outbound message

I have a WCF service built on the classes created from a customer supplied WSDL. Unfortunately this WSDL did not contain the required message header. The client will not be supplying a new WSDL including the header. I do have an xsd file describing the header.
I also have a sample header and know which fields I need to populate.
How can I take this supplied header XML and inject it into an outbound WCF method call?
I want to call my service method as I currently do, but I also want the new header structure to form part of the outbound message.
Thanks in advance.
Any and all help will be greatly appreciated.
Here is an example of the message structure:
I need to add the entire header structure. All that the WSDL contained was the body.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<glob:requestHeader xmlns:glob="http://....">
<timestamp>2013-11-14T05:17:41.793+02:00</timestamp>
<traceMessageId>GUID</traceMessageId>
<enterpriseTraceUUId>GUID</enterpriseTraceUUId>
<contentType>TEXT/XML</contentType>
<sender>
<senderId>SENDER</senderId>
<sourceSystem>001</sourceSystem>
<sourceApplication>001</sourceApplication>
<applicationSessionId>ABC</applicationSessionId>
<sourceLocation>100</sourceLocation>
</sender>
<interfaceName/>
<version>1111</version>
</glob:requestHeader>
</s:Header>
<s:Body xmlns:xsi="http://.../XMLSchema-instance" xmlns:xsd="http://.../XMLSchema">
<UserData xmlns="http://.../Base">
<IdField>1005687</IdField>
<UserInfo>
<UserType>1</UserType>
<UserStatus>Y</UserStatus>
</UserInfo>
</UserData>
</s:Body>
</s:Envelope>
I used this, for instance, to add "User-Agent" to the header of my outgoing messages, but I think you could adapt it to your own needs:
private void AddCustomHeader(System.ServiceModel.OperationContextScope scope)
{
dynamic reqProp = new System.ServiceModel.Channels.HttpRequestMessageProperty();
reqProp.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT; blah; blah; blah)");
System.ServiceModel.OperationContext.Current.OutgoingMessageProperties(System.ServiceModel.Channels.HttpRequestMessageProperty.Name) = reqProp;
}
I call this function above from the the constructor of the client-side program I use to call the host.
AddCustomHeader(new System.ServiceModel.OperationContextScope(base.InnerChannel));
Probably the most important thing to notice is that it's adding this header variable to OutgoingMessageProperties of the "Current" OperationContext used by my client.
have you tried this? Also taken from here: How to add a custom HTTP header to every WCF call?
using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel))
{
MessageHeader<string> header = new MessageHeader<string>("secret message");
var untyped = header.GetUntypedHeader("Identity", "http://www.my-website.com");
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
// now make the WCF call within this using block
}

WCF-Capturing the full HTTP response

I'm using WCF to call a method on a Java web service (using basicHttp with <security mode="Transport">). The service returns some HTML back instead of a SOAPFault. WCF seems to implement some odd truncating of the content returned in the exception, so I can't see the entire error.
Is there a way to get the entire response? Perhaps some configuration I can change to pull back more then 660 bytes? I tried turning on service tracing, but it doesn't seem to capture the entire response. I'm unable to use Fiddler or Charles, because the service is using two-way SSL and it's on a secure network. Here's the exception:
The content type text/html of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 660 bytes of the response were: '<html><head><title>Server - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </he
It seems that an exception occurred on the server side. When exception occurs with httpBinding, HTTP status becomes 404 - NotFound.
It might be as a result of:
Incorrect signature of calling method and actual method, or order of parameters
Failure to serialize or deserialize the result
Some failure with SSL configuration/keys
Internal exception within WCF
In order to eliminate all the above try connecting to it using plain .NET client without SSL. Then add a level of complexity each time.
Hope this helped
Have you set IncludeExceptionDetailInFaults = True in ServiceDebugBehavior?
That might help.
You can try to capture outgoing SOAP request and send that request through HttpWebRequest class. This should allow you capturing whole response.

Categories