Run HttpClient GetAsync in different threads - c#

I have a scenario where I have x amount of queries and I want to run each query in a different thread.
My problem is the Http GetAsync method only works when it returns a Task, I tried to return a void but it did not work. But to create multiple threads I need to return a void.
public static async Task threadAsync(string query)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
try
{
watch.Restart();
HttpResponseMessage response = await client.GetAsync(query);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
watch.Stop();
string logData += $"Execution Time: {watch.ElapsedMilliseconds} ms, ";
watch.Reset();
var data = JObject.Parse(responseBody);
}
catch (HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} ", e.Message);
}
}
I have multiple methods in Threads class with different queries. I tried using GetAwaiter().GetResult(), but that also did not work. How can I use run each query in a different thread?
public class Threads
{
public static void thread1Create()
{
string query = "SOMEQUERY";
threadAsync(query).GetAwaiter().GetResult()
}
};

want to run each query in a different thread.
Why?
You really need to learn how windows works internally and what completion ports are. Async methods run on NO thread - they just get called into a thread back when they are done. This is based on the windows network model actually - NOT HAVING THREADS WHILE IT WORKS.
My problem is the Http GetAsync method only works when it returns a Task, I
tried to return a void
Given that GET Returns something in the task, that would be utterly useless.
Your problem is this:
HttpResponseMessage response = await client.GetAsync(query);
There is no requirement to AWAIT immediately. Start all the async get operations, then start awaiting them.
Really learn basics - you USE async, but you THINK in threads still and thus you do not understand what the async model really gives you. The result is a cargo cult like programming totally nullifying the advantages of async, and now asking how to then regain them via threads.

Related

C# Async and Sync functions confuse me

