SOAP Communication between PHP client and windows service results in NullReferenceException - c#

If i test the Service with SoapUi the operation scucceds, but if implement the Soap Client with PHP the parameters are allways emty and i get an NullReferenceException.
<?php
$options = array();
$options['classmap']['Abonnent'] = 'RequestType';
$client = new SoapClient('wsdllink',$options);
class RequestType
{
public $Email;
public $Nachname;
public $Passwort;
public $Vorname;
}
$abo = new RequestType;
$abo->Email = 'email';
$abo->Nachname = 'lastname';
$abo->Passwort = 'passwort';
$abo->Vorname = 'firstname';
try {
$result = $client->Abonnieren($abo);
} catch(SoapFault $e) {
echo "Request :\n". ($client->__getLastRequest()). "\n";
echo "Response :\n". ($client->__getLastResponseHeaders()). "\n";
echo "Response :\n". ($client->__getLastResponse()). "\n";
echo($e->getMessage());
} catch(Exception $e) {
echo $e->getMessage();
}
?>
var_dump($client->__getFunctions())
array(2) {
[0]=>
string(53) "AbonnierenResponse Abonnieren(Abonnieren $parameters)"
[1]=>
string(53) "RegisterIBResponse RegisterIB(RegisterIB $parameters)"
}
var_dump($client->__getTypes())
array(8) {
[0]=>
string(87) "struct Abonnent {
string Email;
string Nachname;
string Passwort;
string Vorname;
}"
[1]=>
string(41) "struct Abonnieren {
Abonnent abonnent;
}"
[2]=>
string(56) "struct AbonnierenResponse {
boolean AbonnierenResult;
}"
[3]=>
string(41) "struct RegisterIB {
Abonnent abonnent;
}"
[4]=>
string(56) "struct RegisterIBResponse {
boolean RegisterIBResult;
}"
[5]=>
string(8) "int char"
[6]=>
string(17) "duration duration"
[7]=>
string(11) "string guid"
}
XML from SoupUI
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tem="http://tempuri.org/"
xmlns:prm="http://schemas.datacontract.org/2004/07/PRMarketService">
<soapenv:Header/>
<soapenv:Body>
<tem:Abonnieren>
<tem:abonnent>
<prm:Email>email</prm:Email>
<prm:Nachname>lastname</prm:Nachname>
<prm:Passwort>passwort</prm:Passwort>
<prm:Vorname>firstname</prm:Vorname>
</tem:abonnent>
</tem:Abonnieren>
</soapenv:Body>
</soapenv:Envelope>
XML from PHP Client
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://schemas.datacontract.org/2004/07/PRMarketService"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns2="http://tempuri.org/">
<SOAP-ENV:Body>
<ns2:Abonnieren xsi:type="ns1:Abonnent">
<ns1:Email>email</ns1:Email>
<ns1:Nachname>lastname</ns1:Nachname>
<ns1:Passwort>passwort</ns1:Passwort>
<ns1:Vorname>firstname </ns1:Vorname>
</ns2:Abonnieren>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Compare messages sent by SoapUI and PHP's SoapClient, for example using Fiddler. If I recall correctly, you'll have to wrap the XML body PHP sends in a root element named after the appropriate SOAPAction.
Something like this:
class AbonnierenRequest
{
public $Abbonent;
}
class Abonnent
{
public $Email;
public $Nachname;
public $Passwort;
public $Vorname;
}
$request = new AbonnierenRequest();
$request->Abonnent = new Abonnent();
$request->Abonnent->Email = 'email';
$request->Abonnent->Nachname = 'lastname';
$request->Abonnent->Passwort = 'passwort';
$request->Abonnent->Vorname = 'firstname';
$result = $client->Abonnieren($request);

Related

Non-wsdl SOAP request in PHP

