async await (again) inside lambda - task-parallel-library

I was reading a few blogs about async & await, particularly that of Scott's blog . I have a code sample below, which presumably downloads a list of URLs. To simplify things and make the timings reasonable and repeatable, I replaced the real download code with a Task.Delay awaitable call.
The first code doesn't have an async-await pair inside the lambda expression, while the second one has. Both codes compile, and both timings come out the same (around 1 second).
1.) Which method is the right way to do this?
2.) Will the await async pair inside the lambda cost more?
private async void Button_Click(object sender, RoutedEventArgs e)
{
// Capture the UI synchronization context for use later
var ui = TaskScheduler.FromCurrentSynchronizationContext();
// SAMPLE 1 , is this the right way?
var items = Enumerable.Range(1, 100).Select(i => i.ToString()).ToList();
var sp = new Stopwatch();
sp.Start();
// NO await async pair in lambda
var results1 = await Task.WhenAll(
items.Select(item => DownloadFileAsync(item)));
sp.Stop();
var testResult = string.Format("Single await: {0} seconds"
, sp.Elapsed.TotalSeconds);
// SAMPLE 2, or this way?
var items1 = Enumerable.Range(1, 100).Select(i => i.ToString()).ToList();
var sp1 = new Stopwatch();
sp1.Start();
// WITH await async pair in lambda
var results = await Task.WhenAll(items1.Select(async item =>
await DownloadFileAsync(item)));
sp1.Stop();
var testResult1 = string.Format("Double await: {0} seconds",
sp1.Elapsed.TotalSeconds);
// show results
await Task.Factory.StartNew(() =>
{
MessageBox.Show(testResult + System.Environment.NewLine + testResult1);
}, CancellationToken.None, TaskCreationOptions.None,
ui).ConfigureAwait(false);
}
and
private async Task<string> DownloadFileAsync(string uri)
{
//using (var client = new WebClient())
//{
// string data = await
client.DownloadStringTaskAsync(uri).ConfigureAwait(false);
// return data;
//}
await Task.Delay(1000).ConfigureAwait(false);
return uri;
}

Both of them are roughly equivalent. The first one is slightly more efficient.
For the purposes of this question, you can think of
await as "unwrapping" a task, and
async as "wrapping" a method in a task.
The first example uses a lambda expression to define a function with the signature Task<string> F(string). The function defined by the second example has the same signature. The difference is that
the first example just returns the task from DownloadFileAsync directly
while the second example unwraps the task and then wraps it again.

Related

Calling an async api from a xamarin application

