I have bulk of records to send push notifications by mobile device to other mobile devices.
For that I am using for loop inside task.Start(). I wonder whether task.Start() running in background or not? So that while sending remote notifications to mobile device at the same time I could do some other stuff too & it wont block mobile UI.
The code below I am using
var pushTask = new Task(() =>
{
if (myPushDataFilterd.Any())
{
var title = txtHomeworkTitle.Value.Trim();
for (int index = 0; index < myPushDataFilterd.Count; index++)
{
var row = myPushDataFilterd[index];
jData.Add("moduleName", "Homework");
jData.Add("organizationId", ddlOrganization.SelectedValue);
jData.Add("studentId", studentId);
jGcmData.Add("to", to);
jGcmData.Add("data", jData);
api = row.ServerKeyPush;
var url = new Uri("https://fcm.googleapis.com/fcm/send");
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + api);
var r = client.PostAsync(url, new StringContent(jGcmData.ToString(), Encoding.Default, "application/json")).Result;
}
}
}
});
pushTask.Start();
Actually this the web application part I am now using in mobile application. In mobile application do I have other better options too, to send notification?
There is no point in creating task at all. You are doing IO operations, so you can make use of already provided async api.
private async Task PostData()
{
if (myPushDataFilterd.Any())
{
var title = txtHomeworkTitle.Value.Trim();
using (var client = new HttpClient())
{
for (int index = 0; index < myPushDataFilterd.Count; index++)
{
var row = myPushDataFilterd[index];
jData.Add("moduleName", "Homework");
jData.Add("organizationId", ddlOrganization.SelectedValue);
jData.Add("studentId", studentId);
jGcmData.Add("to", to);
jGcmData.Add("data", jData);
api = row.ServerKeyPush;
var url = new Uri("https://fcm.googleapis.com/fcm/send");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + api);
var r = await client.PostAsync(url, new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"));
}
}
}
}
Task in general represents an asynchronous operation, so code inside a task block won't block unless you wanted to read its value by explicitly waiting, check the following for example:
Task myTask = new Task( () => Console.WriteLine("It is me myTask ^_^ "));
myTask.Start();
Console.WriteLine("Currently not waiting the output from myTask");
myTask.Wait();//Now I am waiting
//Output:
//Currently not waiting the output from myTask
//It is me myTask ^_^
Also you can create and start a task in one statement using Task.Run & TaskFactory.StartNew.
For more information about the differences in usage between them check the link.
Related
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)
};
}
I'm running a messaging service bot, which utilities long polling to get user messages sent. This is all working fine, until I added a new component which sends a simple http get request to a heartbeat monitoring service every 30 seconds. After implementing this component, my bot code sends an additional poll request to the messaging service whenever the heartbeat component sends its request.
I'm assuming the request sent by the heartbeat component is interrupting the long polling, or something of that nature? If I comment out the heartbeat request, everything works fine.
I've tried using a shared HttpClient, and seperate HttpClients disposed after ever use.
Heartbeat monitor code:
using (var client = new HttpClient())
{
var response = await client.GetAsync(_heartbeatUrl);
var responseString = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
Log.LogMessage(response.ReasonPhrase, LogType.Error);
Log.LogMessage(responseString, LogType.Error);
}
Log.LogMessage(responseString, LogType.Verbose);
}
Message bot poll code:
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
var jsonData = JsonConvert.SerializeObject(data);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var fullString = _url + "/" + methodName;
Log.LogMessage("Querying: " + fullString, LogType.Verbose);
Log.LogMessage("With Data: " + jsonData, LogType.Verbose);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, fullString)
{
Content = content,
};
request.Headers.Authorization = new AuthenticationHeaderValue("mybot", _botToken);
var response = await client.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
returnedObject = JsonConvert.DeserializeObject<T>(responseString);
if (!response.IsSuccessStatusCode)
{
Log.LogMessage(response.ReasonPhrase, LogType.Error);
Log.LogMessage(responseString, LogType.Error);
}
Log.LogMessage(responseString, LogType.Verbose);
}
Both of these are called in simple while(true) loops, i.e
Thread th = new Thread(async a =>
{
while (true)
{
await SendHeartbeat();
Thread.Sleep(30000);
}
});
and
new Thread(async () =>
{
while (true)
{
try
{
var results = await Methods.getUpdates(_service, update_id);
} catch (Exception e) { Log.LogMessage("Error with HTML query: " + e.Message, LogType.Error, e.StackTrace); }
}
}).Start();
I'm a bit stumped as to what could be causing this. Any suggestions are much appreciated!
Figured this out in the end. My calls to my static Log class had a lock on the file write method. I believe when the heartbeat ran and logged it's result, the polling code would be blocked when trying to Log stuff, causing the thread to be released by the async await. A new thread would start polling before the previous one had finished executing.
so basically i'm using this
public static async void postToPushNotifcationAsync(String deviceId, String message, String title)
{
var serverKey = "";
var senderId = "";
var fcm = new FCMJsonModel();
var fcmNotification = new FCMNotificationModel();
fcmNotification.body = message;
fcmNotification.title = title;
fcmNotification.sound = "sound.caf";
fcm.to = deviceId;
fcm.notification = fcmNotification;
var json = fcm.ToJSON();
var content = new StringContent(json);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + serverKey);
client.DefaultRequestHeaders.TryAddWithoutValidation("Sender", "id=" + senderId);
//client.Timeout = TimeSpan.FromMinutes(2);
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromMinutes(1));
var response = await client.PostAsync("https://fcm.googleapis.com/fcm/send", content, cts.Token);
var responseString = await response.Content.ReadAsStringAsync();
}
}
This method is basically posting a push notification server and send a message.I used this method multiple times for different api's but the post gets cluttered and it sends the first one and doesn't send the other ones. I just want to use this method multiple times and i'm even willing to not use async on this but it won't allow me to. I'm not an expert on ASP.NET programming but I would like to know how this can be fixed. Thank you for your help.
How can HttpClient.PostAsync be used to post HTTP requests to URLs which have an artificial time for sending back a response.
Please note the URL and the parameter sleep=30 which is used to introduce an artificial delay of 30 seconds before sending back an HTTP response.
Console.WriteLine("Start time : " + DateTime.Now);
for (int i = 1; i <= 10; i++)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(#"http://fake-response.appspot.com/api/?data={Hello World}&sleep=30");
//client.BaseAddress = new Uri(#"http://fake-response.appspot.com/api/?data={Hello World}&status=200");
client.Timeout = new TimeSpan(0, 0, 60);
var parameters = new Dictionary<string, string>();
parameters["ContentType"] = "text/plain;charset=UTF-8";
//Create Task to POST to the URL
client.DefaultRequestHeaders.ExpectContinue = true;
var response = await client.PostAsync(client.BaseAddress, new FormUrlEncodedContent(parameters));
Task<bool> b1 = ProcessURLAsync(response, 1, 5, 2);
}
}
Console.WriteLine("End time : " + DateTime.Now);
What needs to be done is that async HTTP Posts need to be made in a loop and should not be dependent on the timeout specified in the URL.
However, the PostAsync times out before a response is received.
Please check the time needed for POSTing the 2 different URLs in a loop of 10 async POSTs
I checked HttpClient.DefaultRequestHeaders.ExpectContinue , but I do not think this might help in this use case.
That artificial delay is no different from network timeout, from client's perspective. So you should set client.Timeout to the maximum expected artificial delay + real network timeout time. If you don't want to block waiting for response - just not await Task returned from PostAsync. You can store all such tasks in some list and wait them all to complete with await Task.WhenAll(yourTaskList). Or you can use ContinueWith to perform specific actions when given task will be completed. However, if you care about response at all - you have to set large enough timeout anyway, otherwise request will be aborted prematurely.
Here is some sample code to help you out
static async void MakeRequests()
{
var requests = new List<Task<bool>>();
for (int i = 1; i <= 10; i++)
{
// no await here, so, not await MakeRequest(i);
requests.Add(MakeRequest(i));
}
// now all 10 requests are running in parallel
try {
await Task.WhenAll(requests);
}
catch {
// no need to handle it here - we handle all errors below
}
// if we are here, all requests are either completed or failed, inspect their results
foreach (var request in requests) {
if (request.IsCanceled) {
// failed by timeout
}
else if (request.IsFaulted) {
// failed
Log(request.Exception);
}
else {
// success
bool result = request.Result;
// handle your result here if needed
}
}
}
static async Task<bool> MakeRequest(int i) {
using (var client = new HttpClient()) {
client.BaseAddress = new Uri(#"http://fake-response.appspot.com/api/?data={Hello World}&sleep=30");
//client.BaseAddress = new Uri(#"http://fake-response.appspot.com/api/?data={Hello World}&status=200");
// no timeout here, or set to max expected delay
//client.Timeout = new TimeSpan(0, 0, 60);
var parameters = new Dictionary<string, string>();
parameters["ContentType"] = "text/plain;charset=UTF-8";
//Create Task to POST to the URL
client.DefaultRequestHeaders.ExpectContinue = true;
var response = await client.PostAsync(client.BaseAddress, new FormUrlEncodedContent(parameters));
Task<bool> b1 = ProcessURLAsync(response, 1, 5, 2);
return b1;
}
}
However, the PostAsync times out before a response is received.
This method times out because you set HttpClient.Timeout property to 10 seconds. Setting this property instructs the client to time out after a specified time if response is not received.
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.