Ok, so I got this little call to a public API using HttpClient:
using (var httpClient = new HttpClient()) {
var response = await httpClient.GetAsync(uri);
}
As soon as the operation reaches the GetAsync() line, the application closes without any exception, neither in the call stack nor in the event callback I've set up to catch unhandled app domain exceptions. I've already figured out it might be because await observes the executing task and supresses any exceptions, however if I remove the await keyword, the operation runs fine! What could be the problem here?
You probably fire that operation without waiting/awaiting for that operation to complete. So the asynchronous operation is fired, but the application goes on and ends before the operation itself has had a chance to complete.
Simply await the root call (or use Wait on the task if you can't use await in that context).
Related
Consider the following WebAPI method:
[HttpPost]
public async Task<IHttpResult> CreateWorkItem(Item wi)
{
var item = await dataContext.Item.AddAsync(wi);
await dataContext.SaveChangesAsync();
return Ok();
}
Is there a situation where it would be safe not to await for a SaveChangesAsync() method?
In theory I would have a faster response time if I just sent a response while the flushing to database gets done in the background.
Is my assumption correct?
There's nothing magical about the await keyword. It quite literally means "wait on this task to complete before moving on". Tasks return hot, or already started, so whether you await them or not, the work is happening.
However, things can get dicey in situations where you don't wait for task completion. In particular, here, your context, which is required to actually do the save operation (remember that it owns the physical DB connection) is request-scoped. That means if you do not await the save and return from the action, you're now essentially in a race to see which completes the first: the save operation or the end of the request. If the end of the request (i.e. the final response is flushed to the client) occurs first, the context is disposed taking the active transaction and your SQL connection with it.
Another important reason to await is for proper exception handling. If you do not await, any exceptions thrown during the save will essentially be swallowed because the code has already moved on. That means you have no real assurances that the save actually completed successfully; all you've got is a wish and prayer.
With very rare exception, all async tasks should be awaited all the time. It doesn't always need to be in the same line (such as when using things like Task.WhenAll to await a series of tasks), but at some point or another the await keyword should be there. FWIW, those rare exceptions are mostly confined to desktop and mobile development where you often need to fire work off on new threads to prevent blocking the main, or UI, thread. That's not remotely a concern for web applications, so you can pretty much consider the "await all the things" rule universal in that context.
I'm still trying to wrap my head around when I can use .Result, and when I can't. I have been trying to avoid it entirely, by using async "all the way down".
While doing some work in our ASP.NET web app (NOT core), I came across this code. Now, the code works (and has been working for 2 years), so I know it works, I just don't know why it works.
This is fired from a sync controller method. It is a chain of method calls that goes through a few layers until it finally does some HTTP work. I have simplified the code here:
// Class1
public byte[] GetDocument1(string url)
{
return class2.GetDocument2(url).Result;
}
// Class2
public Task<byte[]> GetDocument2(string url)
{
return class3.GetDocument3(url)
}
// Class3
public async Task<byte[]> GetDocument3(string url)
{
var client = GetHttpClient(url);
var resp = client.GetAsync(url).Result;
if(resp.StatusCode == HttpStatusCode.OK)
{
using(var httpStream = await resp.Content.ReadAsStreamAsync())
{
// we are also using
await httpStream.ReadAsync(...);
}
}
}
So as far as I can tell, when this all starts, I'm on the "main ASP sync context" (I start in a controller and eventually get to this code). We aren't using any .ConfigureAwait(false), so I believe we are always returning to this context.
In GetDocument3, why doesn't client.GetAsync(url).Result deadlock?
GetDocument3 is mixing .Result with await stuff. In general, is that a good idea?? Is it OK here because .Result comes before the awaits?
In GetDocument1, why doesn't .Result deadlock?
client.GetAsync(url).Result is synchronously blocking. resp.Content.ReadAsStreamAsync() is actually not doing any awaiting. The Task is already completed, because HttpCompletionOption.ResponseContentRead is used in GetAsync, so the entire block of code here is synchronous code pretending to be asynchronous.
In general, you should never use .Result or .Wait or Task.Wait* - if you absolutely have to, use GetAwaiter().GetResult(), which doesn't throw exceptions wrapped in AggregateExceptions, for which you may not have a catch, but even that should be avoided like the plague. You're right to use async all the way down.
The deadlock is only a problem in a context that wants to return back to the original thread (e.g. UI or ASP.NET), and that thread is blocked by a synchronous wait. If you always use ConfigureAwait(false) on every await, unless you know you actually need to preserve the context on the continuation (usually only at the top level UI event handler because you need to update something on the UI, or in the top level of the ASP.NET controller) then you should be safe.
Synchronous blocking inside asynchronous code also isn't good, but won't cause the deadlock. Using await with ConfigureAwait(true) (the default), inside a synchronous wait, in a context that wants to return back to a specific thread will cause the deadlock.
I use standard HttpListener from System.Net namespace. When I use Task.Delay to simulate some work on server side (without await) and test server with Apache benchmark it gives good results (2000 rps). But when I'm "awaiting" bandwith is about 9 rps (according to Apache Benchmark). Why is it behave like this? Appreciate for answers.
private async Task Listen()
{
while (listener.IsListening)
{
try
{
var context = await listener.GetContextAsync().ConfigureAwait(false);
context.Response.StatusCode = (int)HttpStatusCode.OK;
// good without await
await Task.Delay(100).ConfigureAwait(false);
using (var sw = new StreamWriter(context.Response.OutputStream))
{
await sw.WriteAsync("<html><body>Hello</body></html>");
await sw.FlushAsync();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
public async Task Run()
{
listener.Start();
Task.Run(() => Listen());
}
This is because the pause you've inserted delays the loop.
You only accept requests on the line:
await listener.GetContextAsync()
which is in this same loop.
This means that you have to wait for the previous request to complete before you accept a new context.
Most likely, you want to handle the accepted contexts concurrently. To achieve this, you should accept contexts in a tight loop, then spin off the handling of the request to a different place which doesn't "hang" the accept loop.
At it's simplest, you could "fire and forget"...
while (listener.IsListening)
{
var context = await listener.GetContextAsync().ConfigureAwait(false);
HandleContextAsync(context); //note: not awaited
}
...in reality, you'll need to think a bit harder about how to track exceptions in the HandleContextAsync method.
The Delay() Task is created and allowed to run in its own time, without influencing the creating method any further. If you neither await (asynchronous) or Wait() (synchronous) on that Task, then the creating method carries on immediately, making it appear 'fast'. await actually waits for the delay Task to complete, but does it in a way that means the thread does not block and can execute other work concurrently. Your other version doesn't wait at all, synchronously or otherwise. The delay Task is created and runs, but since nothing else cares when it finishes, it just gets executed and garbage-collected playing no further part in the method.
That's because you wait 100 ms before processing a next request, so you can process maximum 10 requests per second. Task.Delay without await doesn't affect your application at all, you can remove this line and as a result still will be handle 2000 request per second.
I have the following code where I'm trying to make a request to a remote endpoint using HttpClient:
using (var client = new HttpClient())
{
client.BaseAddress = _serviceBaseAddress;
Task<HttpResponseMessage> readResponseTask = client.GetAsync(relativeUri);
readResponseTask.Wait();
using (var response = readResponseTask.Result)
{
if (response.StatusCode == HttpStatusCode.NotFound || !response.IsSuccessStatusCode)
{
return default(TResult);
}
Task<TResult> readContentTask = response.Content.ReadAsAsync<TResult>();
readContentTask.Wait();
TResult value = readContentTask.Result;
return value;
}
}
..and occassionally I would get ThreadAbortException at the readResponseTask.Result like so:
System.Threading.ThreadAbortException: Thread was being aborted. at
System.Threading.Monitor.ObjWait(Boolean exitContext, Int32
millisecondsTimeout, Object obj) at
System.Threading.ManualResetEventSlim.Wait(Int32 millisecondsTimeout,
CancellationToken cancellationToken) at
System.Threading.Tasks.Task.SpinThenBlockingWait(Int32
millisecondsTimeout, CancellationToken cancellationToken) at
System.Threading.Tasks.Task.InternalWait(Int32 millisecondsTimeout,
CancellationToken cancellationToken) at
System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout,
CancellationToken cancellationToken)
Under what circumstance will the .Result throw such an exception? I have tried simulating a timeout on the remote endpoint but I got the exception at the .Wait() instead of .Result. Since the exception happens after .Wait(), I'm assuming the result has already been returned from the remote site but somehow something went wrong when it tries to access the result.
Any clues? Could it be something to do with thread concurrency?
I would get ThreadAbortException at the readResponseTask.Result
No, you don't. The call stack clearly shows that it is in fact the Wait() call that produced the exception. Note the frequent appearance of the word "wait" in the trace.
Hard to see how you got confused. Keep in mind that the Task.Result property getter is very small and is going to be inlined when you run the Release build of your program. So you never can see it back in the stack trace.
Perhaps you'll be ahead by simply removing the Wait() call. It isn't necessary, the Result property getter already performs a wait if necessary.
During Wait(), the thread is aborted from outside. Nobody can tell for sure why.
Enabling network client trace can help detecting the root cause.
First, do not use .*Async() if you're going to immediately call .Wait(). This is poor practice and will more than likely lead to errant results. Instead use the synchronous versions of the calls, client.Get(relativeUri) and the following:
TResult value = response.Content.ReadAs<TResult>();
return value;
If you intend on not taking advantage of the .NET frameworks asynchronous programming model.
But if you would rather take advantage of the asynchronous I/O capabilities, you should do so following the best practices. Use the async/await keywords and make your methods look as though they are synchronous while leveraging the capabilities of the .NET framework's asynchronous keywords.
I can only imagine the entry point to your method looks something like this:
public TResult InvokeClientGet<TResult>(string relativeUri)
{
// ... left out for brevity
}
This is actually preventing you from using the async/await keywords. Instead try the following:
public async Task<TResult> InvokeClientGet<TResult>(string relativeUri)
{
try
{
using (var client = new HttpClient { BaseAddress = _serviceBaseAddress })
{
using (var response = await client.GetAsync(relativeUri))
{
if (response.StatusCode == HttpStatusCode.NotFound ||
!response.IsSuccessStatusCode)
{
return default(TResult);
}
return await response.Content.ReadAsAsync<TResult>();
}
}
catch (Exception ex)
{
// Handle exceptional conditions
}
}
A few words specifically about System.Threading.ThreadAbortException.
When a call is made to the Abort method to destroy a thread, the common language runtime throws a ThreadAbortException. ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. When this exception is raised, the runtime executes all the finally blocks before ending the thread. Because the thread can do an unbounded computation in the finally blocks or call Thread.ResetAbort to cancel the abort, there is no guarantee that the thread will ever end. If you want to wait until the aborted thread has ended, you can call the Thread.Join method. Join is a blocking call that does not return until the thread actually stops executing.
With that being said, if something is calling .Abort() and causing this exception. There isn't much you can do to prevent it. Regardless, try following best practices.
I had the same problem while testing a method via Unit-Tests which was sending Data to a WebService. (ik there are better ways to do that)
The problem was that the Unit-Test called my async method but didn't waited unitl the WebService call had finished. This aborted the WebService call and i got an ThreadAbortException.
[TestMethod]
public void WebServiceTest01(){
BusinessLogic bs = new BusinessLogic();
bs.CallWebService();
}
All I needed to do was to make the Unit-Test wait until the WebService call has finished by adding the keyword await.
[TestMethod]
public void WebServiceTest01(){
BusinessLogic bs = new BusinessLogic();
var result = await bs.CallWebService();
Assert.NotNull(result);
}
I'm using the HttpClient to post data to a remote service in a .NET 4.0 project. I'm not concerned with this operation blocking, so I figured I could skip ContinueWith or async/await and use Result.
While debugging, I ran into an issue where the remote server wasn't responsive. As I stepped through the code, it seemed like my code just stopped running on the third line... the current stack pointer line stopped being highlighted yellow, and didn't advance to the next line. It just disappeared. It took me a while to realize that I should wait for the request to timeout.
var client = new HttpClient();
var task = client.PostAsync("http://someservice/", someContent);
var response = task.Result;
My understanding was that calling Result on the Task caused the code to execute synchronously, to behave more like this (I know there is no Post method in the HttpClient):
var client = new HttpClient();
var response = client.Post("http://someservice/", someContent);
I'm not sure this is a bad thing, I'm just trying to get my head around it. Is it really true that by virtue of the fact that the HttpClient is returning Tasks instead of the results directly, my application is automatically taking advantage of asynchrony even when I think I'm avoiding it?
In Windows, all I/O is asynchronous. Synchronous APIs are just a convenient abstraction.
So, when you use HttpWebRequest.GetResponse, what actually happens is the I/O is started (asynchronously), and the calling thread (synchronously) blocks, waiting for it to complete.
Similarly, when you use HttpClient.PostAsync(..).Result, the I/O is started (asynchronously), and the calling thread (synchronously) blocks, waiting for it to complete.
I usually recommend people use await rather than Task.Result or Task.Wait for the following reasons:
If you block on a Task that is the result of an async method, you can easily get into a deadlock situation.
Task.Result and Task.Wait wrap any exceptions in an AggregateException (because those APIs are holdovers from the TPL). So error handling is more complex.
However, if you're aware of these limitations, there are some situations where blocking on a Task can be useful (e.g., in a Console application's Main).
Capturing the result of a task blocks the current thread. There is no point in using a async version of a method in this case. Post() and PostAsync().Result will both block.
If you want to make use of concurrency, you should write it as such:
async Task PostContent()
{
var client = new HttpClient();
Task t = await client.PostAsync("http://someservice/", someContent);
//code after this line will execute when the PostAsync completes.
return t;
}
Since PostContent() itself returns a Task, the method calling it should also await.
async void ProcessResult()
{
var result = await PostContent();
//Do work with the result when the result is ready
}
For instance, if you call ProcessResult() in a button click handler, you see that the UI is still responsive, other controls still function.