I have an app in which a button starts creating XMLs. In the end of each XML creation, the SendInvoice function sends it, receives the response and a function (ParseResponse) parses the responses and does the database operations needed.
The idea is that when all the XMLs are created and sent, the application must close.
The problem is that I have lost control with async and the application seems to close before it actually finishes all the jobs. Also XMLs are sent before the previous have been processed.
The ParseResponse function is not asynchronous.
Here is the SendInvoice function.
Can you suggest any good practise?
Thank you in advance.
public async void SendInvoice(string body)
{
Cursor.Current = Cursors.WaitCursor;
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
var uri = "https://xxxx.xxx/SendInvoices?" + queryString;
HttpResponseMessage response;
// Request body
byte[] byteData = Encoding.UTF8.GetBytes(body);
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
response = await client.PostAsync(uri, content);
string responsebody = await response.Content.ReadAsStringAsync();
ParseResponse(response.ToString());
ParseResponse(responsebody);
}
}
The rest of the code
private void button1_Click(object sender, EventArgs e)
{
For
{
......
SendInvoice(xml)
}
System.Windows.Forms.Application.Exit();
}
Since you are calling the method from an Event Handler, this is a case where async void is acceptable, change your Button Click handler method signature to use async, I also added some ConfigureAwait(false) to async method calls - best-practice-to-call-configureawait-for-all-server-side-code and why-is-writing-configureawaitfalse-on-every-line-with-await-always-recommended:
private async void button1_Click(object sender, EventArgs e)
{
//since you are using a for-loop, I'd suggest adding each Task
//to a List and awaiting all Tasks to complete using .WhenAll()
var tasks = new List<Task>();
FOR
{
......
//await SendInvoice(xml).ConfigureAwait(false);
tasks.Add(SendInvoice(xml));
}
await Task.WhenAll(tasks).ConfigureAwait(false);
System.Windows.Forms.Application.Exit();
}
AND change your SendInvoice method signature to return a Task
public async Task SendInvoice(string body)
{
Cursor.Current = Cursors.WaitCursor;
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
var uri = "https://xxxx.xxx/SendInvoices?" + queryString;
HttpResponseMessage response;
// Request body
byte[] byteData = Encoding.UTF8.GetBytes(body);
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
response = await client.PostAsync(uri, content).ConfigureAwait(false);
string responsebody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
ParseResponse(response.ToString());
ParseResponse(responsebody);
}
}
I was very used to multithreaded programming and it took me some time to understand asynchronous programming, because it really has nothing to do with multithreading. It is about doing more with a single thread, or a small number of threads.
asynchronous code is beneficial when the CPU would otherwise be waiting for something besides processing. Examples are: waiting for a network response, waiting for data to be read from disk, waiting on a separate process such as a database server.
It provides a way for the thread you are running to do other things while you wait. C# does this using Task. A task is some work that is being done, and it can be running or it can be waiting, and when waiting it doesn't need a thread attached.
All asynchronous functions must return a Task to be useful. So your function should be:
public async Task SendInvoice() {
...
The async keyword is used by the compiler to automatically wrap your function in a task object so you don't need to worry about a lot of the details. You just use await when calling another async function. You could do more work yourself to create tasks or return a task from another async function, or even call multiple async functions and await all of them together.
If your async method returns a value, use the generic Task: Task<String>, for example.
The Task is returned from an async method before the task completes. That is what allows the thread to be used by something else, but it has to get back to that starting place, which is why asynchonous programming you'll hear "async all the way up". It doesn't really do any good until it gets back to a caller that has multiple tasks to balance, which is usually the entry point of your application or the web request.
You can make your C# Main method async, but it mostly won't matter unless your process is really doing multiple things at the same time. For a web application, that can just be handling multiple requests. For a standalone app, it means you can query multiple APIs, make multiple web requests or db queries at the same time, and await them all, just using a single thread. Obviously, that can make things faster (at least locally, the external resources may have more work to do).
For a simple way to keep your program from exiting, if you have an asynchronous main, just await the call to SendInvoice. If your main is not async, you can use something like:
SendInvoice().Wait()
or
SendInvoice().Result
Using Wait() or Result will lock the thread until the task completes. It typically will make that thread exclusively available to the task so the thread cannot be used for any other tasks. If there are more threads in the threadpool, other tasks may continue to run, but typically using Wait/Result on a single Task defeats the point of asynchronous programming, so keep that in mind.
EDIT
Now that you have posted your calling code, it appears your call is in a loop. This is a good opportunity to take advantage of async calls and send ALL the invoices at once.
private async void button1_Click(object sender, EventArgs e)
{
List<Task> tasks = new List<Task>();
FOR
{
......
t = SendInvoice(xml).ConfigureAwait(false);
tasks.Add(t)
}
await Task.WhenAll(tasks).ConfigureAwait(false);
System.Windows.Forms.Application.Exit();
}
That will send ALL the invoices, then return from the handler, and then exit once all the responses have been received.

Async/Await Usage in .NET

I've been working on a project and saw the below code. I am new to the async/await world. As far as I know, only a single task is performing in the method then why it is decorated with async/await. What benefits I am getting by using async/await and what is the drawback if I remove async/await i.e make it synchronous I am a little bit confused so any help will be appreciated.
[Route("UpdatePersonalInformation")]
public async Task<DataTransferObject<bool>> UpdatePersonalInformation([FromBody] UserPersonalInformationRequestModel model)
{
DataTransferObject<bool> transfer = new DataTransferObject<bool>();
try
{
model.UserId = UserIdentity;
transfer = await _userService.UpdateUserPersonalInformation(model);
}
catch (Exception ex)
{
transfer.TransactionStatusCode = 500;
transfer.ErrorMessage = ex.Message;
}
return transfer;
}
Service code
public async Task<DataTransferObject<bool>> UpdateUserPersonalInformation(UserPersonalInformationRequestModel model)
{
DataTransferObject<bool> transfer = new DataTransferObject<bool>();
await Task.Run(() =>
{
try
{
var data = _userProfileRepository.FindBy(x => x.AspNetUserId == model.UserId)?.FirstOrDefault();
if (data != null)
{
var userProfile = mapper.Map<UserProfile>(model);
userProfile.UpdatedBy = model.UserId;
userProfile.UpdateOn = DateTime.UtcNow;
userProfile.CreatedBy = data.CreatedBy;
userProfile.CreatedOn = data.CreatedOn;
userProfile.Id = data.Id;
userProfile.TypeId = data.TypeId;
userProfile.AspNetUserId = data.AspNetUserId;
userProfile.ProfileStatus = data.ProfileStatus;
userProfile.MemberSince = DateTime.UtcNow;
if(userProfile.DOB==DateTime.MinValue)
{
userProfile.DOB = null;
}
_userProfileRepository.Update(userProfile);
transfer.Value = true;
}
else
{
transfer.Value = false;
transfer.Message = "Invalid User";
}
}
catch (Exception ex)
{
transfer.ErrorMessage = ex.Message;
}
});
return transfer;
}
What benefits I am getting by using async/await
Normally, on ASP.NET, the benefit of async is that your server is more scalable - i.e., can handle more requests than it otherwise could. The "Synchronous vs. Asynchronous Request Handling" section of this article goes into more detail, but the short explanation is that async/await frees up a thread so that it can handle other requests while the asynchronous work is being done.
However, in this specific case, that's not actually what's going on. Using async/await in ASP.NET is good and proper, but using Task.Run on ASP.NET is not. Because what happens with Task.Run is that another thread is used to run the delegate within UpdateUserPersonalInformation. So this isn't asynchronous; it's just synchronous code running on a background thread. UpdateUserPersonalInformation will take another thread pool thread to run its synchronous repository call and then yield the request thread by using await. So it's just doing a thread switch for no benefit at all.
A proper implementation would make the repository asynchronous first, and then UpdateUserPersonalInformation can be implemented without Task.Run at all:
public async Task<DataTransferObject<bool>> UpdateUserPersonalInformation(UserPersonalInformationRequestModel model)
{
DataTransferObject<bool> transfer = new DataTransferObject<bool>();
try
{
var data = _userProfileRepository.FindBy(x => x.AspNetUserId == model.UserId)?.FirstOrDefault();
if (data != null)
{
...
await _userProfileRepository.UpdateAsync(userProfile);
transfer.Value = true;
}
else
{
transfer.Value = false;
transfer.Message = "Invalid User";
}
}
catch (Exception ex)
{
transfer.ErrorMessage = ex.Message;
}
return transfer;
}
The await keyword only indicates that the execution of the current function is halted until the Task which is being awaited is completed. This means if you remove the async, the method will continue execution and therefore immediately return the transfer object, even if the UpdateUserPersonalInformation Task is not finished.
Take a look at this example:
private void showInfo()
{
Task.Delay(1000);
MessageBox.Show("Info");
}
private async void showInfoAsync()
{
await Task.Delay(1000);
MessageBox.Show("Info");
}
In the first method, the MessageBox is immediately displayed, since the newly created Task (which only waits a specified amount of time) is not awaited. However, the second method specifies the await keyword, therefore the MessageBox is displayed only after the Task is finished (in the example, after 1000ms elapsed).
But, in both cases the delay Task is ran asynchronously in the background, so the main thread (for example the UI) will not freeze.
The usage of async-await mechanism mainly used
when you have some long calculation process which takes some time and you want it to be on the background
in UI when you don't want to make the main thread stuck which will be reflected on UI performance.
you can read more here:
https://learn.microsoft.com/en-us/dotnet/csharp/async
Time Outs
The main usages of async and await operates preventing TimeOuts by waiting for long operations to complete. However, there is another less known, but very powerful one.
If you don't await long operation, you will get a result back, such as a null, even though the actual request as not completed yet.
Cancellation Tokens
Async requests have a default parameter you can add:
public async Task<DataTransferObject<bool>> UpdatePersonalInformation(
[FromBody] UserPersonalInformationRequestModel model,
CancellationToken cancellationToken){..}
A CancellationToken allows the request to stop when the user changes pages or interrupts the connection. A good example of this is a user has a search box, and every time a letter is typed you filter and search results from your API. Now imagine the user types a very long string with say 15 characters. That means that 15 requests are sent and 15 requests need to be completed. Even if the front end is not awaiting the first 14 results, the API is still doing all the 15 requests.
A cancellation token simply tells the API to drop the unused threads.
I would like to chime in on this because most answers although good, do not point to a definite time when to use and when not.
From my experience, if you are developing anything with a front-end, add async/await to your methods when expecting output from other threads to be input to your UI. This is the best strategy for handling multithread output and Microsoft should be commended to come out with this when they did. Without async/await you would have to add more code to handle thread output to UI (e.g Event, Event Handler, Delegate, Event Subscription, Marshaller).
Don't need it anywhere else except if using strategically for slow peripherals.

How to loop a C# ARGGIS asynchronous method (Check post for the method code)

I am using the arcGIS SDK in C# to search for addresses. What i would like to do is search for multiple addresses and then executing a method when all the addresses are found. This will most likely be achieved by using a loop.
Here is the code to find an address on the map:
public async void searchSubjectAddress(string sAddress)
{
var uri = new Uri("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");
var token = string.Empty;
var locator = new OnlineLocatorTask(uri, token);
var info = await locator.GetInfoAsync();
var singleAddressFieldName = info.SingleLineAddressField.FieldName;
var address = new Dictionary<string, string>();
address.Add(singleAddressFieldName, sAddress);
var candidateFields = new List<string> { "Score", "Addr_type", "Match_addr", "Side" };
var task = locator.GeocodeAsync(address, candidateFields, MyMapView.SpatialReference, new CancellationToken());
IList<LocatorGeocodeResult> results = null;
try
{
results = await task;
if (results.Count > 0)
{
var firstMatch = results[0];
var matchLocation = firstMatch.Location as MapPoint;
Console.WriteLine($"Found point: {matchLocation.ToString()}");
MyMapView.SetView(matchLocation);
}
}
catch (Exception ex)
{
Console.WriteLine("Could not find point");
var msg = $"Exception from geocode: {ex.Message} At address: {sAddress}";
Console.WriteLine(msg);
}
}
I am currently following this tutorial:
https://developers.arcgis.com/net/10-2/desktop/guide/search-for-places.htm
I can find a single address, but the asynchronous tasks are a bit confusing. The code must be executed with the asynchronous tasks to function, so i cant change that.
To use this in an example:
I want to get the distance between one property and several others. I only have access to the street addresses, so i use the above code to find the address and fetch the Geo-coordinates. Then i save those coordinates in a list for later use.
My problem is that when i want to execute the later methods, the async tasks are still running and my program executes the later methods regardless of whether the async methods are completed. When i change the method to a Task type instead of void, i usually end up with an endless wait with no tasks being accomplished.
I would like to know how i can loop the above method synchronously (let each new tasks only run when the older ones are finished) through a list of addresses and then run a method when all async tasks are finished. It would also be nice if the async tasks stop when a resulting address is found.
Help would be much appreciated!
Change
public async void searchSubjectAddress(string sAddress)
to
public async Task searchSubjectAddress(string sAddress)
Then whatever is calling searchSubjectAddress can await this call, so you know when it's complete.
You might also consider making it return Task < SearchResult> instead so you can get the address sent back to the caller.
Generally when you write "async void" you're setting yourself up for problems, so try to always make things "async Task" or "async Task< T>" instead.
On a side note: The v10.x releases have long been deprecated/unsupported, and you really should move to v100.8

I cannot understand how exactly does await/async work

I started to look into Task, async/await concepts is c# and I'm having big problems understanding it, well at least i don't know how to implement it. I started rewriting an older test program i had written before, but now instead of threading i want to use these new concepts. Basically the layout is as it follows:
I have a simple class where i download the HTML content of a web page.
I process that in another class where i basically just parse the page to my model. Later on i want to display that to my UI.
The problem is that my program is not responsive, it blocks the UI while I'm processing the info.
I started learning this 2 days ago, i have read a lot of stuff online, including MSDN and some blogs but yet I'm unable to figure it out. Maybe someone can provide a look as well
HtmlDOwnloadCOde:
public async Task<string> GetMangaDescriptionPage(string detailUrl)
{
WebClient client = new WebClient();
Stream data = await client.OpenReadTaskAsync(detailUrl);
StreamReader reader = new StreamReader(data);
string s = reader.ReadToEnd();
data.Dispose();
reader.Dispose();
data.Close();
reader.Close();
return s;
}
My parse class code:
public async Task<MangaDetailsModel> ParseMangaDescriptionPage()
{
ParseOneManga pom = new ParseOneManga();
string t1 = await pom.GetMangaDescriptionPage(selectedManga.url);
HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(t1);
var divs = htmlDoc.DocumentNode.Descendants("div").Where(x => x.Attributes.Contains("id") &&
x.Attributes["id"].Value.Contains("title")).ToArray();
mangaDetails.mangaName = divs[0].Element("h1").InnerText;
mangaDetails.description = divs[0].Descendants("p").Single().InnerText ?? "DSA";
var tds = divs[0].Descendants("td");
int info = 0;
var chapters = htmlDoc.DocumentNode.Descendants("div").Where(x => x.Attributes.Contains("id") &&
x.Attributes["id"].Value.Contains("chapters")).ToArray();
var chapterUi = chapters[0].Descendants("ul").Where(x => x.Attributes.Contains("class") &&
x.Attributes["class"].Value.Contains("chlist"));
foreach (var li in chapterUi)
{
var liChapter = li.Descendants("li");
foreach (var h3tag in liChapter)
{
var chapterH3 = h3tag.Descendants("a").ToArray();
SingleManagFox chapterData = new SingleManagFox();
chapterData.name = chapterH3[1].InnerHtml;
chapterData.url = chapterH3[1].GetAttributeValue("href", "0");
mangaDetails.chapters.Add(chapterData);
}
};
return mangaDetails;
}
UI code:
private async void mainBtn_Click(object sender, RoutedEventArgs e)
{
if (mangaList.SelectedItem != null)
{
test12((SingleManagFox)mangaList.SelectedItem);
}
}
private async void test12(SingleManagFox selectedManga)
{
selectedManga = (SingleManagFox)mangaList.SelectedItem;
MangaDetails mangaDetails = new MangaDetails(selectedManga);
MangaDetailsModel mdm = await mangaDetails.ParseMangaDescriptionPage();
txtMangaArtist.Text = mdm.artisName;
txtMangaAuthor.Text = mdm.authorName;
chapterList.ItemsSource = mdm.chapters;
}
Sorry if its trivial but i cannot figure it out myself.
When going async you need to try to go async all the way and avoid mixing blocking calls with async calls.
You are using async void in the event handler with no await.
Try to avoid async void unless it is an event handler. test12 should be updated to return Task and awaited in the event handler mainBtn_Click.
private async void mainBtn_Click(object sender, RoutedEventArgs e) {
if (mangaList.SelectedItem != null) {
await test12((SingleManagFox)mangaList.SelectedItem);
}
}
private async Task test12(SingleManagFox selectedManga) {
selectedManga = (SingleManagFox)mangaList.SelectedItem;
MangaDetails mangaDetails = new MangaDetails(selectedManga);
MangaDetailsModel mdm = await mangaDetails.ParseMangaDescriptionPage();
txtMangaArtist.Text = mdm.artisName;
txtMangaAuthor.Text = mdm.authorName;
chapterList.ItemsSource = mdm.chapters;
}
Also consider updating the web call to use HttpClient if available.
class ParseOneManga {
public async Task<string> GetMangaDescriptionPageAsync(string detailUrl) {
using (var client = new HttpClient()) {
string s = await client.GetStringAsync(detailUrl);
return s;
}
}
}
Reference: - Async/Await - Best Practices in Asynchronous Programming
Quite often people think that async-await means that multiple threads are processing your code at the same time. This is not the case, unless you explicitly start a different thread.
A good metaphore that helped me a lot explaining async-await is the restauran metaphor used in this interview with Eric Lippert. Search somewhere in the middle for async-await.
Eric Lipperts compares async-await processing with a cook who has to wait for his water to boil. Instead of waiting, he looks around if he can do other things instead. When finished doing the other thing, he comes back to see if the water is boiling and starts processing the boiling water.
The same is with your process. There is only one thread busy (at a time). This thread keeps processing until he has to await for something. This something is usually a fairly long process that is processed without using your CPU core, like writing a file to disk, loading a web page, or querying information from an external database.
Your thread can only do one thing at a time. So while it is busy calculating something, if can't react on operator input and your UI freezes, until the calculations are done. Async await will only help if there are a lot of times your thread would be waiting for other processes to complete
If you call an async function, you are certain that somewhere in that function is an await. In fact, if you declare your function async, and your forget to await in it, your compiler will warn you.
When your call meets the await in the function, your thread goes up its call stack to see if it can do other things. If you are not awaiting, you can continue processing, until you have to await. The thread goes up its call stack again to see if one of the callers is not awaiting etc.
async Task ReadDataAsync()
{
// do some preparations
using (TextReader textReader = ...)
{
var myReadTask = textReader.ReadToEndAsync();
// while the textReader is waiting for the information to be available
// you can do other things
ProcessSomething();
// after a while you really need the results from the read data,
// so you await for it.
string text = await MyReadTask;
// after the await, the results from ReatToEnd are available
Process(text);
...
There are some rules to follow:
an async function should return Task instead of void and Task<TResult> instead of TResult
There is one exception: the async event handler returns void instead of Task.
Inside your async function you should await somehow. If you don't await, it is useless to declare your function async
The result of await Task is void, and the result of await Task<TResult> is TResult
If you call an async function, see if you can do some processing instead of waiting for the results of the call
Note that even if you call several async functions before awaiting for them, does not mean that several threads are running these functions synchronously. The statement after your first call to the async function is processed after the called function starts awaiting.
async Task DoSomethingAsync()
{
var task1 = ReadAsync(...);
// no await, so next statement processes as soon as ReadAsync starts awaiting
DoSomeThingElse();
var task2 = QueryAsync(...);
// again no await
// now I need results from bothtask1, or from task2:
await Task.WhenAll(new Task[] {task1, task2});
var result1 = Task1.Result;
var result2 = Task2.Result;
Process(result1, result2);
...
Usually all your async functionality is performed by the same context. In practice this means that you can program as if your program is single threaded. This makes the look of your program much easier.
Another article that helped me a lot understanding async-await is Async-Await best practices written by the ever so helpful Stephen Cleary

Async/Await in foreach with HTTPClient

I have a webservice that loads up some plugins (dlls) and calls their Process method. One of the plugins takes a list of members and ensures that they are all included in a MailChimp list.
Here is the code that adds the users to the MailChimp group.
private async Task AddMCUsers(List<Member> _memberList)
{
using (var http = new HttpClient())
{
var creds = Convert.ToBase64String(Encoding.ASCII.GetBytes("user:password");
http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", creds);
string memberURI = string.Format(#"{0}lists/{1}/members", _baseURI, _memberGroupId);
var jss = new JavaScriptSerializer();
foreach (var user in _memberlist)
{
var _addStatus = "";
try
{
var content = jss.Serialize(new MCPost()
{
email_address = user.Email,
status = "subscribed",
merge_fields = new MCMergeFields()
{
FNAME = user.Firstname,
LNAME = user.Lastname
}
});
using(var result = await http.PostAsync(memberURI, new StringContent(content,Encoding.UTF8, "application/json")))
{
var resultText = await result.Content.ReadAsStringAsync();
if(result.IsSuccessStatusCode)
{
_addStatus = "Success";
var _returnedUser = jss.Deserialize<MCMember>(resultText);
//Store new user's id
user.ServiceId = _returnedUser.id;
}
else
{
_addStatus = "Fail";
}
}
}
catch {
_addStatus = "Error";
}
LogEvent("Add User - " + _addStatus, string.Format("Id: {0} - {1} {2} (Account: {3}) : {4}", user.Id, user.Firstname, user.Lastname, user.AccountId, user.Email));
}
}
}
In normal procedural code, this wouldn't be a problem. However, the only Post method available on the httpClient was PostAsync. Being fairly new to the async/await stuff, I'm not sure the ramifications on the rest of my code ... particularly as it relates to my attempt to reuse the httpClient instead of instantiating a new one for each http call.
I'm not sure what happens with await when its wrapped in a foreach like I have. Will I run into issues with reusing the httpClient to make repeated calls when running asynchronously?
My other question is, what is actually going to be returned. IOW, my understanding is that await returns a Task. However, here, I'm looping through the list and making multiple calls to await PostAsync. My method returns a Task. But which task gets returned? If my calling method needs to wait for completion before moving on, what does its call look like?
private void Process()
{
//Get List
var task = AddMCUsers(list);
task.Wait();
//Subsequent processing
}
I've read that you should use Async all the way. Does this mean my calling method should look more like this?
public async Task Process()
{
//Get list
...
await AddMCUsers(list);
//Other processing
}
Thanks to whatever help you can offer on this.
In normal procedural code, this wouldn't be a problem.
The whole point of async/await is to write asynchronous code in a way that looks practically identical to "normal" synchronous code.
Being fairly new to the async/await stuff, I'm not sure the ramifications on the rest of my code ... particularly as it relates to my attempt to reuse the httpClient instead of instantiating a new one for each http call.
HttpClient was intended to be reused; in fact, it can be used for any number of calls simultaneously.
I'm not sure what happens with await when its wrapped in a foreach like I have.
One way to think of it is that await "pauses" the method until its operation completes. When the operation completes, then the method continues executing. I have an async intro that goes into more detail.
Will I run into issues with reusing the httpClient to make repeated calls when running asynchronously?
No, that's fine.
IOW, my understanding is that await returns a Task.
await takes a Task. It "unwraps" that task and returns the result of the task (if any). If the task completed with an exception, then await raises that exception.
My method returns a Task. But which task gets returned?
The Task returned from an async method is created by the async state machine. You don't have to worry about it. See my intro for more details.
If my calling method needs to wait for completion before moving on, what does its call look like? ... I've read that you should use Async all the way. Does this mean my calling method should look more like this?
Yes, it should look like your second snippet:
public async Task ProcessAsync()
{
//Get list
...
await AddMCUsers(list);
//Other processing
}
The only thing I changed was the Async suffix, which is recommended by the Task-based Asynchronous Pattern.
in your code you should be fine with reusing the HttpClient. What async / await is allow the code to release the execution thread to prevent locking a cpu thread while waiting for the web response. It also releases control back to the caller. When releasing code back to the caller it means that if your Process function does not await your AddMCUsers, Process could finish before AddMCUsers (useful in fire and forget situations to not await a method).
What async/await do not do is affect the logical flow of an individual method. When you await an async web call the execution is paused and then resumed at the same point once the web call returns. There is also thread context tracking and the code resumes in the same context (ie. UI thread or background thread depending on the parent) by default, but this can be changed if needed.
At some point in your code you may want to have a method that blocks until your async code competes and that is where you will want your Task.Wait() call to block execution. If all you use is awaits then it is possible for your program to end before your task competes. See the code example below.
class Program
{
static void Main(string[] args)
{
Task waitForMe = Task.Run(() => waitAsync());
}
static async Task waitAsync()
{
await Task.Delay(5000);
}
}
in the sample with out a Task.Wait call to block the Main method the program will end before the 5 second wait is complete. Having a main method of the following will cause the program to wait for 5 seconds before exiting:
static void Main(string[] args)
{
Task waitForMe = Task.Run(() => waitAsync());
waitForMe.Wait();
}

Categories

Resources