I need to post SOAP request to some server.
I know exactly that the right example of SOAP request as follows:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<CreateOrderBroker xmlns="http://tempuri.org/">
<shortApp xmlns:a="http://schemas.datacontract.org/2004/07/ScroogeCbformsService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:PIB>John Doe</a:PIB>
<a:agreeId>3155</a:agreeId>
<a:formId>55</a:formId>
<a:stateCode>1234567890</a:stateCode>
<a:telephone>1511528945</a:telephone>
</shortApp>
</CreateOrderBroker>
</s:Body>
</s:Envelope>
Also I have working C# example:
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
public EndpointAddress EndPointAddr {
get { return
new EndpointAddress("https://194.126.180.186:77/ScroogeCbForms.svc?wsdl");
}
}
private void btnSend_Click(object sender, EventArgs e)
{
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(IgnoreCertificateErrorHandler);
ServicePointManager.Expect100Continue = false;
ServiceICreditTest.CreateOrderResponse response = new CreateOrderResponse();
ScroogeSiteGist client = new ScroogeSiteGist(Binding(), EndPointAddr);
shortApplicationBroker shortAp = new shortApplicationBroker()
{
agreeId = 3155,
PIB = "John Doe",
stateCode = "1234567890",
formId = 55,
telephone = "1511528945"
};
//response = client.CreateOrder("1012021013");
response = client.CreateOrderBroker(shortAp);
txtText.Text = string.Format("id = {0} ErrorId = {1}", response.OrderId, response.ReturnValue);
}
}
I'm trying to make same code in PHP 5.3:
<?php
$client = new SoapClient("https://194.126.180.186:77/ScroogeCbForms.svc?wsdl", array('soap_version' => SOAP_1_1, 'trace' => 1));
$params = array(
'agreeId' => 3155,
'PIB' => 'John Doe',
'stateCode' => '3289013768',
'formId' => 55,
'telephone' => '0661254877'
);
$client->CreateOrderBroker($params);
But request and callback from this code is next:
<?php
...
echo "REQUEST:<pre>".htmlspecialchars($client->__getLastRequest()) ."</pre>";
echo "CALLBACK:<pre>".htmlspecialchars($client->__getLastResponse())."</pre>";
REQUEST:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/">
<SOAP-ENV:Body><ns1:CreateOrderBroker/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
CALLBACK:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body><CreateOrderBrokerResponse xmlns="http://tempuri.org/"><CreateOrderBrokerResult xmlns:a="http://schemas.datacontract.org/2004/07/ScroogeCbformsService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:OrderId>0</a:OrderId>
<a:ReturnValue>Object reference not set to an instance of an object.</a:ReturnValue>
</CreateOrderBrokerResult>
</CreateOrderBrokerResponse>
</s:Body>
</s:Envelope>
It seems that body of request is empty.
What does it mean? If call made in wsdl-mode and request body is empty then wsdl-schema is broken, right?
If wsdl is broken what is the way to construct initial right SOAP request manually? Can anyone give an example?
Moreover, the data given in initial right SOAP request is enough to construct this request manually? Or I need some extra (namespaces, etc.)
Try the following code:
$client = new SoapClient("https://194.126.180.186:77/ScroogeCbForms.svc?wsdl", array('soap_version' => SOAP_1_1, 'trace' => 1));
class shortApp {
function __construct()
{
$this->agreeId = 3155;
$this->PIB = 'John Doe';
$this->stateCode = '3289013768';
$this->formId = 55;
$this->telephone = '0661254877';
}
}
$sa = new shortApp();
$shortApp = new SoapVar($sa, SOAP_ENC_OBJECT, 'shortApp', 'http://soapinterop.org/xsd');
$response = $client->CreateOrderBroker(new SoapParam($shortApp, 'shortApp'));
This code should give you the following request:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/" 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/" xmlns:ns2="http://soapinterop.org/xsd" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:CreateOrderBroker>
<shortApp xsi:type="ns2:shortApp">
<agreeId xsi:type="xsd:int">3155</agreeId>
<PIB xsi:type="xsd:string">John Doe</PIB>
<stateCode xsi:type="xsd:string">3289013768</stateCode>
<formId xsi:type="xsd:int">55</formId>
<telephone xsi:type="xsd:string">0661254877</telephone>
</shortApp>
</ns1:CreateOrderBroker>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

How to change WebMethod XML output for ASP.NET Webservice, specifically namespace declaration?

