HttpClient web service request gets canceled when iOS app is backgrounded - c#

If I make a web service request and background the iOS app and foreground it again, I get an exception that the request has been canceled. Is this a bug or the way iOS operates? I can't find any documentation on this. What's the right way to implement a reliable web service mechanism using Xamarin Forms? I followed the HttpClient example as documented here.

This works for me both in the foreground and in the background.
maybe you also need to enable background modes in your info.plist
private async Task<string> UsaHttpClient()
do
{
...
...
...
await Task.Run(async () =>
{
HttpClient Client = new HttpClient();
Client.BaseAddress = new Uri("https://services.xxxxx.com/ServiceApi/");
var response = Client.GetStringAsync("api/function?Parametro...").Result;
HttpResponseMessage resp = new HttpResponseMessage();
resp.Content = new StringContent(response, Encoding.UTF8, "application/json");
r = response;
resp.Dispose();
Client.Dispose();
await Task.Delay(second for delay);
});
} while (X == anyCondition);
}

Related

Xamarin.Forms: default instead of AndroidClientHandler as HttpClient implementation

I work on an existing Xamarin.Forms app, where we need to integrate API calls to external providers.
For this, we use my client's custom HttpClient library.
Until now, the Android HttpClient was set to AndroidClientHandler.
But after a basic call to a provider's API, we get a "400 - bad request" answer:
HttpContent content = new StringContent(string.Empty);
if (tObject != null)
{
string data = JsonSerializer.Serialize(tObject, new JsonSerializerOptions() { IgnoreNullValues = true, IgnoreReadOnlyProperties = true });
content = new StringContent(data, Encoding.UTF8, "application/json");
}
HttpResponseMessage apiResponse = await _client.PostAsync(route, content);
string responseData = await apiResponse.Content.ReadAsStringAsync();
If we set the Android HttpClient to default, all works fine.
But it seems that it's better choice to use the AndroidClientHandler.
So would you have suggestions to investigate and identify the issue related to the AndroidClientHandler?

App goes into Break Mode when I try to use Json with HttpClient

I am trying to post data from my app from a register page to a web service (testing with requestb.in) however when I try to use the below code it puts the app into break mode, then when I use break points to find where the problem is it just shows that "await PostRequest(...)" is causing the problem.
I have installed System.Net.Http on both the Portable project and the android project.
public async Task<JObject> PostAsync(string uri, string data)
{
var httpClient = new HttpClient();
var response = await httpClient.PostAsync(uri, new StringContent(data));
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
return await Task.Run(() => JObject.Parse(content));
}
Then for the button clicked where this method is called:
async void NextBtnClicked(object sender, EventArgs)
{
await PostAsync("https://requestb.in/MYURL", Username.Text);
}
Username.Text is the string from an entry field in the XAML class, This will recreate my problem
Here is the generic method I made to post data to an API.
As #maccettura pointed out above, it is best practice to reuse HttpClient and I've included that in the code, below.
HttpClient Post
static readonly Lazy<HttpClient> _clientHolder = new Lazy<HttpClient>(() => CreateHttpClient(TimeSpan.FromSeconds(60)));
static HttpClient Client => _clientHolder.Value;
protected static async Task<HttpResponseMessage> PostObjectToAPI<T>(string apiUrl, T data)
{
var stringPayload = await Task.Run(() => JsonConvert.SerializeObject(data)).ConfigureAwait(false);
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
try
{
return await Client.PostAsync(apiUrl, httpContent).ConfigureAwait(false);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
return null;
}
}
static HttpClient CreateHttpClient(TimeSpan timeout)
{
var client = new HttpClient();
client.Timeout = timeout;
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
return client;
}
This snippet was taken from my BaseHttpClientService.cs that I copy/paste into any app that needs to use HttpClient:
https://github.com/brminnick/XamList/blob/master/XamList/Services/BaseHttpClientService.cs
Troubleshoot your application using UWP so that you can see what kind of exception it is throwing. Try also to downgrade the two Nuget packages.

How to call asynchronous method synchronously in Windows Phone 8

