Using httpclient in MVC application [duplicate] - c#

This question already has answers here:
HttpClient.GetAsync(...) never returns when using await/async
(7 answers)
Closed 9 years ago.
When I invoke below function in a console app, it just works. But when I add the same to a MVC controller, execution never reaches JsonConvert line. Any idea, what I am missing.
Calling code
GetVersion(url).Result.FileVersion
Method
public static async Task<Version> GetVersion(string url, string hostHeader)
{
var client = new HttpClient();
if (!string.IsNullOrEmpty(hostHeader))
{
client.DefaultRequestHeaders.Host = hostHeader;
}
var version = await client.GetStringAsync(url);
var output = JsonConvert.DeserializeObject<Version>(version);
client.Dispose();
return output;
}

You are causing a deadlock, as I explain on my blog. By default, await captures a "context" (in this case, the ASP.NET request context) and uses that to resume the async method. The ASP.NET request context only allows one thread in at a time, and you're blocking that thread by calling Result, thus preventing the async method from completing.
Your console app doesn't deadlock because it doesn't have a "context", so the async methods resume on the thread pool.
The solution is to change the calling code to use:
(await GetVersion(url)).FileVersion

Related

Await doesn't block calling thread [duplicate]

This question already has answers here:
How and when to use ‘async’ and ‘await’
(25 answers)
How do yield and await implement flow of control in .NET?
(5 answers)
Brief explanation of Async/Await in .Net 4.5
(3 answers)
Closed 2 years ago.
I never had a good chance to go deep into async/await , so I have just a gist of what it does.
So I tried it in WinForms app like this:
private async void button2_Click(object sender, EventArgs e)
{
// In below line I understand the Task is created and scheduled to execute, which in this
// simple case means, that it executes right away asynchronously.
var task = Task.Factory.StartNew(() =>
{
Task.Delay(5000).Wait();
return 12;
});
// Here we wait for the task to finish, so we don't see MessageBox yet.
var res = await task;
MessageBox.Show("Result is :" + res);
}
My question is, since we are waiting on await I expected to block UI thread, since we can go any further in that thread (to the line with MessageBox). So UI thread actually stops on method with event hadnler.
But, to my surprise, windows is responsive and everything works very well, but I didn't expect that. Can anybody explain me what is going on?
After reading this post, I still have a doubt, if await is asynchronous and doesn't block UI thread in my example, why the thread doesn't proceed to next line with MessageBox? How the UI thread proceeds then?
Is good idea that code after await is just another Task, like in ContinueWith? But it comes back to UI context?
Async methods are a lot like generator methods. The compiler will split up your code at each await operator. A block of code is inserted to check if the task is already complete, in which case the method immediately continues. Or if the task is not complete, a callback is registered to continue execution later, and your method returns.
Returning early is the whole point of an async method.

Multiple Task.Run vs no await for async method? [duplicate]