I'm developing an ASP.NET Webservice (not WCF) for a given client. This is one of those situations, where you can not change anything at the client.
The client sends the following XML to request a method:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:cometxsd="http://werk-ii.de/soap/comet/Schema"
xmlns:comet="http://werk-ii.de/soap/comet"
xmlns:xop="http://www.w3.org/2004/08/xop/include"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xmime5="http://www.w3.org/2005/05/xmlmime"
xmlns:ns1="http://soap.comet.werkii.com/">
<SOAP-ENV:Body>
<ns1:login xsi:type="ns1:login">
<user>myusername</user>
<password>mypassword</password>
<client>whatever</client>
<language>de</language>
</ns1:login>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
My Service provides the login-Method like this:
[WebService(Namespace = "http://soap.comet.werkii.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class CometService : WebService
{
[WebMethod(MessageName = "login")]
[return: XmlElement("return")]
public LoginResult Login (string user, string password, string client, string language)
{
return new LoginResult() {
ResultCode = 0,
SessionId = user + "-" + password + "-" + client + "-" + language
};
}
}
public class LoginResult
{
[XmlElement("resultCode")]
public int ResultCode { get; set; }
[XmlElement("sessionId")]
public string SessionId { get; set; }
}
If I start the service, it tells me what SOAP 1.1 code I have to send as a request, that ist:
<?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>
<login xmlns="http://soap.comet.werkii.com/">
<user>string</user>
<password>string</password>
<client>string</client>
<language>string</language>
</login>
</soap:Body>
</soap:Envelope>
When I use this code - as told by the service - from another test client (i wrote one in PHP), everything works fine an I get a result. But when I send the code from the beginning (which is what the real client will send), the method is called but all 4 arguments are null.
From an XML view, in my opinion both requests are the same. The only difference is, where the namespace is defined and if elements use the ns1 prefix. This should not make any difference, when the service reads it as XML. Maybe I'm wrong.
Perhaps the 4 arguments in the first XML have a different namespace (none) than the method (ns1). Can that be the reason why all arguments are null? How would I change the namespace for the arguments only?
When I change only the method lines in XML - replacing <ns1:login xsi:type="ns1:login"> with <login xmlns="http://soap.comet.werkii.com/"> and also the closing tag - it works! So the service seems not to understand my request, if the method element uses a namespace prefix, though the namespace is properly defined in the root element.
I tried the following to change the XML format which the service expects:
System.Web.Services.Protocols.SoapDocumentMethodAttribute - no effect at all
XmlNamespaceDeclarationsAttribute as shown here - which seems not to work because it is made for manipulating complex types, not the service class or a method
So the question is, how can I tell my service to accept the XML from the first example?
Good to know that parameters can also have Attributes:
public LoginResult Login (
[XmlElement(Namespace = "")] string user,
[XmlElement(Namespace = "")] string password,
[XmlElement(Namespace = "")] string client,
[XmlElement(Namespace = "")] string language)
{
return new LoginResult() {
ResultCode = 0,
SessionId = user + "-" + password + "-" + client + "-" + language
};
}
That's the solution to put the parameters into the global namespace – problem solved.

Can I remove the default namespace when creating raw Soap XML?

I'm trying to send a soap request to a WCF service. I am building the soap request using the System.ServiceModel.Channels.Message.CreateMessage() method.
I haven't gotten super deep into building the body, but here is what I have...
Message msg = Message.CreateMessage( MessageVersion.Soap11WSAddressing10, "MethodName" );
msg.Headers.MessageId = new UniqueId( Guid.NewGuid().ToString() );
msg.Headers.Add( Message.CreateHeader( "Security", "",
new Security()
{
TimeStamp = new TimeStampType() {
Created = DateTime.Now,
Expires = Created.AddDays( 1 )
},
UsernameToken = new UsernameToken() {
Username = "stackoverflow",
Password = new Password() {
Type = "hashed",
Value = "Password"
}
}
} ) ) );
string s = msg.ToString();
When I run this, I get the following output. I'm using the Visual Studio XML Visualizer btw.
<s:Envelope>
<s:Header>
<Action>MethodName</Action>
<MessageID>GUIDVALUE</MessageID>
<Security>
<Timestamp xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
.....
</s:Header>
<s:Body />
</s:Envelope>
My question is, can I remove xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1" from the xml? It shows up in Timestamp and in UsernameToken.
Thanks
set Namespace to empty in datacontract
in a class that wrap your security and timestamp
[DataContract(Namespace = "")]

Can't pass java parameters in the same format as c# for WCF service

This is the scenario: I have a WCF service running, who communicates with this method, in C#:
public bool ValidateUser(UserPass up)
{
initializeAttributes();
IMembershipService Member = new AccountMembershipService();
bool login = Member.ValidateUser(up.User, up.Pass);
return login;
}
The parameter are encapsulated in this class:
[DataContract]
public class UserPass
{
string user = "";
string pass = "";
string email = "";
[DataMember]
public string User
{
get { return user; }
set { user = value; }
}
[DataMember]
public string Pass
{
get { return pass; }
set { pass = value; }
}
[DataMember]
public string Email
{
get { return email; }
set { email = value; }
}
}
Now, I want to connect to the server via an Android application, now, my question is, how can I replicate the UserPass class in Java, so the ValidateUser method can receive its parameter in a way it can understands it.
for reference, this is the code where I'm obtaining the User and Password:
private void validateUser(String user, String pass)
{
String SOAP_ACTION = "http://tempuri.org/IUserService/ValidateUser/";
String METHOD_NAME = "ValidateUser";
String NAMESPACE = "http://tempuri.org/";
String URL = "http://10.0.2.2/UserService.svc";
AlertDialog popup;
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty(user, pass);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = request;
envelope.dotNet = true;
HttpTransportSE httpTransport = new HttpTransportSE(URL);
try
{
httpTransport.call(SOAP_ACTION, envelope); //here's the exception!!
Object response = envelope.getResponse();
popup = createAlertDialog("Respuesta",response.toString(),"OK");
popup.show();
}
catch (Exception exception)
{
String exceptionStr=exception.toString();
popup = createAlertDialog("Exception!!",exceptionStr,"OK");
popup.show();
}
}
The exception it throws is xmlpullparserexception, which, according to my understanding, is because of a missmatch between the parameters of the request and the actual method.
Many thanks for reading my question, and many more for those who can answer it :)
EDIT:
I finnaly got how to compare the XMLs... now, this is what my SOAP is providing:
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d="http://www.w3.org/2001/XMLSchema"
xmlns:c="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header />
<v:Body>
<ValidateUser xmlns="http://tempuri.org/" id="o0" c:root="1">
<User i:type="d:string">someuser</User>
<Pass i:type="d:string">somepass</Pass>
<Email i:type="d:string"></Email>
</ValidateUser>
</v:Body>
and this is what it SHOULD have made (retrieved from WCF Test Client application from Visual Studio 2010):
<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/IUserService/ValidateUser</Action>
</s:Header>
<s:Body>
<ValidateUser xmlns="http://tempuri.org/">
<up xmlns:d4p1="http://schemas.datacontract.org/2004/07/LiveAndesWCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:Email i:nil="true" />
<d4p1:Pass>somepass</d4p1:Pass>
<d4p1:User>someuser</d4p1:User>
</up>
</ValidateUser>
</s:Body>
</s:Envelope>
Now, I'm lost on how to code my soap code to have it generate a xml file like the latter one.
Many thanks again.
have you tried to look at the xml created by the soap call? you can compare it to the xml created by a .net proxy. maybe this helps to find a solution.
here is how you can enable the logging of the soap calls:
http://msdn.microsoft.com/en-us/library/ms730064.aspx
This line looks suspect to me:
request.addProperty(user, pass);
As far as I can tell, SoapObject comes from the KSOAP2 library, and according to the docs, addProperty takes the name of the property and the value. To set user and pass, I would expect something more like this:
request.addProperty("user", user);
request.addProperty("pass", pass);
Currently, it looks like you're adding a single property named using the value of the user parameter. If the endpoint is expecting at least 2 arguments, then this could be the source of your mismatch.
Also, is the value "Email", from the UserPass wrapper class, optional? As I don't see it being set anywhere, and the wrapper class suggests it's required by the SOAP request