I am working on a xamarin mobile application, upon making an async call to the exposed api, i do not get any error, however when i execute the .Result on the task the call never proceeds and it stuck forever.
Click here to see stringResourceResponse details
The same .Result call from a separate project (windows service) in the same solution works.
Any idea if .NET standard is causing limitation in executing async tasks, any advice would be helpful, thanks
Code added below:
//This is code from app.xaml.cs
var stringResourceApi = new StringResourceApiTask();
Task.Run(() =>
{
a = controller.CallStringResourceApi(stringResourceApi);
}).Wait();
public class MobileController
{
public string CallStringResourceApi(StringResourceApiTask stringResourceApiTask)
{
return stringResourceApiTask.Start(StringResourceUrl);
}
}
public override string Start(string URL)
{
var stringResourceResponse = SendRequest(url, "", HttpMethod.Get);
var result = stringResourceResponse.Result;
return result;
}
protected async Task < string > SendRequest(string url, string uri, HttpMethod method, int attempt = 1, int maxAttempts = 5)
{
return await SendRequest(
url, uri, Key, Secret, method, string.Empty, attempt, maxAttempts)
.ConfigureAwait(false);
}
protected async Task<string> SendRequest(string url, string uri, string key, string secret, HttpMethod method,
string requestBody = "", int attempt = 1, int maxAttempts = 5)
{
if (attempt > maxAttempts)
{
return null;
}
var client = InitialiseHttpClient(key, secret);
var request = new HttpRequestMessage
{
RequestUri = string.IsNullOrEmpty(url) ? new Uri(uri) : new Uri(url),
Method = method,
};
if (!string.IsNullOrWhiteSpace(requestBody))
{
request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
}
SetOutputText($"Attempting to communicate with {uri}...{Environment.NewLine}");
using (var response = await client.SendAsync(request).ConfigureAwait(false))
{
using (var content = response.Content)
{
try
{
response.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex)
{
if (attempt > maxAttempts)
{
SetOutputText(errorMessage);
}
return await SendRequest(url, uri, key, secret, method, requestBody, attempt + 1).ConfigureAwait(false);
}
var responseBody = await content.ReadAsStringAsync().ConfigureAwait(false);
var isSuccessResponseButEmptyBody = response.IsSuccessStatusCode &&
(string.IsNullOrEmpty(responseBody) ||
string.IsNullOrWhiteSpace(responseBody));
if (!isSuccessResponseButEmptyBody)
{
return responseBody;
}
if (attempt > maxAttempts)
{
SetOutputText(errorMessage);
}
return await SendRequest(url, uri, key, secret, method, requestBody, attempt + 1).ConfigureAwait(false);
}
}
}
when i execute the .Result on the task the call never proceeds and it stuck forever.
Yes. This is a common deadlock situation. When code running on the UI thread blocks on asynchronous code, a deadlock usually occurs.
The same .Result call from a separate project (windows service) in the same solution works.
It works because the Win32 service code does not run on a UI thread.
The proper solution is to remove the blocking code; use await instead. This in turn will cause the calling methods to become async (e.g., StringResourceApiTask.Start), and they should also be awaited, etc. The usage of async and await should "grow" through your code; this is natural.
Alternatively, you can block in a thread pool thread, e.g., Task.Run(() => a = controller.CallStringResourceApi(stringResourceApi)).GetAwaiter().GetResult();. This is a bit of a hack (consuming an unnecessary thread), but it's a quick way to remove the deadlock. Note that this hack is not appropriate for ASP.NET apps; it's acceptable here since this is a UI app.

Async Http Request from component in Blazor

Im creating a list of components in Blazor, each one of these components need to request some data from a webpage. The list are created as follows on a .razor page:
#foreach(stringcomp in Complist){
<myComponent />
}
around 100 components are created. On all of these components the following URL request is preformed (using this code):
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await GetUrl("some url here");
}
}
public async Task<string> GetUrl(string url)
{
HttpClient client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("User-Agent", "get data service");
var response = await client.SendAsync(request).ConfigureAwait(false);
string res = null;
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var streamReader = new StreamReader(responseStream);
res = await streamReader.ReadToEndAsync().ConfigureAwait(false);
}
return res;
}
Doing this I'm running in to some problems where most of my calls to SendAsync never returns a value. I have come to understand that this is because of a lock-state but for the life of me can't figure out how to solve it. most similar answers suggest setting .ConfigureAwait(false) but this does not yeald a different result in my case.
So my question is: Hos can i request webbpages simultaneously in different components and be sure that they won't hang/lookup. As theres many requests that some times takes a long time (5-10 sec) to complete it's not an alternative to do them synchronously.
It might also be of importance to mention that me code and pages are separated, every .razor page are using #inherits to get its functions/logic
Try to use IHttpClientFactory as follows:
[Inject] public IHttpClientFactory clientFactory { get; set;}
using System.IO;
Your GetUrl method:
public async Task<string> GetUrl(string url)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("Accept", "application/json");
request.Headers.Add("User-Agent", "get data service");
var client = clientFactory.CreateClient();
var response = await client.SendAsync(request);
string res = null;
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
var streamReader = new StreamReader(responseStream);
res = await streamReader.ReadToEndAsync().ConfigureAwait(false);
}
return res;
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
// More code here...
}
Hope this works...

