Xamarin HttpClient GetStringAsync seems inconsistent - c#

I'm pulling my hair out on this.
I'm working on a Xamarin Forms project and Prism. I have this function that calls Google Map Autocomplete. This past few days it work, but now it doesn't. I traced it and found that my GetStringAsync is not returning anything. It just stop at that function, no errors thrown.
This is my code.
public async Task<List<PredictionsItem>> Predict(string address)
{
List<PredictionsItem> predictions = new List<PredictionsItem>();
try
{
if (Connectivity.NetworkAccess == NetworkAccess.Internet)
{
HttpClient client = new HttpClient();
string _url = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=" + address +"&types=geocode&components=country:ph&key=" + Key;
string response = await client.GetStringAsync(_url);
client.Dispose();
var result = JsonConvert.DeserializeObject<Root>(response);
return result.predictions;
}
return predictions;
}
catch
{
return predictions;
}
}
It just stops here "string response = await client.GetStringAsync(_url);". No errors thrown.
Am I missing something or doing something wrong?

Related

Xamarin.Forms HttpClient.PostAsync never returns on Android

I am working on a Xamarin.Forms multi-platform app, which shall utilize a custom Asp.Net Core Web Api. I've written the code to make the calls to the API, but it fails on Android.
I am suspecting some kind of SSL issue... but we'll get to that in a second.
I am using HttpClient and HttpClient.PostAsync for the calls and on Android - and only on Android - it comes to an deadlock on the PostAsync.
I therefore created a minimum example and started from the beginning:
HttpClient client = new HttpClient();
return client.GetAsync("https://www.google.com").Result.Content.ReadAsStringAsync().Result;
Is working fine, then I tried it with my domain, which contains a simple Asp.Net page, which also worked:
HttpClient client = new HttpClient();
return client.GetAsync("https://aircu.de").Result.Content.ReadAsStringAsync().Result;
Next step was to try and address my API:
HttpClient client = new HttpClient();
var response = client.GetAsync("https://api.aircu.de").Result;
return response.Content.ReadAsStringAsync().Result;
This now fails on Android, the line var response = client... never returns. However it is working on iOS and (in a testing .net core console application) on windows, too. If i add a timeout to the client, the application of course will run into that timeout and throw an exception.
I've tried using async Task<string> and var response = await client.GetAsync("https://api.aircu.de").ConfigureAwait(false);, didn't work either...
I cannot find the problem; I've tried adding a custom handler for the server certificates, which did not help. I added Accept for the client and MediaType for a string content I added; didn't work either.
I've changed the Android HttpClientImplementation to Standard, Legacy and Android; didn't change a thing.
What do I need to do, to make this request working on Android?
EDIT://
To make it crystal clear: There is no deadlock issue! When I use any other url, like my base-url https://aircu.de it's working fine. The function only does not return, when using the subdomain https://api.aircu.de
I also moved my demo code to a VM...
private HttpClient client = null;
public MainPageViewModel()
{
client = DependencyService.Get<IHttpsClientFactory>().CreateClient();
client.Timeout = TimeSpan.FromSeconds(5);
}
[RelayCommand]
public void Click()
{
Task.Factory.StartNew(requestTaskFn);
}
private async void requestTaskFn()
{
var result = await makeRequest();
Device.BeginInvokeOnMainThread(async () => await Application.Current.MainPage.DisplayAlert("Result", result, "OK"));
}
private async Task<string> makeRequest()
{
string responseJson = "";
try
{
var response = await client.GetAsync("https://api.aircu.de").ConfigureAwait(false);
responseJson = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
throw;
}
return responseJson;
}
I also added an AndroidClientHandler in the IHttpsClientFactory:
var handler = new AndroidClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
return new HttpClient(handler);

How to retrieve custom error object from a failed httpClient call?