Access C# .net web service in android

How can I use .net web services using android?
My code is like this...
package Webservices.pck;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import android.widget.TextView;
import android.app.Activity;
import android.os.Bundle;
public class Webservices extends Activity
{
private static final String SOAP_ACTION = "http://tempuri.org/HelloWorld";
private static final String METHOD_NAME = "HelloWorld";
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "http://ipaddress/Service1.asmx";
//private Object resultRequestSOAP = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
try
{
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.debug = true;
envelope.dotNet = true;
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapObject resultRequestSOAP = (SoapObject)envelope.bodyIn;
String result = (String)resultRequestSOAP.getProperty(0).toString();
tv.setText(result);
this.setContentView(tv);
}
catch (Exception aE)
{
tv.setText(aE.toString());
this.setContentView(tv);
}
}
}
In this code I am using.
String URL = "http://ipaddress/Service1.asmx";
then error :-- org.xmlpull.v1.xmlPullParserException: expected:START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope(position:START_TAG<html>#1:6 in java.io.InputStreamReader#4375fda8)
You are accessing an html page and not a SOAP service. The parser Exception has already told you what's wrong.
You got data like this
<html><body>... </body></html>
while the page should return something like
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<YourFunctionToCall... />
</soapenv:Body>
</soapenv:Envelope>
Maybe you have a typo in your URL, or some kind of Authentication or some other kind of error, so that it returned an HTML error instead of the Soap Request/Response.

Categories

Resources