async await for a simple wrapper method - c#

If I write a method that is just wrapping an async method such as this:
public async Task WrapMethodAsync()
{
using(var smtpClient = new SmtpClient())
{
await smtpClient.SendMailAysnc(new MailMessage());
}
}
Is that the same as doing the following:
public Task WrapMethodAsync()
{
using(var smtpClient = new SmtpClient())
{
return smtpClient.SendMailAysnc(new MailMessage());
}
}
Or is the latter not actually running asynchronously?

In this exact scenario the two cases are extremely different because of the using scope.
In the first case you wait (asynchronously) for the SendMailAysnc operation to complete before disposing of the client while in the other case you don't so you would dispose of the client while the operation is still running.
In the general case where there isn't a difference in the general behavior. For example this:
public async Task Run()
{
throw new Exception("stored");
await Task.Delay(-1);
}
VS this:
public Task Run()
{
throw new Exception("thrown");
return Task.Delay(-1);
}
The difference is that the async method has a slight overhead of the whole async mechanism (including a state machine) while the non-async task-returning method has a different exception semantics as exceptions are thrown directly and not stored in the returned task.

The first snippet disposes of the client after the mail is sent, the latter disposes of the client after it starts sending the mail, but before it has finished. Assuming the client isn't supposed to be disposed while it is sending messages, it means that the first solution is very problematic.
Additionally, the error handling semantics are different; exceptions in constructing the Task in the first snippet will result in the method throwing an exception, whereas in the second snippet they result in the return task being marked as Faulted with the appropriate exception set.

Related

Calling async function with `function().Wait()` works, but `async function()` crashes

I'm calling a 3rd party library from my C# code, and have found that ctx.CreateSiteAsync(communicationSiteInfo).Wait(); works well, while await ctx.CreateSiteAsync(communicationSiteInfo); causes the application to crash. As .Wait() to the best of my knowledge causes the thread to block, I'm interested inn getting the await approach to work.
Here an extract from my code to put the above calls in context:
public async Task createSite(string base_url, SiteConfig siteConfig) {
using(var ctx = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(base_url, this.applicationId, this.applicationSecret)) {
ctx.Load(ctx.Web, p => p.Title);
ctx.ExecuteQuery();
CommunicationSiteCollectionCreationInformation communicationSiteInfo = new CommunicationSiteCollectionCreationInformation {
Title = siteConfig.title,
Url = siteConfig.url,
SiteDesign = siteConfig.siteDesign,
Description = siteConfig.description,
Owner = siteConfig.ownerEmailAddress
};
try {
// This works: ctx.CreateSiteAsync(communicationSiteInfo).Wait();
await ctx.CreateSiteAsync(communicationSiteInfo);
} catch....
If I'm not mistaking, the function I'm calling it this one: ClientContextExtensions.cs.
I'm pretty new to C#, so perhaps the reason for the application crashing is obvious, but I can't see why the await wouldn't work, as the function I'm calling has async Task in it's definition.
EDIT: The weird thing regarding the exception is that the application simply crashes, and the catch clause is never reached. I don't know, but maybe this has something to do with threading or context or something in that the exception thrown in the async function call are not returned to the current thread. The application crashes on the await ctx.CreateSiteAsync(communicationSiteInfo); call.
EDIT 2: It looks as though I can simplify the issue at hand, but using this as an example instead:
public async Task StartMessageQueuePollAsync()
{
while (true)
{
await Task.Delay(1000).ConfigureAwait(false);
}
This causes the code to crash on await Task.Delay(1000).ConfigureAwait(false);. If is instead use Task.Delay(1000).Wait(), the code works as expected.
I see your answer, but I don't think that's the root cause. It's perfectly fine to use static async Task Main(), as long as your project is using C# 7.0 or higher (when that was introduced). If changing that (and making everything else synchronous, as you'd have to after removing async) made the symptom go away, then that means that somewhere along your call stack, you were missing an await.
For example, this works just fine:
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
Console.WriteLine("Hello.");
await Pause();
Console.WriteLine("All done");
}
public static async Task Pause() {
await Task.Delay(1000);
Console.WriteLine("Done pausing");
}
}
But if you remove the await in Main, then the application would end before "Done pausing" is printed. This is because async methods run synchronously at first, but return at the first await that acts on an incomplete Task. (Pause() returns a Task when it hits await Task.Delay(1000) - before the waiting is completed)
So if you don't await an async method, then your code will just move on to the next line before the work is done. Sometimes you actually want this, but often not.
Since it otherwise runs synchronously, replacing the await with .Wait() would halt the thread and the method would not return, making it suddenly "work".
In your code, that means that either you weren't awaiting createSite() or weren't awaiting whatever called the method that called createSite(), etc.
Microsoft has a series of very well-written articles about asynchronous articles that are worth reading. Start here: Asynchronous programming with async and await
Thanks for the comments on my initial post. I got it working now, and believe it's because of I defined the Main method to be async, like this:
static async Task Main().