Xamarin Forms execution returns from await Httpclient PostAsync

I am calling a methodgetaddress();inside viewmodel for getting address information from API. But while debugging, execution returns at
var response = await client.PostAsync(base_url + "api_delivery_details", formcontent).ConfigureAwait(false);to the calling method getaddress() but executes the remaining portion later.so getting null result. How to execute all from first time?
public async void Get_branch_products()
{
RestClient restClient = new RestClient();
getaddresses(); //this is the calling method
long delivery_fee1 = long.Parse(delivery_fee);
GrandTotal = Total + (Total * Tax) / 100 + delivery_fee1 ;
OnPropertyChanged("GrandTotal");
tax_amt = (Total * Tax) / 100;
OnPropertyChanged("tax_amt");
}
public async void getaddresses()
{
ind_vis = true;
OnPropertyChanged("ind_vis");
int user_id = (int)App.Current.Properties["user_id"];
RestClient restClient = new RestClient();
var result = await restClient.Get_address(user_id); //calling restAPI method
if (result.status == "success")
{
ind_vis = false;
OnPropertyChanged("ind_vis");
public async Task<Address> Get_address(int user_id)
{
var formcontent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string,string>("user_id",user_id.ToString())
});
//returns from here// var response = await client.PostAsync(base_url + "api_delivery_details", formcontent).ConfigureAwait(false);
//executes later// var result = await response.Content.ReadAsStringAsync();
var Items = JsonConvert.DeserializeObject<Address>(result);
return Items;
}
Always remember one thing while creating background threads using async-await, async voids unless a built-in event handler are never to be used.
Since async voids are fire and forget types and cause a lot of conundrum.
What you should use is a Task or a Task<T> instead.
I would suggest you read this awesome guide by MSDN on Async and Await Best Practices where they have explained everything so well if you read it.
Now jumping to your code you need to have the following changes in your code so that this issue does not happen
execution returns at var response = await client.PostAsync(base_url + "api_delivery_details", formcontent).ConfigureAwait(false); to the calling method getaddress() but executes the remaining portion later.so getting null result. How to execute all from first time?
Change your code like below:
public async Task Get_branch_products()
{
RestClient restClient = new RestClient();
await GetAddresses(); //this is the calling method
long delivery_fee1 = long.Parse(delivery_fee);
GrandTotal = Total + (Total * Tax) / 100 + delivery_fee1 ;
OnPropertyChanged("GrandTotal");
tax_amt = (Total * Tax) / 100;
OnPropertyChanged("tax_amt");
}
public async Task GetAddresses()
{
ind_vis = true;
OnPropertyChanged("ind_vis");
int user_id = (int)App.Current.Properties["user_id"];
RestClient restClient = new RestClient();
var result = await restClient.Get_address(user_id); //calling restAPI method
if (result.status == "success")
{
ind_vis = false;
OnPropertyChanged("ind_vis");
public async Task<Address> Get_address(int user_id)
{
var formcontent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string,string>("user_id",user_id.ToString())
});
//returns from here// var response = await client.PostAsync(base_url + "api_delivery_details", formcontent).ConfigureAwait(false);
//executes later// var result = await response.Content.ReadAsStringAsync();
var Items = JsonConvert.DeserializeObject<Address>(result);
return Items;
}
Once this is done your code will wait for the GetAddresses method to get you the data and it will then move further.

How to make async call to api (http). in c#. inside a Task