I'm quite new to .Net Core Web API and have spent a few days looking for an answer but couldn't find exactly what I am looking for. What I want to know is how to retrieve the custom object that is pass from an API action back to the client via an ActionResult (BadRequest(), NotFound()...etc.)
So I created a new Web API project in VS2019 and updated the default Get method of the WeatherForecastController like this:
[HttpGet]
public ActionResult<IEnumerable<WeatherForecast>> Get()
{
return NotFound(new { Message = "Could not find data", Suggestion = "Refine your search" });
}
When testing in Postman, I can get the expected output of Status = 404 and body is
{
"message": "Could not find data",
"suggestion": "Refine your search"
}
But in the client project, I just don't know how I can retrieve that custom error object.
My client code is like this:
public async Task OnGet()
{
try
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://localhost:44377/");
WeatherForcasts = await httpClient.GetFromJsonAsync<WeatherForcast[]>("weatherforecast");
}
catch (HttpRequestException ex)
{
hasError = true;
}
}
I understand that if the API action does not return a success status code (such as 200) then this will raise an HttpRequestException. But I can't find a away to get that custom error object out from the HttpRequestException.
Any help will be very much appreciated!
Change your code to this:
public async Task OnGet()
{
using var client = new HttpClient();
var baseAddress ="https://localhost:44377");
client.BaseAddress = new Uri(baseAddress);
var response= await client.GetAsync(baseAddress);
var statusCode = response.StatusCode.ToString(); // shoud be "NotFound"
var stringData = await response.Content.ReadAsStringAsync();
var data= JsonConvert.DeserializeObject<object>(stringData);// should be
// "{{"message":"Could not find data","suggestion": "Refine your search"}}"
....
}

Generic async HttpClient method sometimes doesn't work?

I'm creating an application with Xamarin.Forms which consume from SOAP services using POST method; I have a bunch of services that work correctly, indeed, one of these methods is used to send information in multiple cases and my problem is related with this.
I have the following HttpClient method, but sometimes doesn't work... unfortunately I don't have access to back-end code and they are not for the labour of help me with that.
Any idea about how to improve my method or get any approach to the real error? I'm stuck here, since I send the same fields each time.
public async Task<string> InvokeAsync (string uri, string xmlSOAP) {
try {
using (var handler = new HttpClientHandler () { UseCookies = false })
using (var client = new HttpClient (new NativeMessageHandler ())) {
client.DefaultRequestHeaders.Accept.Add (new MediaTypeWithQualityHeaderValue ("application/xml"));
client.DefaultRequestHeaders.Add ("Cache-Control", "no-cache, no-store, must-revalidate");
client.DefaultRequestHeaders.Add ("Pragma", "no-cache");
client.Timeout = TimeSpan.FromSeconds (timeout);
client.DefaultRequestHeaders.CacheControl.NoCache = true;
var req = new HttpRequestMessage (HttpMethod.Post, uri)
{
Content = new StringContent (xmlSOAP, Encoding.UTF8)
};
req.Content.Headers.ContentType = MediaTypeHeaderValue.Parse ("text/xml; charset=utf-8");
if (uri.ToLowerInvariant ().Equals (jsessionUrlCheck)) {
if (jsession != null && jsession.Count > 0) {
foreach (var cookie in jsession) {
req.Headers.Add ("JSESSIONID", cookie);
}
}
jsession = null;
}
HttpResponseMessage response = await client.SendAsync (req);
string responseBodyAsText = response.IsSuccessStatusCode ? await response.Content.ReadAsStringAsync () : string.Empty;
if (!string.IsNullOrEmpty (responseBodyAsText))
{
return responseBodyAsText;
}
return null;
}
} catch (Exception e) {
Debug.WriteLine ("========= InvokeAsync Exception =========");
Debug.WriteLine ("Error: " + e.Message);
return null;
}}
Any idea about how to [...] get any approach to the real error?
It sounds like you don't really know what exactly happens when it "doesn't work". The way you approach the real error is by finding out what exactly happens in this code when it is reported not to work.
Do you have logs? Check the logs. If the exception is there, that should point you in the right direction. Exception not there? Maybe start logging the data received too. No logs? Start logging; there's no better way to handle intermittent failures that you can't reproduce on demand.

HttpClient GetAsync not working as expected