How can I understand where the final 'async' keyword goes in the tree of async-awaits? [duplicate]

I had a situation recently where I had an ASP.NET WebAPI controller that needed to perform two web requests to another REST service inside its action method. I had written my code to have functionality separated cleanly into separate methods, which looked a little like this example:
public class FooController : ApiController
{
public IHttpActionResult Post(string value)
{
var results = PerformWebRequests();
// Do something else here...
}
private IEnumerable<string> PerformWebRequests()
{
var result1 = PerformWebRequest("service1/api/foo");
var result = PerformWebRequest("service2/api/foo");
return new string[] { result1, result2 };
}
private string PerformWebRequest(string api)
{
using (HttpClient client = new HttpClient())
{
// Call other web API and return value here...
}
}
}
Because I was using HttpClient all web requests had to be async. I've never used async/await before so I started naively adding in the keywords. First I added the async keyword to the PerformWebRequest(string api) method but then the caller complained that the PerformWebRequests() method has to be async too in order to use await. So I made that async but now the caller of that method must be async too, and so on.
What I want to know is how far down the rabbit hole must everything be marked async to just work? Surely there would come a point where something has to run synchronously, in which case how is that handled safely? I've already read that calling Task.Result is a bad idea because it could cause deadlocks.
What I want to know is how far down the rabbit hole must everything be
marked async to just work? Surely there would come a point where
something has to run synchronously
No, there shouldn't be a point where anything runs synchronously, and that is what async is all about. The phrase "async all the way" actually means all the way up the call stack.
When you process a message asynchronously, you're letting your message loop process requests while your truly asynchronous method runs, because when you go deep down the rabit hole, There is no Thread.
For example, when you have an async button click event handler:
private async void Button_Click(object sender, RoutedEventArgs e)
{
await DoWorkAsync();
// Do more stuff here
}
private Task DoWorkAsync()
{
return Task.Delay(2000); // Fake work.
}
When the button is clicked, runs synchronously until hitting the first await. Once hit, the method will yield control back to the caller, which means the button event handler will free the UI thread, which will free the message loop to process more requests in the meanwhile.
The same goes for your use of HttpClient. For example, when you have:
public async Task<IHttpActionResult> Post(string value)
{
var results = await PerformWebRequests();
// Do something else here...
}
private async Task<IEnumerable<string>> PerformWebRequests()
{
var result1 = await PerformWebRequestAsync("service1/api/foo");
var result = await PerformWebRequestAsync("service2/api/foo");
return new string[] { result1, result2 };
}
private async string PerformWebRequestAsync(string api)
{
using (HttpClient client = new HttpClient())
{
await client.GetAsync(api);
}
// More work..
}
See how the async keyword went up all the way to the main method processing the POST request. That way, while the async http request is handled by the network device driver, your thread returns to the ASP.NET ThreadPool and is free to process more requests in the meanwhile.
A Console Application is a special case, since when the Main method terminates, unless you spin a new foreground thread, the app will terminate. There, you have to make sure that if the only call is an async call, you'll have to explicitly use Task.Wait or Task.Result. But in that case the default SynchronizationContext is the ThreadPoolSynchronizationContext, where there isn't a chance to cause a deadlock.
To conclude, async methods shouldn't be processed synchronously at the top of the stack, unless there is an exotic use case (such as a Console App), they should flow asynchronously all the way allowing the thread to be freed when possible.
You need to "async all the way up" to the very top of the call stack, where you reach a message loop that can process all of the asynchronous requests.

ThreadAbortException when calling Task.Result

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);
}

Using async keyword in method signature to return a Task in Web Api endpoint

