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.
Related
I have a WCF service where everything is started programmatically (and need to continue doing so) and I want this service to respond to [WebGet] attributes.
However, when I call one of the WCF methods the service returns a 400 Bad Request.
This would initially seem like a duplicate of WCF Service Returns 400 error when using WebGet or Bad Request 400 while accessing WCF Rest service (WebGet) but both of these solutions add to web.config, a file I don't have because I need to do everything programmatically.
I have tried to add a WebHttpBinding to what seems like the endpoint, but it doesn't work properly (I'm probably not doing it the correct way).
The code below starts without errors, but when I try to go to http://localhost:8765/MyService/MyTest I get the aforementioned 400 Bad Request
What am I missing?
WCF starter
MyService myService = new MyService();
ServiceHost host = new ServiceHost(myService, new Uri("http://localhost:8765/MyService"));
ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
behavior.InstanceContextMode = InstanceContextMode.Single;
foreach(ServiceEndpoint endpoint in host.Description.Endpoints) {
endpoint.Binding = new WebHttpBinding();
}
host.Open();
Service interface
[ServiceContract]
public interface IMyService {
[OperationContract]
[WebGet]
string MyTest();
}
Service implementation
public class MyService : IMyService {
public string MyTest() {
return "Response from WCF service";
}
}
I use this code I wrote to initialize and start my WCF restful services completely from code:
public static WebServiceHost InitializeAndStartWebServiceHost(int port, string endPointName, object serviceModel, Type implementedContractType) {
var baseAddress = new Uri($"http://0.0.0.0:{port}/{endPointName}");
WebServiceHost host;
try {
host = new WebServiceHost(serviceModel, baseAddress);
} catch (Exception exception) {
Debug.Print("Error when creating WebServiceHost, message: " + exception.Message);
return null;
}
// ReSharper disable once UseObjectOrCollectionInitializer
var binding = new WebHttpBinding();
binding.UseDefaultWebProxy = false;
binding.BypassProxyOnLocal = true;
//By default, TransferMode is Buffered which causes C# wcf client to be slow as hell (>500ms for requests which give >2kB responses).
//I am not exactly sure why this helps, but it helps!
binding.TransferMode = TransferMode.Streamed;
host.AddServiceEndpoint(implementedContractType, binding, "");
var behavior = new WebHttpBehavior();
behavior.HelpEnabled = false;
behavior.DefaultBodyStyle = WebMessageBodyStyle.Bare;
// We will use json format for all our messages.
behavior.DefaultOutgoingRequestFormat = WebMessageFormat.Json;
behavior.DefaultOutgoingResponseFormat = WebMessageFormat.Json;
behavior.AutomaticFormatSelectionEnabled = false;
behavior.FaultExceptionEnabled = true;
host.Description.Endpoints[0].Behaviors.Add(behavior);
try {
host.Open();
} catch (AddressAccessDeniedException) {
Console.WriteLine(#"Application must run with administrator rights.");
Console.ReadKey();
Environment.Exit(0);
}
return host;
}
Simple Scenario:
Client makes a AJAX Sync call to a central WCF server ==> url: "svc/About.svc/GetAboutInfo";
The WCF "GetAboutInfo()" will call "GetSiteInfo()" in 80 remote servers;
I get the results but it takes awhile since these are NOT Async calls;
With that in mind I have 2 things to fix (but I don't know how):
1 - make GetSiteInfo() a Async call;
2 - only return GetAboutInfo() to the client after ALL Async calls from GetSiteInfo() are returned;
Note: I cannot use "Tasks" since we are still on .Net 3.5.
Currently I am researching about IAsyncResult (with Begin/End methods) but could not find anything that would allow me to adapt to my current code below.
(I am calling remote servers from a central WCF in a loop).
Bear in mind the WCF below is identical in all remote servers except that the loop which only exists in the "CENTRAL WCF server"(the WCF that calls the remote servers). Here is the partial WCF code:
[ServiceContract]
public interface IAbout
{
[OperationContract(Name = "About_GetAboutInfo")]
[WebGet(UriTemplate = "/GetAboutInfo", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
About.AboutInfo GetAboutInfo();
[OperationContract(Name = "About_GetSiteInfo")]
[WebGet(UriTemplate = "/GetSiteInfo", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
About.SiteInfo GetSiteInfo();
}
public SiteInfo GetSiteInfo()
{
SiteInfo siteInfo = new SiteInfo();
//...code stripped out...
return (siteInfo);
}
public AboutInfo GetAboutInfo()
{
AboutInfo aboutInfo = new AboutInfo();
SiteInfo siteInfo = new SiteInfo()
{
ID = site.ID
,Name = site.Name
,DatabaseVersion = "Unavailable"
};
foreach (Site site in sites)
{
try
{
string uri = Utilities.CombineUri(site.Uri, "svc/About.svc/ws");
AboutServiceClient wcfClient = new AboutServiceClient("About");
wcfClient.Endpoint.Address = new EndpointAddress(uri);
SiteInfo childSiteInfo = wcfClient.GetSiteInfo(); <== call is blocked here until I get a response from remote server
siteInfo.DatabaseVersion = childSiteInfo.DatabaseVersion;
}
catch (Exception e)
{ //...code stripped out... }
aboutInfo.Sites.Add(siteInfo); <== this should only be returned after we receive response from all calls
}
...
public class AboutServiceClient : ClientBase<IAbout>
{
public AboutServiceClient(Binding Binding, EndpointAddress Address) : base(Binding, Address)
{
if (Binding is WebHttpBinding)
{
this.Endpoint.Behaviors.Add(new WebHttpBehavior());
}
}
public AboutServiceClient(string endpointConfigurationName) : base(endpointConfigurationName)
{ }
public About.SiteInfo GetSiteInfo()
{ return base.Channel.GetSiteInfo(); }
public About.AboutInfo GetAboutInfo()
{ return base.Channel.GetAboutInfo(); }
}
Thank you
Using .NET 3.5 is a major restrain. You won't be able to keep your linear code flow. Here's the new workflow:
You'd need to implement BeginGetAboutInfo/EndGetAboutInfo as described in "How to: Implement an Asynchronous Service Operation".
In BeginGetAboutInfo you'd do start 80 asynchronous requests to the remote WCF service with wcfClient.GetSiteInfoBegin (in parallel) and keep track of IAsyncResult of each.
As these asynchronous operation are completing (your callback will be called for each), use wcfClient.EndSiteInfoBegin to retriever and store the result of each operation.
As soon as all of them have completed, invoke the callback, provided by the client when your BeginGetAboutInfo was called.
Now expect the client to call your EndGetAboutInfo, where you'd provide the combined result of all 80 operations.
You can install the "Task Parallel Library for .NET 3.5" from NuGEt and use tasks that way. Then you can wrap you wcfClient.GetSiteInfoBegin and wcfClient.EndSiteInfoBegin methods with Task.Factory.FromAsync.
This is untested, but maybe something like this:
public AboutInfo GetAboutInfo()
{
AboutInfo aboutInfo = new AboutInfo();
SiteInfo siteInfo = new SiteInfo()
{
ID = site.ID
,Name = site.Name
,DatabaseVersion = "Unavailable"
};
var tasks = new List<Task<SiteInfo>>();
foreach (Site site in sites)
{
try
{
string uri = Utilities.CombineUri(site.Uri, "svc/About.svc/ws");
AboutServiceClient wcfClient = new AboutServiceClient("About");
wcfClient.Endpoint.Address = new EndpointAddress(uri);
tasks.Add(Task<SiteInfo>.Factory.FromAsync(wcfClient.GetSiteInfoBegin, wcfClient.EndSiteInfoBegin, null)
.ContinueWith(t =>
{
siteInfo.DatabaseVersion = t.Result.DatabaseVersion.DatabaseVersion;
}, TaskScheduler.FromCurrentSynchronizationContext()));
}
catch (Exception e)
{ //...code stripped out...
}
}
Task.WhenAll(tasks.ToArray()).ContinueWith
( ts =>
{
ts.ForEach( t => aboutInfo.Sites.Add(t.Rrsult);
});
return aboutInfo;
}
Looking to convert some .asmx webservices to REST. I am not interested in WCF style, rather a more simple way if that makes sense. All my operations will be CRUD. I have read about REST and HTTPWebRequest and HttpWebResponseDoes anyone know the simpleset way to do this? My asmx code is below.. A quick REST service of this would be appreciated if anyone can help. Thank You!
[WebMethod]
public Products[] GetProducts()
{
ProductDA dataAccess = new ProductDA();
List<Product> obj = new List<Product>();
obj = dataAccess.GetProducts();
return obj.ToArray();
}
Have you checked out the new ASP.NET WebAPI? Sounds like it would be a good choice if you're able to target .NET 4 as a platform. You should be able to use your existing service implementation with virtually no changes.
I would look at the new Web API, which is currently part of the ASP.NET MVC 4 beta (it has a go-live license). Here is Scott Guthrie demonstrating how to use it:
http://channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/2364
I should note that you do not have to convert your web site to MVC in order to use this.
Asmx file can also be used for rest api creation (Which is not the recommended approach).
This can be achieved by the below code snippet.
[ScriptService]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Randezvous : WebService
{
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public void getUnitPersonels(string user, string pass, decimal unitNo)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Context.Response.Clear();
Context.Response.ContentType = "application/json";
#region ..:: Kullanıcı şİfre Kontrol ::..
if (!(unit == "xxx" && pass == "yyy"))
{
string msg = "User or pass is wrong.";
Context.Response.Write(serializer.Serialize(msg));
return;
}
#endregion
List<Personels> personels = _units.getUnitPersonels(unitNo);
string jsonString = serializer.Serialize(personels);
Context.Response.Write(jsonString);
}
}
You can test this code in c# with the code that is shown below:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var builder = new UriBuilder("http://localhost:18511/Randezvous.asmx/getUnitPersonels");
var query = HttpUtility.ParseQueryString(builder.Query);
query["unitNo"] = "0";
builder.Query = query.ToString();
string url = builder.ToString();
var result = Task.FromResult(client.GetAsync(url).Result).Result.Content;
var resultJson = result.ReadAsStringAsync().Result;
}
I'm having a problem with calling a web service request in C#.
The service and request are working fine in Soap UI with the option 'Authenticate Preemptively' enabled (File, Preferences, HTTP Settings). Without this setting enabled the service returns a 'Java.Lang.NullPointerException'.
The problem I'm having is that I do not know how to enable this setting in a C# context.
I have a .NET 3.5 class library which holds a so called service reference to the specific service. This is a simple code snippet;
try
{
CatalogService.CatalogChangeClient service = new CatalogService.CatalogChangeClient();
service.ClientCredentials.UserName.UserName = "fancydress";
service.ClientCredentials.UserName.Password = "47fda9cb4b51a9e";
service.ClientCredentials.SupportInteractive = true;
ProductUpdate[] products = new ProductUpdate[1];
products[0] = new ProductUpdate();
products[0].ProductCode = "00001";
products[0].ProductDescription = "TestProduct";
string result = service.UpdateProducts(products);
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
Update after first reply.
The CatalogService.CatalogChangeClient class seems to implement the WCF abstract class
System.ServiceModel.ClientBase<TChannel>
End Update
Could anyone help me set this property?
You could try and override the GetWebRequest method from your generated client stub. I have used this once and that solved my problem.
Look at the following URL:
http://www.eggheadcafe.com/community/wcf/18/10056093/consuming-webservices-and-http-basic-authentication.aspx
Scroll a bit down.
Here's the code from the link:
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
HttpWebRequest request;
request = (HttpWebRequest)base.GetWebRequest(uri);
if (PreAuthenticate)
{
NetworkCredential networkCredentials =
Credentials.GetCredential(uri, "Basic");
if (networkCredentials != null)
{
byte[] credentialBuffer = new UTF8Encoding().GetBytes(
networkCredentials.UserName + ":" +
networkCredentials.Password);
request.Headers["Authorization"] =
"Basic " + Convert.ToBase64String(credentialBuffer);
}
else
{
throw new ApplicationException("No network credentials");
}
}
return request;
}
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.