When testing my web API with Postman my API get executes fine!
When it comes to running the code with HttpClient in my client application the code executes without error but without the expected result on the server.
What could be happening?
From my client application:
private string GetResponseFromURI(Uri u)
{
var response = "";
HttpResponseMessage result;
using (var client = new HttpClient())
{
Task task = Task.Run(async () =>
{
result = await client.GetAsync(u);
if (result.IsSuccessStatusCode)
{
response = await result.Content.ReadAsStringAsync();
}
});
task.Wait();
}
return response;
}
Here is the API controller:
[Route("api/[controller]")]
public class CartsController : Controller
{
private readonly ICartRepository _cartRepo;
public CartsController(ICartRepository cartRepo)
{
_cartRepo = cartRepo;
}
[HttpGet]
public string GetTodays()
{
return _cartRepo.GetTodaysCarts();
}
[HttpGet]
[Route("Add")]
public string GetIncrement()
{
var cart = new CountedCarts();
_cartRepo.Add(cart);
return _cartRepo.GetTodaysCarts();
}
[HttpGet]
[Route("Remove")]
public string GetDecrement()
{
_cartRepo.RemoveLast();
return _cartRepo.GetTodaysCarts();
}
}
Note these API calls work as expected when called from Postman.
You shouldn't use await with client.GetAsync, It's managed by .Net platform, because you can only send one request at the time.
just use it like this
var response = client.GetAsync("URL").Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
var dataObjects = response.Content.ReadAsAsync<object>().Result;
}
else
{
var result = $"{(int)response.StatusCode} ({response.ReasonPhrase})";
// logger.WriteEntry(result, EventLogEntryType.Error, 40);
}
You are doing fire-and-forget approach. In your case, you need to wait for the result.
For example,
static async Task<string> GetResponseFromURI(Uri u)
{
var response = "";
using (var client = new HttpClient())
{
HttpResponseMessage result = await client.GetAsync(u);
if (result.IsSuccessStatusCode)
{
response = await result.Content.ReadAsStringAsync();
}
}
return response;
}
static void Main(string[] args)
{
var t = Task.Run(() => GetResponseFromURI(new Uri("http://www.google.com")));
t.Wait();
Console.WriteLine(t.Result);
Console.ReadLine();
}
Simple sample used to get page data.
public string GetPage(string url)
{
HttpResponseMessage response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
string page = response.Content.ReadAsStringAsync().Result;
return "Successfully load page";
}
else
{
return "Invalid Page url requested";
}
}
I've had a problem with chace control when using httpclient.
HttpBaseProtocalFilter^ filter = ref new HttpBaseProtocolFilter();
filter->CacheControl->ReadBehavior = Windows::Web::Http::Filters::HttpCacheReadBehavior::MostRecent;
HttpClient^ httpClient = ref new HttpClient(filter);
I'm not really sure what the expected results are or what results your getting at all so this is really just a guessing game right now.
When I POST something using HttpClient I found adding headers by hand seemed to work more often than using default headers.
auto httpClient = ref new HttpClient();
Windows::Web::Http::Headers::HttpMediaTypeHeaderValue^ type = ref new Windows::Web::http::Headers::HttpMediaTypeHeaderValue("application/json");
content->Headers->ContentType = type;
If I don't do these 2 things I found, for me anyways, that half the time my web requests were either not actually being sent or the headers were all messed up and the other half of the time it worked perfectly.
I just read a comment where you said it would only fire once, that makes me think it is the cachecontrol. I think what happens is something (Windows?) sees 2 requests being sent that are the exact same, so to speed things up it just assumes the same answer and never actually sends the request a 2nd time

Why HttpResponse always return 404 status code

I am trying to send request to http://localhost/apptfg/get_biography_group?nombre_grupo=fondoflamenco which is a php based webservice that access to mysql database and retrieve information about the group but I always get a 404 not found when I execute the application in my windows phone 8 device, however when I debug the url in fiddler I get the right result which must be {"success":1,"group":[{"nombre_grupo":"fondoflamenco","anyo_creacion":"2006","descripcion":"Fondo Flamenco Flamenco is a group formed by three young Sevillian. Astola Alejandro Soto, Antonio Sanchez and Rafael Ruda M.R","musicos":"Rafael Ruda,Antonio Manuel Rios,"}]}
this is the HttpClient code I use in my application:
public async Task<string> makeHttpRequest(string group_name)
{
var resultstring = String.Empty;
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "text/html");
try
{
resultstring = await client.GetStringAsync(new Uri("http://localhost/apptfg/get_group_biography.php?nombre_grupo=" + group_name));
client.Dispose();
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
return resultstring;
}

Categories

Resources