Xamarin Forms Android error System.Net.WebExceptionStatus.TrustFailure - c#

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.

Related

HttpClient.GetByteArrayAsync(…) “deadlock” when there is no internet connection in .NET standard library calling from UWP

I am developing a UWP application for a document management system. I am trying to open documents from my application. When I click the open document, It is going to download the document and then open in the default application. But the problem is document is not downloaded if the internet is a disconnect in the middle of the process. It means when httpClient is already called. My code is as following
public async Task<DownloadFileDetail> DownloadFileAsync(int dmsFileId)
{
if (dmsFileId <= 0)
{
throw new ArgumentException("Invalid DMS File Id");
}
try
{
return await Task.Run(async () =>
{
DownloadFileDetail fileDetail = new DownloadFileDetail()
{
DocId = dmsFileId
};
string apiUrl = $"files/download/latest/{dmsFileId}";
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(BaseApiUrl);
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {SessionStore.Instance.AuthToken}");
var response = await httpClient.GetByteArrayAsync(apiUrl); --> gone deadlock
fileDetail.Content = response;
return fileDetail;
});
}
catch (Exception ex)
{
}
return new DownloadFileDetail()
{
DocId = dmsFileId
};
}
Download process called as UWP->.NET Standard Library (holds above code). It will be great if someone helps me to solve the problem.
Thanks
ss
Update:
The above code is working on my laptop and not working on any other laptop in dev environment
when there is no internet connection in .NET standar library calling from UWP
If the deadlock only occurs in no internet connection environment, you could check if internet is available before sending http request. Please check this NetworkHelper.
if (NetworkHelper.Instance.ConnectionInformation.IsInternetAvailable)
{
// sending the request.
}
First, remove the Task.Run(async () => ...) call:
try
{
DownloadFileDetail fileDetail = new DownloadFileDetail()
{
DocId = dmsFileId
};
string apiUrl = $"files/download/latest/{dmsFileId}";
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(BaseApiUrl);
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {SessionStore.Instance.AuthToken}");
var response = await httpClient.GetByteArrayAsync(apiUrl); --> gone deadlock
fileDetail.Content = response;
return fileDetail;
}

Web service call from visual studio xamarin in ios

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/

How to Authenticate a xamarin.Forms app using AAD

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

Mobile Service Client throws exception when response is not found

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.

SOAP webservice used to work in XAMARIN.FORMS, but now it doesn't work on any device below Android 6.0

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!

Categories

Resources