Async requests with .NET core - c#

I need a little help to find out my problem. I've used ASP.NET core and i'm fairly familiar with that, although .NET core C# seems to be "crashing" and exiting when trying to make my async request.
I have a method that returns the external IP of the system
private async Task<string> getExternalIP()
{
using (System.Net.Http.HttpClient HC = new System.Net.Http.HttpClient())
{
return await HC.GetStringAsync("https://api.ipify.org/");
}
}
This should work, but it exits when it reaches the HC.GetStringAsync. I've also tried putting a breakpoint on it but it doesn't actually run.
I'm trying to call the method by using
string Address = await getExternalIP();
Any help is thankful, hopefully i'm not just overlooking something.
Thanks!

Your proposed solution is not good at all.
It is synchronous
It can cause a deadlock
As an alternative, try this approach:
private async Task<string> GetExternalIP()
{
using (HttpClient client = new HttpClient())
return await client.GetStringAsync("https://api.ipify.org/");
}
Your calling method should be asynchronous too:
public async Task CallingMethod()
{
// ...
string address = await GetExternalIP();
// ...
}
The reason it was not working for you before was caused by the use of async void instead of async Task (guessed this by the comments).
async void is an asynchronous method that cannot be awaited. That means, you just call it and forget about it. You won't catch any exception, you won't get any return value.
async Task is an awaitable asynchronous method that does not return anything. It is the asynchronous counterpart for a void synchronous method. Furthermore, since it is awaitable, you'll also be able to catch any exception that may rise on the asynchronous code.

Related

Correct way to return an async task within a non-async method

What is the best practice when returning the following Task:
public async Task<Command> BuildCommunicationCommand
As an object:
public Command BuildCommand
I have the following:
public Command BuildCommand()
{
return BuildCommunicationCommand().GetAwaiter().GetResult();
}
But have been told to try and avoid this and that I should await the Task so we do not block the UI thread. I think the best way to do this is to make the BuildCommand method async and anything else that calls it. This would be a massive change and is not really required for other classes which use the BuildCommand. I do not want to cause a block by using .Result so have read its best to use ConfigureAwait(false) in this case:
public Command BuildCommand()
{
var Command = BuildCommunicationCommand().ConfigureAwait(false);
return Command.GetAwaiter().GetResult();
}
Can I use ConfigureAwait(false) to wait for the process to finish and then call .GetAwaiter().GetResult() to return it as the object Command?
This is my first time working with async tasks so if any of the above is complete rubbish I am sorry!
You can wrap the call to your async method in another method that waits for the task to complete and then returns the result. Of course that blocks the thread that calls GetData. But it gets rid of the async 'virus'. Something like this:
private string GetData()
{
var task = GetDataAsync();
task.Wait();
return task.Result;
}
private async Task<string> GetDataAsync()
{
return "Hello";
}
You're asking after best practices though, and that is to change everything to async as needed.

Async/await, run blocking the UI without obvious reason

I have been reasearching once again the async tasks. No mater how i set the Tasks, my application suffers from UI freeze all the time. I have the following code for downloading the string from a webpage:
internal string DownloadString(string URL)
{
var result = LoadCompanyContracts(URL);
return result.Result;
}
internal async Task<string> LoadCompanyContracts(string URL)
{
Task<string> task2 = Task<string>.Factory.StartNew(() =>
{
for (int i = 0; i <= 10000000; i++) Console.WriteLine(i);
WebClient wc = new WebClient();
string tmp = wc.DownloadString(new Uri(URL));
return tmp;
});
return task2.Result;
}
When i execute this task and during the for loop the UI of my application is freezing. Even though i believe that this code should not freeze the UI i am not able to find a solution. I have tried many different options and really want to use tasks instead of threads or events with webclient async.
Info: I am using .net 4.5 for my project. The difference in my code is that these functions are inside a class library(don't know if it matters).
Is it possible to run this code without blocking the user interface with async await by calling the DownloadString function from my code? If not what are the alternatives(any good nuget packages)?
The async keyword doesn't make something run asynchronously, it enables you to use await to await an already asynchronous operation. You need to use
DownloadStringTaskAsync to truly download in an asynchronous manner:
internal async Task<string> LoadCompanyContracts(string URL)
{
....
using(var wc = new WebClient())
{
string tmp = await wc.DownloadStringTaskAsync(new Uri(URL));
return tmp;
}
}
await by itself returns execution in the original execution context (ie the UI thread). This may or may not be desirable, which is why library code typically uses ConfigureAwait(false); and lets the final user of the library to decide how to await:
string tmp = await wc.DownloadStringTaskAsync(new Uri(URL))
.ConfigureAwait(false);
Finally, there's no point in awaiting if you are going to call .Result from the top-level function. There is no point in using await at all if you don't want to do use the method's result in your code. LoadCompanyContracts could be just:
internal Task<string> LoadCompanyContracts(string URL)
{
....
using(var wc = new WebClient())
{
return wc.DownloadStringTaskAsync(new Uri(URL))
.ConfigureAwait(false);
}
}
Oops
Typically, you don't need to use await at all if you just return the result of an asynchronous operation. The method could just return wc.DownloadStringTaskAsync(..); BUT that would cause the method to return and dispose the WebClient before download finishes. Avoiding the using block isn't a solution either, as it will let an expensive object like WebClient alive longer than necessary.
That's why HttpClient is preferable to WebClient: a single instance supports multiple concurrent calls, which means you can have just one instance eg as a field and reuse it, eg:
HttpClient _myClient =new HttpClient();
internal Task<string> LoadCompanyContractsAsync(string URL)
{
....
return _myClient.GetStringAsync(new Uri(URL))
.ConfigureAwait(false);
}
}
You could get rid of your DownloadString since it doesn't do anything on top of LoadCompanyContracts. If it does use the result of LoadCompanyContracts, it should be rewritten as:
internal async Task<string> DownloadString(string URL)
{
var result = await LoadCompanyContracts(URL);
//Do something with the result
return result;
}
EDIT
The original answer used DownloadStringAsync which is a legacy method that raises an event when download completes. The correct method is DownloadStringTaskAsync
EDIT 2
Since we are talking about a UI, the code can be made asynchronous all the way to the top event handler by using the async void syntax for the handler, eg async void Button1_Click, eg:
async void LoadCustomers_Click(...)
{
var contracts=await LoaCompanyContracts(_companyUrls);
txtContracts>Text=contracts;
}
In this case we want to return to the original thread, so we don't use ConfigureAwait(false);