I am developeing a chatbot using microsoftbotframmwok where I have some requirement to make a call from my task to an api(httpclient). but it is not working. when i test the api from an stand alone console application in side main method it works. but in my application it doesn't work.
I tried to call an api from an simple method without task but when it makes a cal its basically halts or stucked somewhere, i converted my function into task and while making an api call i used await keyword to call it asynchronously but it is returning error, while reading it not the result.
here is the my code which make an api call
private async Task<String> getProblem(IDialogContext context)
{
var response = "Thannks for contacting..";
//here some code logix..
SnowApiClient client = new SnowApiClient(Url, UserId, ApiPassword);
IncidentRequestPayload payload = new IncidentRequestPayload();
payload.caller_id = "tet111";
payload.assignment_group = "it";
payload.category = "complaint";
payload.u_feedback_type = "Praise";
payload.service_offering = "Application Management";
payload.priority = 2;
payload.short_description = "computer battery is dead";
payload.comments = String.Empty;
ApiResponse objResponse = await client.CreateIncident(payload);
//objResponse.payload.number;
return response;
}
//code for CreateIncident...in Api project librarary
public async Task<ApiResponse> CreateIncident(IncidentRequestPayload payload)
{
var incidentRequest = new ApiRequest { method = CreateIncidentMethod, payload = payload };
var createResult = await ExecuteRequest(incidentRequest);
return await ReadIncident(createResult.payload.incNumber);
}
public async Task<ApiResponse> ReadIncident(string number)
{
var incidentRequest = new ApiRequest { method = ReadIncidentMethod, payload = new RequestPayload { number = number } };
return await ExecuteRequest(incidentRequest);
}
private async Task<ApiResponse> ExecuteRequest(ApiRequest requestObject)
{
HttpResponseMessage response = await _client.PostAsJsonAsync("/SRintegratedAPI.rest", requestObject);
ApiResponse responseObject = null;
if (response.IsSuccessStatusCode)
{
responseObject = await response.Content.ReadAsAsync<ApiResponse>();
}
else
{
throw new System.Net.WebException(response.ReasonPhrase);
}
if (responseObject.result != "ok")
{
throw new System.Net.WebException(responseObject.message);
}
return responseObject;
}
I don't understand how and where do i used async/await here in basicalaly in my getProblem function.
please help

Consume WCF Rest Service Json data across all platform using Shared Code

We were developing a sample MWC application with the logic of Business ,DataAccess,Data Layers.
In core Project we used the following code for consuming data from json parsing. This code works fine for Xamarin.Android and Xamarin.iOS, but for windows phone it shows error as 'System.Net.WebRequest does not contain a definition for GetResponse and no extension method for GetResponse...'
We tried to use Async methods for consuming WCF Rest service json data, but it returned as null before the completed method called.
Is it possible to wait and get data from completed method to return the json collection? if no please suggest how to achieve the same.
public String login<T>(T item) where T : BusinessLayer.Contracts.IBusinessEntity, new()
{
var request = HttpWebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "get";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
string nss = content.ToString();
check = nss;
return nss;
}
}
return Check;
}
Edit: I have included the sample code of Async function.
Before Executing the DownloadStringCompleted event it returns null value. We need that DownloadStringCompleted output string for further process.
Note: We were following the logic of Tasky in Xamarin
async Task<string> AccessTheWebAsync(string url)
{
var webClient = new WebClient();
webClient.DownloadStringCompleted += (sender, e) =>
{
string data = (string)e.Result;
check = data;
};
webClient.DownloadStringAsync(new Uri(url));
return check;
}
public async Task<string> login<T>(T item) where T : BusinessLayer.Contracts.IBusinessEntity, new()
{
return check = await AccessTheWebAsync(item.url);
}
Your asynchronous code is not using Task correctly. It should use TaskCompletionSource to get the job done:
Task<string> AccessTheWebAsync(string url)
{
var source = new TaskCompletionSource<string>();
var webClient = new WebClient();
webClient.DownloadStringCompleted += (sender, e) =>
{
source.TrySetResult((string)e.Result);
};
webClient.DownloadStringAsync(new Uri(url));
return source.Task;
}
Before, your function was returning before the event fired. Using the task source wraps it in a task properly and fixes this problem.
You will also need to hook up the error event and call TrySetException to finish the implementation.

Resources