Right to the Point
Why is it if I try running the code below in Visual Studio, and have a break point on the “string urlContents = await getStringTask;” line, I don’t see the call to msdn.microsoft.com until after I execute that line.
I would expect the call to msdn.microsoft.com to occur after processing executes line: Task getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
That's the point of an async method, correct? To kick off tasks that might take a while to run (client.GetStringAsync) so independent work (DoIndependentWork();) can continue while the longer task do their thing.
I am confused by my results. Can someone explain why this occurred.
I am thinking it is because I am running everything on my development machine.
public partial class MainWindow : Window
{
// Mark the event handler with async so you can use await in it.
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
int contentLength = await AccessTheWebAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
// Three things to note in the signature:
// - The method has an async modifier.
// - The return type is Task or Task<T>. (See "Return Types" section.)
// Here, it is Task<int> because the return statement returns an integer.
// - The method name ends in "Async."
async Task<int> AccessTheWebAsync()
{
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
string urlContents = await getStringTask;
// The return statement specifies an integer result.
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
return urlContents.Length;
}
void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
More History and Why are I am asking the questions above
My boss and I were discussing the async / await commands after I read: https://msdn.microsoft.com/library/hh191443(vs.110).aspx (which is where I got the code from above.) There was some debate over how the commands worked so my boss asked me to do some investigation. He suggested running the code above and monitoring it against Fiddler. When I did that I didn’t get the result I expected. I would have expected the call to msdn.microsoft.com to occur after line (Task getStringTask = client.GetStringAsync("http://msdn.microsoft.com");). However, it didn't occur
So, I continued to do research on the commands. Which prompted me to create another demo. I set up the new demo like the one above. However, this demo made a call to a database using an async method, then did some independent work (just like above) and then used the await command (just like above). I monitored this demo using SQL Profiler. This demo gave me the results I would have expected. It proved to me that the async command kicks of the database call before it ran the IndependentWork method.
Here is the code just in case I didn’t explain it clearly
public class HomeController : Controller
{
public Task<string> Index()
{
var returnValue = MacroService();
return returnValue;
}
public async Task<string> MacroService()
{
Task<string> getStringTask = MicroDataService("MicroDataServiceCall");
string string2 = IndependentWork("IndependentWorkCall");
string stringTask1 = await getStringTask;
return $"{stringTask1}, {string2}";
}
public async Task<string> MicroDataService(string parm)
{
string connectionString = ConfigurationManager.ConnectionStrings["xzz"].ConnectionString;
var conn = new SqlConnection(connectionString);
var command = new SqlCommand("sproc", conn);
command.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#ID", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;
param.Value = "00000";
command.Parameters.Add(param);
conn.Open();
await command.ExecuteNonQueryAsync();
conn.Close();
return parm;
}
public string IndependentWork(string parm)
{
return parm;
}
So, I want to understand why I don’t get the same result from the original demo since I know my boss is going to ask.
I am thinking it is because I am running everything on my development machine for the first demo. In the second demo, I am actually using a database server so the second demo kicks off the database processing on that machine.
Let me know. Thanks!!!
Sorry if my description / expectation is not clear. Let me try to be clearer.
My expected result for the first demo was that I would see a call in Fiddler to http://msdn.microsoft.com after Task getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); executed. However, I did not see a call in Fiddler until after line string urlContents = await getStringTask; executed.
Therefore, the first demo did not give me the result I expected.
However, the second demo gave me the results I expected. Which was that I saw a call to the database in SQL Profiler after line: Task getStringTask = MicroDataService("MicroDataServiceCall"); executed.
So, I am trying to understand why I got different behavior. I would have thought that demo1 would have kicked off the async method. I would have seen an entry in Fiddler. Processing would continue in the IndependentWork method. Then continue after the result were returned from the async call. This is what is happening in the second demo.
My guess is that the behavior you observe is because the debugger stops execution of the application before the request is made.
When you hit a breakpoint in a debugger, the whole application stops, it doesn't stop just the current thread. And if the async method you called did not make the request before it returned the Task, then you will not see it in Fiddler.
This probably also explains why you don't observe this with other methods: they do manage to make the request before returning.
Related
Borrowing from the Get method in https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client I have written the following. While being new to C# I assumed the await would complete the API call then move on, but what's happening is that line executes then exits the method without running another line of code (the if statement, the return). I've probably assumed other things as well, which has led me to this predicament.
What should the code be to consistently get a response from the API call and deserialize the Json so I can retrieve the 2 bits of data I actually need?
Any other suggested improvements to my code also greatly appreciated.
The method call:
var ReturnedData = GetProductAsync(companyCode);
The method:
//API Call method - https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
static HttpClient client = new HttpClient();
static async Task<ReturnedAPIdata> GetProductAsync(string CoCode)
{
// TODO - This key will need to be taken out of the code and put in a config file or something
string DavesKey = "abc123";
string path = "http://api.marketstack.com/v1/eod?access_key=" + DavesKey + "&symbols=" + CoCode + ".XASX&sort=DESC&limit=1&offset=0";
ReturnedAPIdata ThatAPIdata = null;
HttpResponseMessage response = await client.GetAsync(path);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
// If we have an API response, deserialise the Json data... somehow
//ThatAPIdata = await response.Content.ReadAsAsync<ReturnedAPIdata>(); // ReadAsAsync has been deprecated, but not replaced. Handy
string responseBody = await response.Content.ReadAsStringAsync();
// Which one of these fuckers actually works. Use an API, they said. It'll be fun, they said. ARG!
ReturnedAPIdata Arses = System.Text.Json.JsonSerializer.Deserialize<ReturnedAPIdata>(responseBody); // attempt 3
List<ReturnedAPIdata> Cock = JsonConvert.DeserializeObject<List<ReturnedAPIdata>>(responseBody); // attempt 2
ReturnedAPIdata Balls = JsonConvert.DeserializeObject<ReturnedAPIdata>(responseBody); // attempt 1
}
Console.WriteLine("FFFFFFFFFfffff....");
return ThatAPIdata;
}
The Conrole.Writeline at the end is just for a breakpoint so I can assess which deserialise attempt works best, I've yet to see be reached to stop on.
If the following code is run:
static void Main(string[] args)
{
Console.WriteLine("Before calling async method");
GetProductAsync();
Console.WriteLine("After calling async method");
}
static async Task<string> GetProductAsync()
{
await Task.Delay(5000);
Console.WriteLine("Inside async method after await");
return "Got all Products";
}
The following result is printed to console:
Before calling async method
System.Threading.Tasks.Task`1[System.String]
After calling async method
So the execution falls through even though the method GetProductAsync is defined as async and there's an await for 5 seconds, also notice that inside of the async method there's a Console.WriteLine("Inside async method after await"); which also doesn't get printed! And the return value doesn't get printed either!
So what's happening here? Just because the method was defined as async and there's an await inside of it won't mean the caller is guaranteed async execution!
Specifically the Main method calling it doesn't await the result so that's why it's falling through.
Now if the code is changed and Main is awaiting the GetProductAsync method:
static async Task Main(string[] args)
{
Console.WriteLine("Before calling async method");
var result = await GetProductAsync();
Console.WriteLine("After calling async method");
Console.WriteLine(result);
}
static async Task<string> GetProductAsync()
{
await Task.Delay(5000);
Console.WriteLine("Inside async method after await");
return "Got all Products";
}
Now the result printed to the console is:
Before calling async method
Inside async method after await
After calling async method
Got all Products
So in this case the result was awaited correctly inside of main, the execution returned to the caller and is now free to continue doing other tasks such as updating the GUI (which isn't the case in this simple console app).
Hopefully this illustrates what's happening here, basically the caller, in this case Main, also needs to await the result from the async GetProductAsync method to see the result.
This article does a good job of explaining various pitfalls and gotchas! without going in too deep
https://www.pluralsight.com/guides/understand-control-flow-async-await
I'm writing a xamarin forms app and I'm using an API that I created. I've followed a tutorial to consume the Api but the code after the async operation never gets executed, it jumps out to the main function.
The code is exactly like the one in the tutorial I've been following. I didn't find any info since there is no error message.
private async void ChecarCredenciales(string username, string password)
{
HttpClient client = new HttpClient();
var url = "http://localhost:57008/api/operadores/" + username;
var response = await client.GetStringAsync(url).ConfigureAwait(false);
Lecturista = JsonConvert.DeserializeObject<Operadores>(response);
}
The JsonConvert.DeserializeObject never gets executed so the Lecturista variable never gets initialized.
Thanks in advance.
First as other already commented change your method to be async Task rather like private async Task ChecarCredenciales(string username, string password){
Second in your await block you are saying to continue on a Threadpool thread context rather on the same synchronization context by doing ConfigureAwait(false);. I would suggest you continue on the same context since on the next step you are requiring the resultant data
var response = await client.GetStringAsync(url);
Lecturista = JsonConvert.DeserializeObject<Operadores>(response);
I have an async codeblock running on the pageload.
The codes run smoothy until you reach capturevalue method where we create a new task.On executing that code block the await just freezes and then the control doesnt come back seems like the code just went to deadlock
protected void Page_Load(object sender, EventArgs e)
{
try
{
var textvalue = GetTextValueFromTask();
txtbox.Text = textvalue.Result;
string ss = "";
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private async Task<string> GetTextValueFromTask()
{
string strReturn = await CaptureValue();
return strReturn;
}
private async Task<string> CaptureValue()
{
Thread.Sleep(5000);
Task<string> T = Task.Factory.StartNew<string>(() => "hi");
return await T;
}
Then I made a small change in Capturevalue method.
private async Task<string> CaptureValue()
{
Thread.Sleep(5000);
Task<string> T = Task.Factory.StartNew<string>(() => "hi");
string ss = T.Result;
return await T;
}
Once I made that change it started working normal.What difference did it make on just fetching the result initially. Please help me Iam a newbee to async
The difference is that second time it doesn't happen any "await" because you waited the task yourself, so await doesn't do anything.
I think you missed the await keyword the first time, here:
var textvalue = await GetTextValueFromTask();
Without it your method GetTextValueFromTask runs synchronously, then it comes into CaptureValue method where await occurs. But the default behaviour of the await is that it tries to capture synchronization context where it was called and to continue the rest of the method in that context, in your example it is WPF synchronization context, which does not allow more than one thread to execute at once. But the continuation cannot proceed, because context is already used by await mechanism.
So, one more time. There is one thread (UI thread), that executes your code up to the last await, which is return await T;, then it yields back to the caller - GetTextValueFromTask, and again to the Page_Load when it gets blocked, because initially you called GetTextValueFromTask synchronously (without await). After that, your operation T completes, and your code tries to continue executing using the initial synchronization context, the WPF one. But it can't, because it is already waiting in the Page_Load.
The link in the comments describes the situation in more detail.
Also consider not using Thread.Sleep in async/await scenarios, because it kills all the "asynchronous" nature of the code. Further reading: link.
Another general piece of advice, which is not directly applicable to your source code, is not to use Task.Factory.StartNew, but rather use Task.Run. Explanation here.
Please use Task.Run() instead of Task.Factory.StartNew()
var T = Task.Run(() => "hi");
It's up to Task.Run to decide how to handle this task.
Also please use .ConfigureAwait(false) in your await calls that do not requires the continuation being done in the awaiter thread context.
Situation
I have a raspberry pi set up as a server taking json via HTTP as input.
The "API" allows to set leds connected to the pi. That all works, I can send requests from the browser and everything is great.
It takes a while for the response to arrive. That's why I want to communicate asynchrounously.
I found this on msdn that explains how it's done.
// Three things to note in the signature:
// - The method has an async modifier.
// - The return type is Task or Task<T>. (See "Return Types" section.)
// Here, it is Task<int> because the return statement returns an integer.
// - The method name ends in "Async."
async Task<int> AccessTheWebAsync()
{
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
string urlContents = await getStringTask;
// The return statement specifies an integer result.
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
return urlContents.Length;
}
For the top level overview, here's how my Main method looks like (it doesn't compile):
var pi1 = new RaspberryPi(#"http://192.168.0.100:8080"); // specify IP
var led = new Led(255, 100, 180); // r, g, b values wrapped in an Led object
Led result = await pi1.setLedAsync(2, led); // FAIL // what should be an async POST, awaiting the response
I hope that makes sense.
The Led class is just a data object holding 3 bytes for the 3 channels and some conversion methods to and from json.
The setLedAsync method:
async public Task<Led> setLedAsync(uint n, Led led)
{
var client = new HttpClient();
client.BaseAddress = _uri;
var content = new StringContent(led.ToJson(), Encoding.UTF8, "application/json");
Task<HttpResponseMessage> response = client.PutAsync("/led/" + n, content);
HttpResponseMessage responseMessage = await response;
string json = await responseMessage.Content.ReadAsStringAsync();
return new Led(json);
}
Error
This line is where I get an error for using await:
Led result = await pi1.setLedAsync(2, led);
await can only be used in an async method.
Questions
Why do I get this error? The last comment line in the example code
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
makes me think that this is how it should be done. As I understand it, the await basically unwrapps the Task<T> into a T.
If I do not use await, I get a type missmatch, because the method returns Task<Led>, not Led.
What's confusing for me is to understand the difference between the example and my situation. I have to use await twice in my async method:
HttpResponseMessage responseMessage = await response;
string json = await responseMessage.Content.ReadAsStringAsync();
The thing is that I have to deal with this HttpResponseMessage as a middleman. I suspect that I'm prematurely giving up the asynchronousity with this second await somehow (if that makes any sense) I think this is the origin of the problem, but I'm not sure how to solve it.
Edit
I wrapped the function call in an asyn method, which allows to compile the code.
But it's not asynchronous. I added a delay on the server side to test this.
class Program
{
static void Main(string[] args)
{
var prog = new Program();
Console.WriteLine("before init");
prog.init();
Console.WriteLine("after init"); // not happening before the response arrives
Console.Read();
}
private async void init()
{
var pi1 = new RaspberryPi(#"http://192.168.0.100:8080"); // specify IP
var led = new Led(255, 0, 0); // r, g, b values wrapped in an Led object
Console.WriteLine("before await");
Led result = await pi1.setLedAsync(2, led); // what should be an async POST, awaiting the response
Console.WriteLine("after await");
}
}
None of the "after" messages are written to the console before the response from the request arrives.
You get the error because an asynchronous wait -- an await -- implies that the method doing the awaiting is itself asynchronous. I think you do not understand what await means. Await does not mean synchronously block until the result is available -- that is the opposite of what it means. Await means return immediately so my caller can do important work without waiting for this result; schedule the remainder of this method at some time in the future when the result is available. Await is an asynchronous wait. When you await a letter to arrive in the mail you do not sit by the door doing nothing until it arrives; you do other work asynchronously and then resume the task of reading your mail at some time after the letter arrives.
You say that the method -- the method doing the awaiting, not the method returning the task being awaited -- is Main. If this is a console app then you cannot make Main asynchronous because when Main returns the program ends. Again, internalize this: an await is just a return from the perspective of the current method. The current method will be called again later in the future and will pick up where it left off, but when Main returns there is no future. So you cannot make Main async.
You note that async turns a task of T into a T, which is correct, but it does so asynchronously. So your principal choices here are here are:
turn the task of T into a T synchronously from Main
write some sort of app other than a Console app; say, a winforms or WPF app, which does not terminate until you tell it to
i go through a msdn sample code where a function is called when button is clicked and when routine is called then Await keyword is used and function has async keyword used.
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
int contentLength = await AccessTheWebAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
When AccessTheWebAsync is called then await keyword is used, what does it mean?
When this function AccessTheWebAsync() will be executing then DoIndependentWork() function is called and i guess here control will be waiting until this function DoIndependentWork() is finished. Am I right?
again there is another statement called
string urlContents = await getStringTask;
why they use here await. if we do not use await here then what would happen?
Please guide me to understand the code that how it is working.
I have an intro blog post here, and the MSDN docs are also extremely good.
You can think of await as "pausing" the method (without blocking the thread) until the awaitable operation completes. When this happens, it returns a task that is not completed to the calling method, so it also has the option to await.
Here's a brief description about async/await methods.
Async Methods:
Caller is not necessarily blocked for the full execution of async
method
Possible return types
void: “fire-and-forget”
Task: allows to await termination of async method
Task<T>: allows to await termination and get result of type T
No ref or out parameter for async methods
Must again contain an await => Otherwise compile warning
await for Tasks
Await termination of a TPL task
Return result of task (if task with
result type)
Must only occur in async methods => Otherwise compile error
An async method is partly synchronous and partly asynchronous
Caller synchronously executes the method until a blocking await
Thereafter, the method rest is asynchronously executed
async & await Mechanism
Efficient
public async Task<int> GetSiteLengthAsync(string url)
{
HttpClient client = new HttpClient(); <= Sync
Task<string> download1 = client.GetStringAsync(url); <= Sync
string site1 = await download1; <= Async (Another thread)
return site1.Length; <= Async (Another thread)
}
Not sure if that simplier for you to understand that in the following way, but this is how it helped myself:
As you can see, the AccessTheWebAsync returns Task<int> but not just int.
If you would have called it without "await", you would just get the Task<int> object as its result. And could do anything further you want (manually) with that task: for instance, to wait until it finishes theTask.Wait(); and obtain the result of int in theTask.Result.
But await does all that instead of you and returns just int: Task<int> => int.
This is it.
from MSDN:
the await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.await does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
So when the compiler encounter
int contentLength = await AccessTheWebAsync();
it waits till the AccessTheWebAsync() task is complted
please take a look at this example C# Async,Await
All await does is blocks the thread until the result of an async operation returns.
Edit: sorry when I said block I should have said suspend, since blocking would prevent execution from continuing!
Edit2: As Alex pointed out - I should have probably said "execution is suspended" rather than the thread. Basically "Stuff happens until await returns but the point is it appears you are writing and executing synchronous code"
Since async operations have the potential to be take a while (e.g. web service calls), they tend to use callbacks to return a result.
If you have to handle callbacks in your code it can get a little messy, especially when waiting on multiple async tasks that are dependant on each other. Async/await and Task simplify the code so that you can write async code literally in the order you would read it.
e.g. example standard async code with callbacks:
public int CallSomeServiceAndReturnItsValue()
{
int result = 0;
WebService.SomeAsyncServiceCall((svcResult) => { result = svcResult.Value; });
return result;
}
and if you have multiple calls that need to be chained:
public int CallSomeServiceAndReturnItsValue()
{
int result = 0;
WebService.GetSomeIdentifier((svcResult) =>
{
var identifier = svcResult.Value;
WebService.GetResult(identifier, (anotherResult) =>
{
result = anotherResult.Value;
}
}
);
return result;
}
As you can see, it starts getting messy, the code doesn't really read in an order that feels natural. The alternative is to use callback methods instead of anonymous methods but still, the callback methods are far away from the code that called them and things can feel disjointed
The other alternative is of course async/await which is much clearer
public int CallSomeServiceAndReturnItsValue()
{
int identifier = await WebService.GetSomeIdentifier();
return await WebService.GetResult(identifier);
}