We are developing an iOS shopping cart application in c# and Visual Studio 2017 for Xamarin. We are using rest web services, Here I could not call web services. when I call web service I am getting null response with an error[ConnectFailure (Connection refused)]. My question is How to get a value from localhost URL like [http://localhost:56207/api/Users/Raju/Password#123]. When I enter this URL in the browser I am getting true or false depending upon user and password validation.I request you to help me to resolve this issue.I paste the code in below:
public class RestInterfaceImp : IRestLogin
{
HttpClient client;
private const string WebServiceUrl = "http://localhost:56207/api/Users/Raju/Password#123";
public async Task<List<User>> RefreshDataAsync()
{
try
{
var httpClient = new HttpClient();
var resp = await httpClient.GetAsync(WebServiceUrl);
if (resp.IsSuccessStatusCode)
{
var respStr = await resp.Content.ReadAsStringAsync();
var listaAtletas = JsonConvert.DeserializeObject<List<User>>(respStr);
}
}
catch (HttpRequestException e)
{
Debug.WriteLine(e.InnerException.Message);
}
return null;
}
}
Whenever we need to expose a local api to a simulator like you are doing, we use ngrok:
https://github.com/inconshreveable/ngrok
For some reason their website is down right now so it's possible they are no longer a thing but here is the url:
https://ngrok.com/
Related
I recently implemented custom authentication with Azure Mobile App - All the server side works fine and also my web application which is using that mobile app service is working fine. I tested the server-side in details with POSTMAN and with different scenarios, everything works fine until I try to LoginAsync on Xamarin.
When I pass email and password in POSTMAN, I get the following response as a clear indication that it is working
but when I send a request from my app using LoginAsync I get the following error.
Cannot access child value on Newtonsoft.Json.Linq.JValue
My code to send request is fairly simple as following
public async Task<bool> Authenticate()
{
string username = "todo#gmail.com";
string password = "todo";
string message = string.Empty;
var success = false;
var credentials = new JObject
{
["email"] = username,
["password"] = password
};
try
{
MobileServiceUser user = await client.LoginAsync("CustomAuth", credentials);
if (user != null)
{
success = true;
CreateAndShowDialog("OK", "Auth");
}
}
catch (Exception ex)
{
CreateAndShowDialog(ex, "Auth Error");
}
return success;
}
where I am calling it as follows
private MobileServiceClient client;
client = new MobileServiceClient(applicationURL);
await Authenticate();
Any idea why I am getting Cannot access child value on Newtonsoft.Json.Linq.JValue error?
Cheers
EDIT POST
As a workaround, I am temporarily using InvokeApiAsync with JObject.FromObject instead of LoginAsync
await client.InvokeApiAsync("/.auth/login/CustomAuth", JObject.FromObject(credentials), HttpMethod.Post, null);
I am still not sure why LoginAsync does not work - Until I find a solution I will keep using InvokdeApiAsync as a workaround
AFAIK, your initialization for credentials is correct. For the below error:
Cannot access child value on Newtonsoft.Json.Linq.JValue
I checked your testing result via POSTMAN and found that you did not return userId to your client. The essential properties returned to your client would look like as follows:
{
"authenticationToken":"***",
"user":{
"userId":"***"
}
}
When using MobileServiceClient.LoginAsync, the client SDK would internally invoke LoginAsync() method under MobileServiceAuthentication.cs as follows:
JToken authToken = JToken.Parse(response);
// Get the Mobile Services auth token and user data
this.Client.CurrentUser = new MobileServiceUser((string)authToken["user"]["userId"]);
this.Client.CurrentUser.MobileServiceAuthenticationToken = (string)authToken[LoginAsyncAuthenticationTokenKey];
You would find that it would try to extract the userId property under user to construct the MobileServiceUser instance and assign to MobileServiceClient.CurrentUser.
I am a newbie to Mobile app and took a new project recently. I'm developing a Xamarin.Forms App and trying to get an access token from Azure Active Directory in order able to get access to some Web API services on an other server.
using this code below I was able to get the response on console app but not from Xamarin.forms.
Q1. How can I implement this functionality in my PCL?
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Xamarin.Auth;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.Serialization.Json;
internal class UtilityClass
{
public static async Task<string> GetTokenAsync()
{
var authenticationContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(aadInstance, null);
ClientCredential clientCredential = new ClientCredential(clientId, clientSecret);
try
{
if (Token == null)
{
AuthenticationResult result = await authenticationContext.AcquireTokenAsync(audienceApi, clientCredential);
if (result == null)
throw new InvalidOperationException("Failed to obtain the JWT token");
Token = result.AccessToken;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return Token;
}
public async static Task<TReturn> CallApiAsync<TReturn>(string URI)
{
TReturn result = default(TReturn);
HttpClient client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
client.BaseAddress = new Uri(audienceApi);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await GetTokenAsync());
var uri = new Uri(string.Format(URI, string.Empty));
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<TReturn>(content);
}
return result;
}
}
with in my PCL's app Method, try to access it this way
public App ()
{
var CustomerContactList = UtilityClasses.CallApiAsync<List<CustomerContact>>();
}
Q2. I want to run my web API service on a local server and debug the call from Xamarin.Forms App, so how can I configure my Visual Studio 2015 and Android Emulator to get access to https://localhost:PortNumber/api/getCustomerContacts?
Thank You in Advance, for your support
You need to configure your local IIS Express to handle requests it receives on your external IP, follow steps here, debug steps if you get stuck in comments
Cheers
Q1. How can I implement this functionality in my PCL?
There is something that is suitable for you if you take a look at this link
https://forums.xamarin.com/discussion/19021/using-xamarin-auth-with-xamarin-forms
Substitute the auth with the below redirectUrl and authorizeUrl should work, although i haven't tested this.
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code
var auth = new OAuth2Authenticator (
clientId: "clientId",
scope: "",
authorizeUrl: new Uri ("https://login.microsoftonline.com/{yourtenant}/oauth2/authorize?"),
redirectUrl: new Uri ("urn:ietf:wg:oauth:2.0:oob"));
Q2. I want to run my web API service on a local server and debug the call from Xamarin.Forms App, so how can I configure my Visual Studio 2015 and Android Emulator to get access to https://localhost:PortNumber/api/getCustomerContacts?
In your IIS , expose your local web site in a specific port, then in your android emulator you can use
https://10.0.2.2:portNumber/api/getCustomerContacts
I am having a challenge with my Xamarin Forms Android app in Visual Studio 2015 Enterprise edition.
Below is my helper class which makes all calls to my WebAPIs
public string CallWebService(string ps_URI)
{
HttpClient lobj_HTTPClient = null;
HttpResponseMessage lobj_HTTPResponse = null;
string ls_Response = "";
string ls_Prefix = "";
//We assume the internet is available.
try
{
ls_Prefix = Device.OnPlatform<string> (App.APISecurePrefix, App.APIPrefix, App.APIPrefix);
//Get the Days of the Week
//lobj_HTTPClient = new HttpClient(new NativeMessageHandler());
lobj_HTTPClient = new HttpClient();
lobj_HTTPClient.BaseAddress = new Uri(App.APISecurePrefix);
lobj_HTTPClient.DefaultRequestHeaders.Accept.Clear();
lobj_HTTPClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var lobj_Result = lobj_HTTPClient.GetAsync(ps_URI);
while (!lobj_Result.IsCompleted)
{
Debug.WriteLine("WebAPICaller-CallWebService-1: URI:" + ps_URI);
Task.Delay(100);
}
//GEt the http response object
lobj_HTTPResponse = lobj_Result.Result;
if (!lobj_HTTPResponse.IsSuccessStatusCode)
{
App.ProcessException(new Exception(lobj_HTTPResponse.ReasonPhrase));
}
else
{
var lobj_DataResult = lobj_HTTPResponse.Content.ReadAsStringAsync();
while (!lobj_DataResult.IsCompleted)
{
Debug.WriteLine("WebAPICaller-CallWebService-2");
Task.Delay(100);
}
ls_Response = lobj_DataResult.Result;
}
}
catch (Exception ex)
{
App.ProcessException(ex);
}
finally
{
if (lobj_HTTPClient != null)
lobj_HTTPClient.Dispose();
if (lobj_HTTPResponse != null)
{
lobj_HTTPResponse.Dispose();
}
Debug.WriteLine("WebAPICaller-CallWebService-1: Done");
}
return ls_Response;
}
It works fine on Windows phones but when I attempt to make WebAPI calls on the Android Emulator an exception is thrown as follows (See the TrustFailure):
Please note I am calling the WebAPI over a secure connection (https) and the server I am contacting does support both HTTP and HTTPS access to the WebAPIs.
I am using the latest stable version of Xamarin forms (2.3.3.180). I have removed the use of ModernHTTPClient. I did try to use the latest beta version of Xamarin Forms but then my needed components would not install so I went back to the last stable version.
Any idea how I can resolve this? If the solution involves doing anything with the Java or Android components outside of Visual Studio 2015, please provide specific details as I am not that familiar with how to do many Android / Java related things.
I am trying to port an application from an azure mobile service to an azure web app. (the mobile service was working). I have added microsoft account authentication to the web-app, and the web app api has a MobileAppController attribute. I have a Universal windows app front end that calls the api. The app first checks if a player is in the database, if not I get a not found response. If I call the method using the following code with the MobileServiceClient I get an exception.
private async Task<HttpResponseMessage> GetAZMAsyncP(string apiext, IDictionary<string,string> param )
{
string myuri = String.Format("{0}{1}", urlbase, apiext);
//client is the MobileServiceClient that is correctly logged in
//I do not get response which is 404 not found, I get an exception "The request could not be completed, Not Found"
var response = await client.InvokeApiAsync(myuri, System.Net.Http.HttpMethod.Get, param);
return response;
}
If I call the api from an httpclient and add my own headers, which the mobile client is supposed to do for me, then I get the response as requested. Here is the code:
private async static Task<HttpResponseMessage> GetAZAsync(string apiext)
{
string completeUrl = String.Format("{0}{1}", urlbase, apiext);
// Call out to AZ
using (var http = new HttpClient())
{
// http.BaseAddress = new Uri(completeUrl);
HttpRequestMessage rq = new HttpRequestMessage()
{
RequestUri = new Uri(completeUrl),
Method = HttpMethod.Get
};
addauthheader(rq);
var response = await http.SendAsync(rq);
return response;
}
}
private static void addauthheader(HttpRequestMessage rq)
{
MobileServiceUser user = App.client.CurrentUser;
rq.Headers.Add("X-ZUMO-FEATURES", "AT,QS");
rq.Headers.Add("X-ZUMO-INSTALLATION-ID",
"ff90f37e-0c03-4c52-a343-af711752e383");
rq.Headers.Add("X-ZUMO-AUTH", user.MobileServiceAuthenticationToken);
rq.Headers.Add("Accept", "application/json");
rq.Headers.Add("User-Agent", "ZUMO/2.1");
rq.Headers.Add("User-Agent",
"(lang = Managed; os = Windows Store; os_version = --; arch = X86; version = 2.1.40707.0)");
rq.Headers.Add("X-ZUMO-VERSION",
"ZUMO/2.1(lang = Managed; os = Windows Store; os_version = --; arch = X86; version = 2.1.40707.0)");
rq.Headers.Add("ZUMO-API-VERSION", "2.0.0");
}
You can try this out as it is live (and buggy).
https://gamenote2.azurewebsites.net/api/Players?displayname=Paul Goldschmidt&teamid=arizona-diamondbacks
Should give you a 404,
https://gamenote2.azurewebsites.net/api/Players?displayname=Chase Utley&teamid=los-angeles-dodgers
should give you a chase utley object. (YOu will be asked to log into a Microsoft Account).
So my questions: 1. Can I fix the mobileclient call to get a response instead of an execption
2. Is there any good reason for me to be spending so much time on this.
If you examine the exception, you will note that the status code is in there - it's just in a property that is not serialized. Just surround your InvokeApiAsync() call with a try/catch and test for the StatusCode. It should be a lot easier than writing your own HTTP Client code for the same purpose.
Specifically, MobileServiceInvalidOperationException contains the HttpResponse of the failed request, so you can check exception.Response.StatusCode value.
Suddenly i got reports form user that a list in my app didn't show any data - It worked fine on my device. Later i found out that everything works fine and dandy on all android devices with 6.0 installed - every android version below 6.0(Marshmallow), wont get data transferred! I am at a loss - have no idea what has happened or how to fix this.... Help!
Does anyone recognize this or have possible solution to how this can be fixed?
In my forms app i have a portable library where i have a class handling the SOAP webservice, it is implemented like below:
public class soapwebservice
{
//private Uri baseUri = new Uri("uri");
private static DataConnection _instance = null;
private HttpClient client = null;
//Contructor
private DataConnection()
{
client = new HttpClient(new NativeMessageHandler());
client.BaseAddress = baseUri;
}
public static DataConnection Instance { get { if (_instance == null) _instance = new DataConnection(); return _instance; } }
public async Task<Other.ServiceResponse> RefreshRouteList()
{
try
{
var soapString = this.constructRefreshsoap();
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("SOAPAction", "https://trolderuterne.play2know.dk/GetRoutes");
var content = new StringContent(soapString, Encoding.UTF8, "text/xml");
using (var response = await client.PostAsync("/Classes/mobileServices.asmx", content))
{
if (response.IsSuccessStatusCode)
{
var soapResponse = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Other.ServiceResponse>(ParseSoapResponse(soapResponse));
}
return new ServiceResponse { Code = Codes.ServerError, Message = response.StatusCode.ToString() };
}
}
catch (Exception ex)
{
return new ServiceResponse
{
Code = Codes.ServerError,
Message = ex.Message
};
}
finally
{
}
}
The error message i get when running the app is:
"Error: NameResolutionFailure"
I have now tried to consume the webservice directly in the android project instead of the PCL.
Just to mention it i have my webservice going over a proxy, due to security. It still works on 6.0, but when i go to a simulator running 4.4 i still get error: "Error: NameResolutionFailure".
I tried grabbing the original webservice directly from our server and I get the following error message: "Error: ConnectFailure (Network is unreachable)"
Hopefully someone has some insight, and can tell me how to get the data i need from the webservice in devices below Android 6.0!
NameResolutionFailure looks like a DNS error. But you're going through a proxy, so who knows what they are doing. Did they change something recently? Can you try to resolve the name into an IP both with and without the proxy, over WiFi and mobile data too?
ConnectFailure looks like you cannot connect to the server. Can you try to get data directly from the IP address instead? Try both directly and through the proxy, over WiFi and mobile data too.
Android 6 changed some things related to SSL, could that be affecting it?
I was asked by XAMARIN suppport to install the beta version og their software and this "kinda" solved the issue. I can now consume a SOAP webservice, but the service cant be SSL encrypted, if you want to use android below 6.0.
So i removed the SSL encryption from our proxy and now it works with all versions!