We have existing iOS application developed using Xamarin.Forms. Now we want to extend to both Android and Windows Phone. In the existing application, all the web service calls are made synchronously. Windows phone supports only asynchronous calling, so we thought of wrapping the asynchronous calls to synchronous.
We are using HttpClient.PostAsync method to access the service. Once the execution hits PostAsync method, the phone hangs. The code to call the service is as follows:
private static async void CallService(System.Uri uri)
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Host = uri.Host;
client.Timeout = System.TimeSpan.FromSeconds(30);
HttpContent content = new StringContent("", Encoding.UTF8, "application/xml");
var configuredClient = client.PostAsync(uri, content).ConfigureAwait(false);
var resp = configuredClient.GetAwaiter().GetResult();
resp.EnsureSuccessStatusCode();
responseString = resp.StatusCode.ToString();
resp.Dispose();
client.CancelPendingRequests();
client.Dispose();
}
}
I know this is because of blocking the UI thread, so only I implemented ConfigureAwait(false) but that didn't work at all. I tried with System.Net.WebClient also but the same result.
Now, how I will make this asynchronous call to process synchronously in Windows Phone 8?
First of all avoid using async void methods,because you can't easily wait for its completion. Return Task instead, being inside async method you don't need to do something special to return a Task. Compiler does all the work for you.
You need to await the call to HttpClient.PostAsync, that should be enough to keep the UI responsive.
private static async Task CallService(System.Uri uri)
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Host = uri.Host;
client.Timeout = System.TimeSpan.FromSeconds(30);
HttpContent content = new StringContent("", Encoding.UTF8, "application/xml");
var resp = await client.PostAsync(uri, content);// Await it
resp.EnsureSuccessStatusCode();
responseString = resp.StatusCode.ToString();
resp.Dispose();
client.CancelPendingRequests();
}
}
Note: I've removed the ConfigureAwait(false) as that's not required. If you really need it, you may add it back.

How to consume a WCF Service in Windows Phone 8.1

I am trying to call a WCF service from a windows phone 8.1 app, the option to add a service reference no longer exists.
I tried this:
HttpClient httpClient = new System.Net.Http.HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://serverURl/serviceName.svc/methodName?variableName=value");
HttpResponseMessage response = await httpClient.SendAsync(request);
string data = await response.Content.ReadAsStringAsync();
But it didnt work, the string is always empty.
N.B The server is also not local host so im not facing the problem of connecting from windows phone emulator to local host.
Try this.
If its not working, let me know.
HttpClient httpClient = new System.Net.Http.HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get,"http://localhost:18362/Service1.svc/GetData");
HttpResponseMessage response = await httpClient.SendAsync(request);
string data = await response.Content.ReadAsStringAsync();
var dialog = new MessageDialog(data);
await dialog.ShowAsync();
Windows Phone Store apps in Windows Phone 8.1 do not support the System.ServiceModel namespace.
There is a workaround you can
Read here.
You can use System.Net.Http :
public async Task<string> GetMethod(string url)
{
HttpClient client = new HttpClient();
var response = await client.GetAsync(url); // The Get Process to get result from WCF service
string result = await response.Content.ReadAsStringAsync(); // Get Json string result
return result;
}
}

ASP.Net Web API Request URI Error

I have an ASP.Net Web API that generally works fine. I have a Winforms client application that does GET requests. The client application runs on our corporate network (the API is hosted as an Azure Website). Occasionally, and inconsistently, the HttpClient calls I make add what seem to be corporate URLs in front of my GET call.
Example: I try to call send an HttpClient request to the following URL: 'http://xyzxyz.azurewebsites.net/api/user/1'
but the actual request made is:
'http://usgaabc1iru01/B0000D0000N0001F0000S0000R0004/http://xyzxyz.azurewebsites.net/api/user/1'
This obviously causes an error.
I've asked our IT department what may be happening and they are at a loss. Hoping someone could point me in the right direction.
Edit:
Here's the code I use. First I have a static method I call everything I make a call to the API to get the HttpClient (is this awkward/bad perhaps):
public static HttpClient GetHttpClient()
{
var credentials = new NetworkCredential(GlobalVariables.CurrentUser.UserName, GlobalVariables.CurrentUser.Password);
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = false;
handler.Credentials = credentials;
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(PublicClasses.GlobalVariables.BaseUriString);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
GlobalVariables.CredentialedHttpClient = client;
}
return GlobalVariables.CredentialedHttpClient;
}
}
Here's a simple GET call I use:
public static List<Project> GetAllProjects()
{
try
{
HttpClient client = GetHttpClient();
HttpResponseMessage response = client.GetAsync("api/project").Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
var projects = response.Content.ReadAsAsync<IEnumerable<Project>>().Result;
return (List<Project>)projects;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
return null;
}
}
catch (Exception)
{
throw;
}
}
I don't have an answer for why is this happening but I came across similar issue in a web form (not a win forms client). That is solved by using base meta tag.I am not sure if that solves your problem, but you can give a try.
You can use base address with HttpClient like this (if you are not already doing this):
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://xyzxyz.azurewebsites.net/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/user/1");
if (response.IsSuccessStatusCode)
{
//add your code
}
}

Categories