If I wanted to write a non-blocking web api action by returning a Task object, I could do it with or without using the async keyword as such:
Using async
public async Task<HttpResponseMessage> Get()
{
Func<HttpResponseMessage> slowCall = () =>
{
Thread.Sleep(2000);
return Request.CreateResponse(HttpStatusCode.OK, "Hello world");
};
var task = Task<HttpResponseMessage>.Factory.StartNew(slowCall);
return await task;
}
Without using async
public Task<HttpResponseMessage> Get()
{
Func<HttpResponseMessage> slowCall = () =>
{
Thread.Sleep(2000);
return Request.CreateResponse(HttpStatusCode.OK, "Hello world");
};
var task = Task<HttpResponseMessage>.Factory.StartNew(slowCall);
return task;
}
They both work properly. However, every example I've seen (online and in books) on writing a web api action that returns a Task uses the async keyword. Granted, I understand that gives you more flexibility as it allows you to control what you want to "await" on and what not. But assuming your functionality could be effectively handled either way,
Is there any advantage to using one approach vs the other?
Should I always use the async keyword (and if so why)?
Or is it irrelevant?
The async keyword allows you to use an await in your method by creating a state machine. If you can manage returning an asynchronous task without using it you can go ahead and remove it because it has some (very small) overhead. Keep in mind though that it's only useful in a few cases. Your return await is one of them.
Another difference is how exceptions are handled. If there's an exception in the synchronous part of the method and it's marked as async the exception will be stored in the returned task. Without the keyword the exception would be thrown regularly. For example in this case there's a big difference:
var task = Get(); // unhandled exception without async
try
{
var result = await task; // handled exception with async
}
catch
{
}
My recommendation is to use the async keyword even when you don't absolutely need to*, because most developers don't understand the difference and the value in the optimization is mostly negligible.
* Unless you and your teammates really know what you're doing.
There is one advantage to bypassing the await and returning the Task directly: performance. You won't allocate or process the state machine that goes with an async method. There are, however, some subtle differences when exceptions are involved.
In the async example, any exceptions thrown will be enclosed in a Task. This is generally what people assume will happen when they call a Task-returning method. In the sync example, exceptions will be thrown immediately upon invocation.
This will also have an effect on the exception's stack trace. In the async example, it will show Get(). In the sync example, it will show your anonymous delegate or worse, some internal crap in Task.Factory.StartNew with no actual reference to your actual code. This can result in being a little more difficult to debug.

Using the Async framework to make a web call

I'm making a web call using the async framework. I'm getting an Error noted in the code below
class Program
{
static void Main(string[] args)
{
TestAsync async = new TestAsync();
await async.Go();//Error: the await operator can only be used with an async method. Consider markign this method with the async modifier. Consider applying the await operator to the result of the call
}
}
class TestAsync
{
public async Task Go()
{
using (WebClient client = new WebClient())
{
var myString = await client.DownloadStringTaskAsync("http://msdn.microsoft.com");
Console.WriteLine(myString);
}
}
}
I've tried several variations of this code. It either fails at runtime or does not compile. In this case the method completes before my async call is allowed to fire. What am I doing wrong?
My goal is to execute a call to a web site using WebClient in an async fashion. I want to return the result as a string and print it out using Console.WriteLine. If you feel more comfortable starting with code that executes simply change
await async.Go(); to async.Go(); The code will run, but Console.WriteLine will not be hit.
The error message is correctly telling you that await can only be used in async methods. But, you can't make Main() async, C# doesn't support that.
But async methods return Tasks, the same Task used in TPL since .Net 4.0. And Tasks do support synchronous waiting using the Wait() method. So, you can write your code like this:
class Program
{
static void Main(string[] args)
{
TestAsync async = new TestAsync();
async.Go().Wait();
}
}
Using Wait() is the right solution here, but in other cases, mixing synchronous waiting using Wait() and asynchronous waiting using await can be dangerous and can lead to deadlocks (especially in GUI applications or in ASP.NET).
The program is ending before the web request can complete. This is because the Main will not wait for the async operation to complete since it has nothing left to do.
I bet if you make the Main last longer, then Console.WriteLine will get called.
I'd try adding a sleep after the call to the async method - Thread.Sleep(500) - anything long enough to permit the web request to complete should work.

Categories