HttpClient ReadAsAsync<IQueryable<T>> never returns

Im quite new to writing controllers for asp.net and Im trying to return IQueryable, but I cant seem to get the call for the content to return.
This is my controller:
// GET: api/RumsaRooms
[EnableQuery]
public IQueryable<RumsaRoom> GetRooms()
{
return db.Rooms;
}
and this is my client call:
public async Task<IQueryable<T>> GetAllOf<T>()
{
var typeName = typeof(T).Name;
var result = await _client.GetAsync($"api/{typeName}");
if (!result.IsSuccessStatusCode)
{
var exception = await result.Content.ReadAsStringAsync();
}
//This method never returns
var rooms = await result.Content.ReadAsAsync<IQueryable<T>>();
return rooms;
}
I have enabled multipleactiveresultsets in the connectionstring.
The StatusCode is 200.
The method that GetAllOf() looks like this:
private async Task<bool> LoadEntities()
{
var rooms = (await _rumsaClient.GetAllOf<RumsaRoom>()).ToList();
RoomsCollection = new ObservableCollection<RumsaRoom>(rooms);
return true;
}
LoadAllEntities is called in the constructor of my viewmodel.
If I change the call to this it works:
var rooms = await result.Content.ReadAsAsync<List<T>>();
Is it not possible to ReadAsAsync to a IQueryable?
Thanks
Erik
Your problem is almost certainly in this code:
LoadAllEntities is called in the constructor of my viewmodel.
I explain why this deadlock happens in detail on my blog. It doesn't have anything to do with ReadAsAsync or IQueryable. It has to do with calling Wait or Result on an asynchronous task.
In summary:
Tasks returned by async methods are only completed when that method completes.
await by default captures a "context" and uses that "context" to resume the async method.
On ASP.NET, this "context" is an instance of AspNetSynchronizationContext, which only allows one thread in at a time.
When the code calls Wait/Result, it will block the thread (which is still in the ASP.NET request context), waiting for the task to complete.
When the await is ready to resume the method, it does so in the captured context, and waits for the context to be free.
Since await cannot complete the method until the context is free, and the context is in use by a thread waiting until the method completes, you end up with a deadlock.
The proper way to solve this is to not block on asynchronous code; use await instead. This principle is called "async all the way", and is described in my MSDN article on async best practices. Since you're trying to call asynchronous code from a constructor, you may also find my blog post on async constructors helpful, which explains some alternative approaches.

blocking main thread on async/await

I am trying to make my base repository class asynchronous and I am running into some trouble. I am using Dapper ORM in my C# application.
Base method
protected async Task<List<T>> Read<T>(CommandDefinition cmd) {
using(SqlConnection myCon = new SqlConnection(Config.DBConnection)) {
await myCon.OpenAsync();
IEnumerable<T> results = await myCon.QueryAsync<T>(cmd);
List<T> retVal = results.ToList();
myCon.Close();
return retVal;
}
}
Calling method
public List<Category> GetAllActiveCategories(Guid siteGuid) {
return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result;
}
Everything looks in order to me. I have the method declaration decorated with the async keyword. I am awaiting on asynchronous methods.
The problem that I am having is that the thread blocks on await myCon.OpenAsync();. This is my first attempt at using async and await, so I am sure that I am doing something wrong, but it is not obvious. Please help!
The posted Read code is fine. The issue is in the consuming code. It's common to get a deadlock with async if you call Wait() or Result on the returned Task or its antecedent Task up in the call chain.
As always in these cases, the general advice applies: don't block on async code. Once you start using async/await, you should be using async/await throughout your entire call chain.
So, your calling method becomes
public Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) {
return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
}
... or
public async Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) {
List<Category> result = await base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
// Do something.
return result;
}
The culprit is:
return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result;
As Kirill noted, any time you use .Wait() or .Result on a Task, you are blocking synchronously. What you need to do is this:
public Task<List<Category>> GetAllActiveCategories(Guid siteGuid) {
return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
}
This will return a Task to the calling method of this method, and so on... it has to be async "all the way up".
If the top-level consumer of this code is ASP.NET, you're fine. Just return a Task<IActionResult> (or the appropriate return type wrapped in a Task) and the framework will sort out the awaiting for you.
If you're writing a console application or otherwise can't make it "async all the way up", you'll have to either block on .Result or make your method async void and use await. Neither one is a great solution, sadly. Async/await is pretty aggressive in the sense that you really do have to use it throughout your stack.

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