Summary
Here I’ll list all steps I’ve taken to solve this problem as reference for others.
1.
PHP, stupidly enough, ‘listens’ to the input message of a function to define what function it should use. So give every one of your functions a different input message, even though it uses the same type or element. You may think this is quite some work for you to solve but it can be done like this:
<xsi:complexType name="UserCredentials">
<xsi:attribute name="customerID" type="xsi:int"/>
</xsi:complexType>
<xsi:element name="UserCredentials" type="types:UserCredentials"/>
<xsi:element name="UserCredentials1" type="types:UserCredentials"/>
<wsdl:message name="getCustomerCredentials">
<wsdl:part name="body" element="types:UserCredentials"/>
</wsdl:message>
<wsdl:message name="getCustomerCredentials1">
<wsdl:part name="body" element="types:UserCredentials1"/>
</wsdl:message>
Next, Visual Studio was whining, I spend a couple of days figuring this stupidly idiotic simple thing out, just tell the program you have just set the objects property:
UserCredentials.customerID = User.CustomerID;
UserCredentials.customerIDSpecified = true;
And that’s it. I can’t believe it myself. I spend 1,5 weeks, solution is two steps, please give this guy who answered below some votes up.
Update
My input object is NOT begin parsed into XML.
//Fix:
You have to tell the program that the property is set like so:
UserCredentials.customerID = User.CustomerID;
UserCredentials.customerIDSpecified = true;
Fiddler shows this:
Input
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<UserCredentials2 xmlns="http://5.157.80.21/servicehandler/wsdl_service.wsdl"/>
</s:Body>
</s:Envelope>
Output
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="types">
<SOAP-ENV:Body>
<ns1:PersoonArray/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Is there something wrong with this code?
public static List<Klant> GetAllPersonen()
{
List<Klant> list = new List<Klant>();
WeGotchaService.Persoon[] servicePersonen = dpc.getAllPersoonData(UserCredentials);
foreach (WeGotchaService.Persoon p in servicePersonen)
{
Klant k = new Klant(p);
list.Add(k);
}
return list;
}
Update to comment below
<xsi:complexType name="UserCredentials">
<xsi:attribute name="customerID" type="xsi:int"/>
</xsi:complexType>
<xsi:element name="UserCredentials" type="tns:UserCredentials" />
<xsi:element name="UserCredentials2" type="tns:UserCredentials"/>
<wsdl:message name="getCustomerCredentials">
<wsdl:part name="body" element="ns:UserCredentials"/>
</wsdl:message>
<wsdl:message name="getCustomerCredentials2">
<wsdl:part name="body" element="ns:UserCredentials2"/>
</wsdl:message>
<wsdl:operation name="getAllLessenData">
<wsdl:input message="ns:getCustomerCredentials"/>
<wsdl:output message="ns2:LessenList"/>
</wsdl:operation>
<wsdl:operation name="getAllPersoonData">
<wsdl:input message="ns:getCustomerCredentials2"/>
<wsdl:output message="ns3:PersoonList"/>
</wsdl:operation>
This seems to work, except that it now returns a count=0 array in VS10
Another Update
In the comments someone posted a link to a bug report with PHP. The second last commenter claimed that he worked around this same issue I have by placing all the message defenitions in other files and included them in this main WSDL document. I tried this but it did not work, nothing changed.
UPDATE:
So I changed the order of the functions defined in the binding method, and figured out the following: only the first function defined in the binding area works, so in this case only my getAllLessenData works, because I put it above all the others. Does anyone see an error?
<wsdl:binding name="DataBinding" type="tns:DataPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getAllLessenData">
<soap:operation soapAction="" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getAllPersoonData">
<soap:operation soapAction="" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getAllBetalingData">
<soap:operation soapAction="" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getPersoonLessenData">
<soap:operation soapAction="" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getPersoonBetalingenData">
<soap:operation soapAction="" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
end of update
I’m having a little problem with WSLD (again)
my getAllLessenData (and other functions) all return NULL while one function (getAllPersoonData) returns what is expected.
WSDL array defenitions:
<xsi:element name="PersoonArray">
<xsi:complexType>
<xsi:sequence>
<xsi:element name="Persoon" type="tns:Persoon" maxOccurs="unbounded"/>
</xsi:sequence>
</xsi:complexType>
</xsi:element>
<xsi:element name="LessenArray">
<xsi:complexType>
<xsi:sequence>
<xsi:element name="Les" type="tns:Les" maxOccurs="unbounded"/>
</xsi:sequence>
</xsi:complexType>
</xsi:element>
WSDL complexType defenitions:
<xsi:complexType name="Les">
<xsi:attribute name="ID" type="xsi:int"/>
// lots of stuff //
<xsi:attribute name="Definitief" type="xsi:boolean"/>
</xsi:complexType>
<xsi:complexType name="Persoon">
<xsi:attribute name="ID" type="xsi:int"/>
<// lots of stuff //
<xsi:attribute name="Laatste_keer_bewerkt" type="xsi:dateTime"/>
</xsi:complexType>
WSDL message defenitions:
<wsdl:message name="getCustomerID">
<wsdl:part name="CustomerID" type="xs:int"/>
</wsdl:message>
<wsdl:message name="PersoonList">
<wsdl:part name="PersoonList" element="tns:PersoonArray"/>
</wsdl:message>
<wsdl:message name="LessenList">
<wsdl:part name="LessenList" element="tns:LessenArray"/>
</wsdl:message>
WSDL portType defenition
<wsdl:operation name="getAllPersoonData">
<wsdl:input message="tns:getCustomerID"/>
<wsdl:output message="tns:PersoonList"/>
</wsdl:operation>
<wsdl:operation name="getAllLessenData">
<wsdl:input message="tns:getCustomerID"/>
<wsdl:output message="tns:LessenList"/>
</wsdl:operation>
WSDL Binding defention
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getAllPersoonData">
<soap:operation soapAction="http://localhost/weGotcha/servicehandler/servicehandler.php" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getAllLessenData">
<soap:operation soapAction="http://localhost/weGotcha/servicehandler/servicehandler.php" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
PHP function defenitions:
function getAllPersoonData($customer_ID)
{
connectToDB();
//////////// yes I use mysqli now /////////////
$sql = "SELECT * FROM personen WHERE Customer_ID='". $customer_ID ."'";
$sql = mysql_query($sql) or die(mysql_error());
$result = array();
while($row = mysql_fetch_array($sql))
{
$row["Kosten_totaal"] = mysql_fetch_array(mysql_query("SELECT SUM(Kosten) FROM lessen WHERE Persoon_ID='". $row["ID"] ."'"))[0];
$row["Totaal_betaald"] = mysql_fetch_array(mysql_query("SELECT SUM(Bedrag) FROM betalingen WHERE Persoon_ID='". $row["ID"] ."'"))[0];
$lkbDatum = strtotime($row["Laatste_keer_bewerkt"]);
$row["Laatste_keer_bewerkt"] = date("Y-m-d", $lkbDatum) . "T". date("H:i:s", $lkbDatum);
$result[] = $row;
}
mysql_close();
return $result;
}
function getAllLessenData($customer_ID)
{
$sql = "SELECT * FROM lessen WHERE Customer_ID='". $customer_ID ."'";
//////////// yes I use mysqli now /////////////
connectToDB();
$sql = mysql_query($sql) or die(mysql_error());
$result = array();
while($row = mysql_fetch_array($sql))
{
$result[] = $row;
}
mysql_close();
return $result;
}
$server = new SoapServer("wsdl_service.wsdl");
$server->AddFunction("getAllPersoonData");
$server->AddFunction("getAllBetalingData");
$server->AddFunction("getPersoonBetalingData");
$server->AddFunction("getAllLessenData");
$server->AddFunction("getPersoonLessenData");
$server->handle();
Test.php
$client = new SoapClient("http://localhost/weGotcha/servicehandler/wsdl_service.wsdl", array("trace" => 1));
var_dump($client->__getFunctions());
var_dump($client->getAllLessenData(1));
var_dump($client->__getLastRequest());
var_dump($client->__getLastResponse());
which returns:
array (size=5)
0 => string 'PersoonArray getAllPersoonData(int $CustomerID)' (length=47)
1 => string 'LessenArray getAllLessenData(int $CustomerID)' (length=45)
2 => string 'BetalingenArray getAllBetalingData(int $CustomerID)' (length=51)
3 => string 'LessenArray getPersoonLessenData(int $getCustomerID, int $getPersoonID)' (length=71)
4 => string 'BetalingenArray getPersoonBetalingenData(int $getCustomerID, int $getPersoonID)' (length=79)
null
string '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><CustomerID>1</CustomerID></SOAP-ENV:Body></SOAP-ENV:Envelope>
' (length=195)
string '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost/weGotcha/servicehandler/wsdl_service.wsdl"><SOAP-ENV:Body> <ns1:PersoonArray><ns1:Persoon ID="1" Voornaam="xxxx" Achternaam="xxxx" Adres="xxxx" Postcode="xxxx" Woonplaats="xxxx" Email_adres="xxxx" Telefoonnummer="xxxx" Geboortedatum="0001-01-01" CBR_kandidaatnummer="12381233" Rijbewijs="2" Theorie_behaald="false" Theorie_po'... (length=3096)
There are rows in my database and calling getAllLessenData(1) directly from my servicehandler.php returns the expected results. however, in my test.php it simply returns NULL and the getLastResponse returns the results from getAllPersoonData(1).
Both function defenitions look the same for me, heck I copy-pasted most of it. I tried changing namespaces etc. google. but it didn’t work. Any ideas?
If you need more info please respond.
EDIT 1: This may also have to do with the fact that
getAllPersoonDataandgetAllLessenDatahave the same input signature, which means that, for document literal style web services, the endpoint won’t be able to distinguish what kind of request you’re actually making. Try passing two different element names.EDIT 2: Also, giving these messages different signatures would allow you to put
getPersoonIDwithin the type definition so that you only have one message part. Right now, if you look inCustomer.wsdlyou have:You should not have more than one part in a document-literal message.
EDIT 3: If you don’t want to define a new element for each function that you have, then you would have to switch to RPC literal, which wraps the request in the
wsdl:operationname. If this would fix everything except .NET, then you could try my SO post on coaxing .NET into reading RPC-literal web services.