This question already has answers here:
When should you use Task.Run() rather than await?
(2 answers)
is using an an `async` lambda with `Task.Run()` redundant?
(3 answers)
What difference does it make - running an 'async' action delegate with a Task.Run (vs default action delegate)?
(2 answers)
Closed 3 years ago.
I have some IO-Bound jobs(periodically write some data to file) codes as follows:
public async Task SaveToFile1(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
public async Task SaveToFile2(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
public async Task SaveToFile3(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
The caller is the main method.
The tasks worked fine and produced the correct result when I run them with 2 ways as follows:
void main ()
{
// other codes
// way 1:
SaveToFile1(1000);
SaveToFile2(1000);
SaveToFile3(1000);
// other codes will not let the app exit
}
void main ()
{
// other codes
// way 2:
Task.Run(async() => await SaveToFile1(1000));
Task.Run(async() => await SaveToFile2(1000));
Task.Run(async() => await SaveToFile3(1000));
// other codes will not let the app exit
}
Which is the right way or another way is the best choice for my situation?
Thanks for your answers!
Edit:
In way 1, when await Task.Delay 'complete', a new thread-pool thread may be captured to execute the loop's next step, ..., loop will always running in other thread at the await hit.
In way 2, may be a new thread-pool thread will be used when Task.Run execute immediately, loop will always running in other thread at the begin.
The result are the same, where is the diffrence?
So my question is not about Task.Run vs async-await!
Asynchronous code allows the current thread to be freed to do other work while waiting for a response from something else. But all the code before the first await will be done on the same thread you call it from. If that code is significantly CPU-heavy, it could be noticeable.
If you don't use Task.Run, the method will be run on the same thread up until the first asynchronous I/O request, when it will return a Task and your next method will be called.
Task.Run will execute the code on a different thread. This is good if it does do some CPU-heavy work and you don't want that done on the current thread (like in a desktop app where you don't want it done on the UI thread). But there is a small cost to starting up a new thread too.
Whether using Task.Run will make any noticeable difference depends on the type of app you're writing and what your methods do.
It's fine if you don't await them immediately, but if you don't ever await them, then you will never know when they finished, if they finished successfully, or threw and exception. This is called "fire and forget". Do that only if you don't care if they succeed.
Instead, you can wait at the end to make sure they completed successfully. For example:
void main ()
{
// other codes
var taskList = new List<Task>();
taskList.Add(SaveToFile1(1000));
taskList.Add(SaveToFile2(1000));
taskList.Add(SaveToFile3(1000));
// other codes will not let the app exit
// wait till everything finishes before exiting
await Task.WhenAll(taskList);
}

UI Received task got cancelled [duplicate]

This question already has answers here:
'await' works, but calling task.Result hangs/deadlocks
(6 answers)
Closed 3 years ago.
In my application, I am trying to update the user profile which calls the Rest API. API has one sync method UpdateProfile where execution getting stuck.
this line of code is ending the execution
command.UserProfile.LookupItems = GetLookupItemsByUserId(existingUser.Id).Result;
When i changed this line of code to
command.UserProfile.LookupItems = Task.Run(async () => await GetLookupItemsByUserId(existingUser.Id)).Result;
It started working without any issue.Can anybody explain to me what is going on behind the scene?
The first version is blocking the current thread, when the task complete the blocked thread cannot catch it.
YourType Signature() {
var neverUsedValue = task.Result;
}
The second one is yielding the current "thread" until the task is returned.
YourType Signature() {
var value = Task.Run(await => async MethodThatWillComplete()).Result
}
What you should do is propagate the async to the method:
async Task<YourType> SignatureAsync() {
command.UserProfile.LookupItems = await GetLookupItemsByUserId(existingUser.Id);
}
In this way you will avoid handling the AggregateException.
There is very well written article on this here:Don't block async
In a few words, blocking on async code is bad because it may be blocking the thread which is supposed to run the async code and thus generete a deadlock.

Asynchronous calls with await [duplicate]

This question already has answers here:
How Async and Await works
(4 answers)
Closed 7 years ago.
I have one question about await keyword. Here is some test code:
string username = await GetUsernameAsync();
// Some other code
var some_variable = username;
My question is: Does waiting starts at first line where we called async method or at the third line where we need the result of async method? Does some other code executes after GetUsernameAsync finishes its execution, or they are executing in parallel?
It happens at the line where the await is.
If you want to delay the waiting, move the await to the moment you need the result. Remember the task, and move on. Then if you need the result, await the task:
Task<string> usernameTask = GetUsernameAsync();
// Some other code
var some_variable = await usernameTask;
The first one. Take into account the await is just sugar syntax. It will be, more or less, replaced by a Task.Wait() to obtain the result. In fact, GetUsernameAsync() will return a Task, not a string.
Take a look to this link to deep more how threads work with the asyn/await pattern

Await operator can only be used within an Async method [duplicate]

This question already has answers here:
Can't specify the 'async' modifier on the 'Main' method of a console app
(20 answers)
Closed 5 years ago.
I'm trying to make a simple program to test the new .NET async functionality within Visual Studio 2012. I generally use BackgroundWorkers to run time-consuming code asynchronously, but sometimes it seems like a hassle for a relatively simple (but expensive) operation. The new async modifier looks like it would be great to use, but unfortunately I just can't seem to get a simple test going.
Here's my code, in a C# console application:
static void Main(string[] args)
{
string MarsResponse = await QueryRover();
Console.WriteLine("Waiting for response from Mars...");
Console.WriteLine(MarsResponse);
Console.Read();
}
public static async Task<string> QueryRover()
{
await Task.Delay(5000);
return "Doin' good!";
}
I checked out some examples on MSDN and it looks to me like this code should be working, but instead I'm getting a build error on the line containing "await QueryRover();" Am I going crazy or is something fishy happening?
You can only use await in an async method, and Main cannot be async.
You'll have to use your own async-compatible context, call Wait on the returned Task in the Main method, or just ignore the returned Task and just block on the call to Read. Note that Wait will wrap any exceptions in an AggregateException.
If you want a good intro, see my async/await intro post.

Categories