Windows Phone 8.1 Runtime HttpClient async with the same result - c#

I'm working with Windows Phone Runtime API.
I declare a timer, which every 2 seconds does async http connection in Listen method.
Timer t = new Timer(Listen, null, 0, 2000);
Listen method:
private async void Listen(object state)
{
string url = "http://www.mywebpage.com?data=my_data";
string responseBodyAsText = null;
var response = new HttpResponseMessage();
var httpClient = new HttpClient();
try
{
response = await httpClient.GetAsync(new Uri(url));
responseBodyAsText = await response.Content.ReadAsStringAsync();
}
catch
{
//...
}
Debug.WriteLine(responseBodyAsText);
httpClient.Dispose();
}
My problem is that responseBodyAsText contains always the same data (given the same uri) and not as I would expect different data according to my external actions (modifying web page or different results with the same uri).
Does HttpClient remembers content during liftime of application? How can I solve this problem?

HttpClient does have caching on by default. You can turn it off by passing it an HttpBaseProtocolFilter:
var filter = new HttpBaseProtocolFilter
{
CacheControl.ReadBehavior = HttpCacheReadBehavior.MostRecent,
CacheControl.WriteBehavior = HttpCacheWriteBehavior.NoCache;
}
Side note: You could also, instead of a Timer, use Task.Delay to achieve the timer behavior (it internally uses one):
private async Task ListenAsync()
{
while (someCondition)
{
string url = "http://www.mywebpage.com?data=my_data";
string responseBodyAsText = null;
var response = new HttpResponseMessage();
using (var httpClient = new HttpClient())
{
try
{
response = await httpClient.GetAsync(new Uri(url));
responseBodyAsText = await response.Content.ReadAsStringAsync();
}
catch
{
//...
}
Debug.WriteLine(responseBodyAsText);
await Task.Delay(2000);
}
}

Related

C# async - creating a task properly

I'm creating a Task in C# but I'm not sure what I do is correct. I'm using Restsharp and in Restsharp there are two methods: Execute and ExecuteAsync. I want to do an Async call but I also need to return data to the client without blocking the execution.
Therefore I created a task which will use Execute instead of ExecuteAsync. The reason why is because I have to wait until I get a response back and then return it in the right data structure. So I thought there is no use in using ExecuteAsync if I have to await it in a Task...
My code looks as follows:
public Task<Response> ExecuteAsync()
{
return new Task<Response>(() =>
{
var client = new RestClient(URL);
if (_useBasicAuth)
{
client.Authenticator = new HttpBasicAuthenticator(_username, _password);
}
var request = RequestBuilder(_method);
var response = client.Execute(request);
return new Response()
{
HttpStatusCode = response.StatusCode,
HttpStatusDescription = response.StatusDescription,
Content = response.Content,
Cookies = ExtractCookies(response.Cookies),
Headers = ExtractHeaders(response.Headers)
};
});
}
Is this correct? The client should be able to call ExecuteAsync without blocking the execution.
I strongly suspect you should really just use ExecuteAsync and write an async method:
public async Task<Response> ExecuteAsync()
{
var client = new RestClient(URL);
if (_useBasicAuth)
{
client.Authenticator = new HttpBasicAuthenticator(_username, _password);
}
var request = RequestBuilder(_method);
var response = await client.ExecuteAsync(request).ConfigureAwait(false);
return new Response
{
HttpStatusCode = response.StatusCode,
HttpStatusDescription = response.StatusDescription,
Content = response.Content,
Cookies = ExtractCookies(response.Cookies),
Headers = ExtractHeaders(response.Headers)
};
}

HttpClient GetAsync with query string

I am using Google's GeoCoding API. I have two methods where one works and the other doesn't and I can't seem to figure out why:
string address = "1400,Copenhagen,DK";
string GoogleMapsAPIurl = "https://maps.googleapis.com/maps/api/geocode/json?address={0}&key={1}";
string GoogleMapsAPIkey = "MYSECRETAPIKEY";
string requestUri = string.Format(GoogleMapsAPIurl, address.Trim(), GoogleMapsAPIkey);
// Works fine
using (var client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(requestUri))
{
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
}
}
// Doesn't work
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("https://maps.googleapis.com/maps/api/", UriKind.Absolute);
client.DefaultRequestHeaders.Add("key", GoogleMapsAPIkey);
using (HttpResponseMessage response = await client.GetAsync("geocode/json?address=1400,Copenhagen,DK"))
{
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
}
}
My last method with GetAsync where I am sending a query string doesn't work and I am in doubt why it is so. When I introduce BaseAddress on the client the GetAsync somehow doesn't send to the correct URL.
I don't suggest adding API key into globals. Maybe you'll need to send some HTTP request outside of the API and the key will be leaked.
Here's the example that works.
using Newtonsoft.Json;
public class Program
{
private static readonly HttpClient client = new HttpClient();
private const string GoogleMapsAPIkey = "MYSECRETAPIKEY";
static async Task Main(string[] args)
{
client.BaseAddress = new Uri("https://maps.googleapis.com/maps/api/");
try
{
Dictionary<string, string> query = new Dictionary<string, string>();
query.Add("address", "1400,Copenhagen,DK");
dynamic response = await GetAPIResponseAsync<dynamic>("geocode/json", query);
Console.WriteLine(response.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
private static async Task<string> ParamsToStringAsync(Dictionary<string, string> urlParams)
{
using (HttpContent content = new FormUrlEncodedContent(urlParams))
return await content.ReadAsStringAsync();
}
private static async Task<T> GetAPIResponseAsync<T>(string path, Dictionary<string, string> urlParams)
{
urlParams.Add("key", GoogleMapsAPIkey);
string query = await ParamsToStringAsync(urlParams);
using (HttpResponseMessage response = await client.GetAsync(path + "?" + query, HttpCompletionOption.ResponseHeadersRead))
{
response.EnsureSuccessStatusCode();
string responseText = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(responseText);
}
}
}
Ciao, the problem is related with key parameter on URL. Change your code like this:
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("https://maps.googleapis.com/maps/api/");
using (HttpResponseMessage response = await client.GetAsync("geocode/json?address=1400,Copenhagen,DK&key=" + GoogleMapsAPIkey))
{
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
}
}
As google sheets said:
After you have an API key, your application can append the query parameter key=yourAPIKey to all request URLs. The API key is safe for embedding in URLs; it doesn't need any encoding.

Endless wait for async Web Response

i have the following problem, i try to wait for for an Async Web Response.
But it never finished.
public string getTermine(string trmId)
{
System.Threading.Tasks.Task<string> lisi = LoadTermine((HttpWebRequest)WebRequest.Create("http://" + curent.usrCH + apiKey + curent.phrase + apiTrmIDIS + trmId));//Request get String result like http://ajax.googleapis.com/ajax/services/search/web?v=1.0&start="+i+"&q=
lisi.Wait();
return lisi.Result;
}
private async System.Threading.Tasks.Taskstring>LoadTermine(HttpWebRequest myRequest)
{
//List<Termine> terminListe = new List<Termine>();
List<Appointment> Resu = null;
using (WebResponse response = await myRequest.GetResponseAsync())
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream()))
{
Resu = reader.ReadToEnd();
}
}
return Resu;
}
P.S. I cant use and synchronous request because this methods are an part of the Base code which is used by iOS, WinPhone and Android and i dont know why i cant get an synchronous WebResponse.
You are creating a deadlock by calling .Result on the task.
You could do something like this where the remoteUrl variabled is the url of your web service
private async System.Threading.Tasks.Task<string> LoadTermineAsync(HttpWebRequest myRequest)
{
using (var client = new HttpClient()) {
using (var request = new HttpRequestMessage(HttpMethod.Get, myRemoteUrl)) {
var response = await client.SendAsync(request).ConfigureAwait(false);
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return result;
}
}
}
For more info on Async/Await
And this evolve video is a little bit more advanced.

