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.
Related
I'm trying to send a request to an API in soap using WCF, in the API documentation I was told that first I need to pass the following authentication header containing a fixed token:
<soapenv:Header>
<Token xmlns="Token">12345as566788ds900987654</Token>
</soapenv:Header>
After passing and validating this token I access the class I need to send the file, I tried with the code below that I managed to assemble searching, but I'm getting the error: System.ServiceModel.FaultException: informing that I need to pass the token tag in the header.
Below how I'm trying to do it:
using (new OperationContextScope(client.InnerChannel))
{
HttpRequestMessageProperty requestMessage = new();
requestMessage.Headers["Token"] = "12345as566788ds900987654";
var result= client.uploadFile(file);
}
You can try this for the client-side:
IContextChannel contextChannel = (IContextChannel)myServiceProxy;
using (OperationContextScope scope = new OperationContextScope(contextChannel))
{
MessageHeader header = MessageHeader.CreateHeader("PlayerId", "", _playerId);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
act(service);
}
And you can try this on the server-side:
private long ExtractPlayerIdFromHeader()
{
try
{
var opContext = OperationContext.Current;
var requestContext = opContext.RequestContext;
var headers = requestContext.RequestMessage.Headers;
int headerIndex = headers.FindHeader("PlayerId", "");
long playerId = headers.GetHeader<long>(headerIndex);
return playerId;
}
catch (Exception ex)
{
this.Log.Error("Exception thrown when extracting the player id from the header", ex);
throw;
}
}
I'm trying connect Twilio autopilot to voice call with custom data. According to documentation there is Memory parameter where I can put custom data.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect action="https://www.example.com/autopilot">
<Autopilot Memory={"CarModel":"Diablo","CarMake":"Lamborghini","CarYear":"2019"}>UAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</Autopilot>
</Connect>
</Response>
But when I try to put it via strong types I receive a message "Sorry an error occurred."
Here is the method:
public VoiceResponse ConnectAutopilot(Guid requestId)
{
var response = new VoiceResponse();
var autopilotUrl =
$"https://channels.autopilot.twilio.com/v1/{ AccountSid}/{AutopilotName }/twilio-voice";
var connect = new Connect
{
Action = new Uri(autopilotUrl)
};
var pilot = new Autopilot { Name = AutopilotName};
pilot.SetOption("Memory", new{requestId});
pilot.SetOption("TargetTask", "greeting");
connect.Append(pilot);
response.Append(connect);
response.Hangup();
return response;
}
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);
I am trying to call a .net web service from an android emulator but I am getting connection timeout exception.
Before I tried to call my webService I called the http://www.w3schools.com/webservices/tempconvert.asmx without problems.
So I am assuming that either I have something wrong in my .net webService either in android application.
the .net is
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class Pros : System.Web.Services.WebService {
[WebMethod]
public List<Product> Get(int pageIndex,int pageSize) {
var efUnitOfWork = new EFUnitOfWork();
var productsRepos = new ProductRepository(new EFRepository<Product>(), efUnitOfWork);
return (List<Product>)productsRepos.GetByPage(pageIndex, pageSize);
}
}
and the java is
private static final String METHOD_NAME = "Get";
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "http://10.0.0.2:2807/webservices/webService.asmx";
private static String SOAP_ACTION = NAMESPACE+METHOD_NAME;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("pageIndex", "0");
request.addProperty("pageSize", "10");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet=true;
envelope.setOutputSoapObject(request);
AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapObject result=(SoapObject)envelope.getResponse();
String resultData=result.getProperty(0).toString();
}
catch (Exception e) {
e.printStackTrace();
}
}
Am I missing something?
You can try to increase the timeout for the call like this:
AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL, 15000);
You should try to increase the timeout as mentioned but more importantly you have to move your call into a background thread. Use AsyncTask.
Also as discussed in the comment there is a blog post linked in the ksoap2-android wiki that explains the connection stuff in detail. You can NOT use localhost or equivalent since that is on the device but your service runs on a server.. now that I look at the code again .. 10.0.0.2 will not work most likely.
Do an ifconfig/ipconfig on the server and use that IP address. I bet it will work then.
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