How to know when a A-Synchronous REST call in Windows 8.1 Mobile Library has been completed?

Background::
I am creating a Windows 8.1 Mobile SDK that will have a License Manager(LM) Module.
The client will have to Call The License Manager in their code once whenever the application starts.
The license manager will register the client and send a set of JSON Response that will be stored on the device for future validations.
The License Manager function makes REST Calls to our server.
Problem::
What will be the best place within a Windows 8.1 application to call the License Manager Function provided in the SDK?
How to make the call to the LM Synchronous, so that the client gets a chance to handle responses in case the license is not validated. Or before the client calls the other APIs included in the SDK.
Work Done::
I have created the LM function and returns the desired results.
Created a Demo App that calls the LM on a button click.
Please find the sample code below,
Client Application:
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
var x = await sdk.InitializeAsync("xxxxxxx-xxx-xxxx");
//Calling an API included in the SDK
APIResponse res = await laas.Function1_Async(par1, par2);
msg.Text = x.ToString();
}
catch (Exception ex)
{
}
}
SDK:
public async Task<int> InitializeAsync(string apiKey)
{
int status = 0;
if (!_isInitialized)
{
status = await GetLicenseInfo(localSettings);
}
this._isInitialized = true;
return status;
}
private async Task<int> GetLicenseInfo(Windows.Storage.ApplicationDataContainer localSettings)
{
APIResponse res = new APIResponse();
res.Status = -10;
res.Message = "Unknown Error!";
// Create the web request
StringBuilder data = new StringBuilder();
data.Append(*JSON String*);
string Uri = _regisUrl;
using (HttpClient client = new HttpClient())
{
Uri url = new Uri(Uri);
StringContent content = new StringContent(data.ToString(), Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Host = url.Host;
try
{
using (HttpResponseMessage response = await client.PostAsync(url, content))
{
if (response.IsSuccessStatusCode)
{
res = JsonConvert.DeserializeObject<APIResponse>(await response.Content.ReadAsStringAsync());
//Check that the Response is Success
if (res.Status == 1)
localSettings.Values["IsDeviceRegistered"] = StringCipher.Encrypt("registered");
}
}
}
catch
{
}
}
return res.Status;
}
Any Help would be appreciated.
This will change your code to be Synchronous...
Task<int> t = sdk.InitializeAsync("xxxxxxx-xxx-xxxx");
t.Wait();
var myvalue = t.Result;
.....

Shared HttpClient blocks on async requests

I'm having an issue with HttpClient and async requests. Basically i'm having an async method that is creating async requests with a shared HttpClient that is initialized in the ctor.
My problem is that it seems that the HttpClient blocks when calling my method in an async manner.
Here is my calling code:
var tasks = trips.Select(u => api.Animals.GetAsync(u * 100, 100).ContinueWith(t =>
{
lock (animals)
{
if (t.Result != null)
{
foreach (var a in t.Result)
{
animals.Add(a);
}
}
}
}));
await Task.WhenAll(tasks);
Here is the method that blocks with a shared HttpClient:
//HttpClient blocks on each request
var uri = String.Format("animals?take={0}&from={1}", take, from);
var resourceSegmentUri = new Uri(uri, UriKind.Relative);
var response = await _client.GetAsync(resourceSegmentUri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var animals = JsonConvert.DeserializeObject<T>(content);
return animals;
}
This snippet does not block, when using a client for each request:
using (var client = new HttpClient(){BaseAddress = new Uri(_config.BaseUrl)})
{
var uri = String.Format("animals?take={0}&from={1}", take, from);
var resourceSegmentUri = new Uri(uri, UriKind.Relative);
var response = await client.GetAsync(resourceSegmentUri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var animals = JsonConvert.DeserializeObject<T>(content);
return animals;
}
}
Is a shared HttpClient a no go? Or can I utilize it in some other way?
Using a shared HttpClient is actually recommended.
See my answer why - What is the overhead of creating a new HttpClient per call in a WebAPI client?

Categories

Resources