Using await inside a ContinueWith() block - c#

I have the following code:
var result = MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo)
.ContinueWith((answer) =>
{
if (answer.Result == MessageBoxResult.Yes)
{
Task<bool> asyncTask = ExecuteAsyncFunc();
//asyncTask.Unwrap(); ??
asyncTask.ContinueWith((a) =>
{
// More
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
Invoked elsewhere like this:
public async Task<bool> ExecuteAsyncFunc()
{
await CallAnotherAsyncFunction();
}
I believe that I need to call Unwrap(), where I have tried to, because I am calling await inside a ContinueWith() block. However, I get the following error when I uncomment it:
Error CS1929 'Task' does not contain a definition for 'Unwrap'
and the best extension method overload
'TaskExtensions.Unwrap(Task)' requires a receiver of type
'Task'
Do I need to use Unwrap in this context, and if so, what am I doing wrong?

The short answer is to use await instead of ContinueWith:
var result = MessageBoxHelper.MsgBox.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo);
if (answer == MessageBoxResult.Yes)
{
var a = await ExecuteAsyncFunc();
// More
}
The long answer is that ContinueWith has some dangerous default options (including using an ambient TaskScheduler), and await automatically does everything correctly for you. I go into more detail on my blog.

Do I need to use Unwrap in this context, and if so, what am I doing
wrong?
You need to Unwrap only when your return type is a Task<Task>, and you actually want to do something with the inner task.
For example:
Task<Task> exampleTask = Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
});
If I wanted to actually asynchronously wait on the inner Task, i'd call Unwrap and await on that:
Task exampleTask = await Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
}).Unwrap();
If for any reason you'd want to await on any task returned from your continuation, or want to monitor the inner task, then you'd call Unwrap. There is no need to do that here.
What you're doing is simply invoking an async method inside your ContinueWith, but it doesn't seem like you want to await the result at all.
I'd recommend using async-await wherever possible to reduce the verbosity of ContinueWith. Mixing those two together usually yields bad results as thing get rather complicated. Refactoring that code ends up much cleaner with much less cyclomatic complexity:
var result = await MessageBoxHelper.MsgBox.ShowAsync("Press Yes to proceed",
MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
bool answer = await ExecuteFuncAsync();
}

You say that you have to call unwrap due to your using await inside the ContinueWith; I don't actually see you using await though. I assume what you meant is that you want to await but are not sure how, and thus thought unwrapping is needed. If that is the case, then what you want is to just make your nested Task awaitable. You can do that by making the delegate you provide async
var result = MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo)
.ContinueWith(async (answer) =>
{
if (answer.Result == MessageBoxResult.Yes)
{
await ExecuteAsyncFunc();
}
}, TaskContinuationOptions.OnlyOnRanToCompletion);
public async Task<bool> ExecuteAsyncFunc()
{
await CallAnotherAsyncFunction();
}
This allows you to await within the delegate, within the ContinueWith call and not have to deal with unwrapping.
If you are going to do anything with the Task, such as return it without unwrapping, then this is the right way to go.
public Task<BoolOrSomeOtherReturnType> Foo()
{
return MessageBoxHelper.MsgBox
.ShowAsync /* Continue with etc here */
}
But if you are going to act on the results within the Foo method, then there is no need to use ContinueWith, just await it.
public async Task<bool> Foo()
{
var result = await MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
await ExecuteAsyncFunc();
return true;
}
return false;
}
That simplifies your code quiet a bit. The other thing to note is that your ExecuteAsyncFunc() method does not act on the return value. You simply await and do nothing else.
I noticed that you're not returning true/false, so I assume there is more code there that you just omitted for clarity sake. If that isn't the case, you can save yourself some overhead and just return the Task, allowing someone further up the callstack to await it instead. If your call to CallAnotherAsyncFunction returns Task<bool> then you can just return that call in the same way as well. You only need to await if you have to prevent the method from going any further so you can react to the result of the awaited method. If you don't have to, just return the Task.
public Task<bool> ExecuteAsyncFunc()
{
return CallAnotherAsyncFunction();
}

Related

How to make sure a task is done before returning from a function?

I have a decent understanding of how Async/Await works in C#.
I understand that when the await keyword is reached, control is given back to the calling function and that is how asynchronous execution is achieved (if I am wrong here, I would appreciate correction and a better explanation).
However I am not sure as to how I would make sure that an async function has finished executing before returning from a function.
Take the example below:
private static async Task<bool> LoadDataIntoLocalAppFile(ZipArchiveEntry entry, string key)
{
try
{
/* SqLiteAsyncConnection is an instance variable in the class that has this function.*/
string pathToUse = "localDatabase.db"
if (SqLiteAsyncConnection != null)
{
await SqLiteAsyncConnection.CloseAsync()
.ContinueWith(x => entry.ExtractToFile(pathToUse, true));
}
else
{
entry.ExtractToFile(pathToUse, true);
}
return true;
}
catch (Exception ex)
{
Colsole.WriteLine(ex.ToString());
return false;
}
}
In the above code snippet, I want to make sure that my SqLiteAsyncConnection is closed before I replace the data in the .db file with the contents of entry (so that it does not error out). As such I have used ContinueWith (if this is wrong I would appreciate some clarification).
But I also want to ensure that await SqLiteAsyncConnection.CloseAsync().ContinueWith(x => entry.ExtractToFile(pathToUse, true)); finishes its execution before the function returns. That is I want to ensure that this function does not return true inaccurately, and that it does not return true before await SqLiteAsyncConnection.CloseAsync() .ContinueWith(x => entry.ExtractToFile(pathToUse, true)); finishes its execution.
How do I achieve this?
You don't need the ContinueWith when you have await there. You would use ContinueWith if you don't use await, it can be seen as a type of callback once the parent task has completed/failed.
await SqLiteAsyncConnection.CloseAsync()
.ContinueWith(x => entry.ExtractToFile(pathToUse, true));
//can be replaced by
await SqLiteAsyncConnection.CloseAsync();
entry.ExtractToFile(pathToUse, true);
When you hit an await section in your code, your function isn't done, it doesn't return true, it gets suspended in a sense and the control is given back to calling thread. Once all your awaits have completed in the function, only then does it return the result.
When the await keyword is reached, control is given back to the calling function.
I find this commonly used explanation confusing. In simpler terms, the job of an asynchronous method is to create a Task. That's why you call the method, to get a Task back. You get this Task when the first¹ await is reached inside this method. At this point the asynchronous operation has started, and (generally) it has not completed yet. The caller has received the Task that represents the asynchronous operation, and can continue doing other things while the operation is in-flight. In some cases the caller has nothing better to do than wait for the completion of the asynchronous operation, in which case you see this pattern:
await LoadDataIntoLocalAppFile();
Here the caller is itself an asynchronous method. We know it because of the await keyword. The code above is equivalent with this:
Task task = LoadDataIntoLocalAppFile();
await task;
The first line will complete when the first await inside the LoadDataIntoLocalAppFile is reached. The second line will complete when the last line of code inside the LoadDataIntoLocalAppFile has ran.
¹ To be more precise, the first await of a non-completed awaitable.
Your understanding of async/await is incorrect, just awaiting the asynchronous call is enough:
private static async Task<bool> LoadDataIntoLocalAppFile(ZipArchiveEntry entry, string key)
{
try
{
string pathToUse = "localDatabase.db"
await SqLiteAsyncConnection?.CloseAsync();
entry.ExtractToFile(pathToUse, true);
return true;
}
catch (Exception ex)
{
Colsole.WriteLine(ex.ToString());
return false;
}
}
Then call with:
await LoadDataIntoLocalAppFile(...

How can I await until I receive a callback/notification without busy-waiting?

I understand how I can await on library code to wait for a network request or other long-running action to complete, but how can I await on my own long-running action without busy waiting?
This is the busy-waiting solution. How can I make it event-driven?
public async Task<DataBlock> ClickSend() {
// await until someone calls DataReceived()
while (_Block == null) {
await Task.Yield();
}
return _Block;
}
// Something external calls this function.
// Once called, ClickSend should complete with this data.
public void DataReceived(DataBlock data_block) {
_Block = data_block;
}
DataBlock _Block = null;
(This question is completely different from How do I await events in C#? which is asking how to await on event handlers, but very similar to Promise equivalent in C#.)
Generally in concurrency a "future" is placeholder for a return value and it has an associated "promise" that is fulfilled to pass the final return value.
In C#, they have different names: the future is a Task and the promise is a TaskCompletionSource.
You can create a promise, await on it, and then fulfill it when you get your callback:
TaskCompletionSource<DataBlock> _Promise = new TaskCompletionSource<DataBlock>();
public async Task<DataBlock> ClickSend() {
DataBlock block = await _Promise.Task;
return block;
}
public void DataReceived(DataBlock data_block) {
_Promise.TrySetResult(data_block);
}
Here's an executable example.

Check if Task<bool> is true or false (C#)

I had method, to check count of Landlords шт LandlordTypes
I had this code to check it
var type = _landlordTypeRepository.GetAll()
.Include(x => x.Landlords)
.FirstOrDefault(x => x.Id == input.Id);
if (type.Landlords.Count > 0)
{
throw new UserFriendlyException(L("ThisTypeIsInUse"));
}
But I rewrote it like this
var type = _landlordTypeRepository
.GetAll()
.AnyAsync(x=> x.Id == input.Id && x.Landlords.Any());
But now return type id Task<bool>
How I can use this in if?
You need to use await:
var type = await _landlordTypeRepository.GetAll().AnyAsync(x=> x.Id == input.Id && x.Landlords.Any());
You method must also be marked as async.
I recommend you get acquainted with async - await.
Use await to "unwrap" Task result
bool type = await _landlordTypeRepository.GetAll().AnyAsync(x=> x.Id == input.Id && x.Landlords.Any());
Also mark calling method as async
async Task SomeMethod() {
//..
bool type = await _landlordTypeRepository.GetAll().AnyAsync(x=> x.Id == input.Id && x.Landlords.Any());
//..
}
You can either use the await keyword or simply put .Result at the end of a task to get the value you are looking for.
When using await, your method's signature must have async and must also return a Task (e.g. Task<string> or simply Task for void) unless it's an event which can then be async void.
Using .Result, will block the current thread which means can freeze the UI as well!
A Task is a reference data structure used for asynchronous calls. It contains a .Result-property which will be filled with the return value once the call has completed. Since it is an asynchronous call you cannot know for sure that the call has been completed when receiving a Task the way you have done here.
There is two main ways of dealing with this:
If you're inside an asynchronous context (method using the async keyword), you could just use the await-keyword to wait for and unwrap the result.
var type = await _landlordRepository.GetAll().AnyAsync(...);
If you're in a synchronous context, you can use Task.Wait() to await the call and then read the result value from Task<T>.Result.
var task = _landlordRepository.GetAll().AnyAsync(...).Wait();
var type = task.Result
As people have pointed out, using .Result is usually not advised since it is a blocking call.

c#-WPF: Cannot convert async lambda expression to delegate type 'Func<int>'

Im trying to understand how Lambda expression work with async methods.
I have a function
private int Server_Get_Int(){
Task<int> task = Task.Factory.StartNew<int>( async () => {
FirebaseClient c = Server_Connect();
FirebaseResponse response = await c.GetAsync("todos/set");
return response.ResultAs<int>(); //The response will contain the data being retreived
} );
task.Wait();
int result = task.Result;
Console.WriteLine(result);
return result;
}
I want my async code to run in the lambda expression and get back the result from the server.
But i get back the error:
error CS4010: Cannot convert async lambda expression to delegate type 'Func<int>'. An async lambda expression may return void, Task or Task<T>, none of which are convertible to 'Func<int>'.
It says i can only return a void, task or task<> and to my understanding im returning
task<int>
Is this a problem with what im returning or is this because of async lambda?
Thanks
Edit:
response.ResultAs<int>()
Returns an Int but being inside a Task function it should be returned as a Task
Your whole method is suboptimal. You could rewrite your code to be much simpler. A few comments on your existing code first, however.
You're using Task.Factory.StartNew(), which is dangerous. In
most cases you should simply use Task.Run()
You're using Task.Wait() and Task.Result, which is also suboptimal, not to mention, that Task.Result includes Task.Wait() when accessing it. But I guess, that you want to test the lambda, so it's ok here.
The ResultAs<T>() method converts the response into an int (in your case). The method itself is defined as public virtual T ResultAs<T>(). It needn't return a Task<int>, because your lambda is asynchronous. If you'd remove the async from the lambda you'd have to return a Task<int>, but you can'T do that by simply changing the ResultAs<T> to ResultAs<Task<int>>, you'd have to use a TaskCompletionSource.
Based on the above that we can rewrite your method to this:
private int Server_Get_Int(){
var task = Task.Run(async () => {
var c = Server_Connect();
return (await c.GetAsync("todos/set")).ResultAs<int>();
});
int result = task.Result;
Console.WriteLine(result);
return result;
}
A more concise approach could look like this:
private async Task<int> Server_Get_Int_Async(){
return await Task.Run(async () => {
var c = Server_Connect();
return (await c.GetAsync("todos/set")).ResultAs<int>();
});
}
This creates a new task via Task.Run() and returns that to be completed later.
Based on the comments here are tow ways how you'd call the Server_Get_Int_Asnyc() method. I used explicit types so you can follow my comment, but in almost any case it's better to use var, because the compiler than can choose the best type for the job.
public async Task Foo()
{
// This is the fetch task that's going to be completed sometime in the future. You should almost in any case use configure await on your tasks. For reasons see below.
Task<int> intTask = Server_Get_Int_Async().ConfigureAwait(false);
// Do something other with the task object
// Finally await it and print
int result = await intTask;
Console.WriteLine(result);
}
// Do this if you just need the result and nothing else.
public async Task Bar()
{
int result = await Server_Get_Int_Async().ConfigureAwait(false);
Console.WriteLine(result);
}
In the end it seems, you're pretty new to Task based programming with async/await. I recommend you read the (excellent) introduction article written by Stephen Cleary and go on from there.
The beauty of async/await is, that it propagates naturally through your code and you can write asynchronous code almost like you'd write synchronous code.
Also, placing another article here on why you shouldn't use Wait() or Result to simply get the return value of the async method, since it's going to be noticed much better:
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Test code (console app). This correctly shows "Result: 10".
static void Main(string[] args)
{
Func<Task<int>> func = async () => { await Task.Delay(1000); return 10; };
var task = Task.Factory.StartNew(func);
task.Wait();
int result = task.Unwrap().Result;
WriteLine($"Result: {result}");
ReadKey(true);
}

C# Ninject: How to bind to method async

I am using Ninject 3.2.2.0 and I am trying to bind an async method.
This is what I got so far:
kernel.Bind<Task<MyInterface>>().ToMethod(async ctx =>
{
var someData = await DoSomethingAsync();
return new SomethingElse(someData);
}).InRequestScope();
My method DoSomethingAsync never gets called. I believe it's not being called because MyInterface is being requested, not Task<MyInterface>.
Any ideas?
The construction of your object graph should be reliable and fast. This excludes doing anything that is I/O related. This means that you should not do anything that is asynchronous at all.
Instead anything that is slow, unreliable or asynchronous should be postponed untill after the object graph is constructed.
I ended up making my binding sync
kernel.Bind<MyInterface>().ToMethod(ctx =>
{
var someData = DoSomethingSync(); // <-- Made this one sync, see method below
return new SomethingElse(someData);
}).InRequestScope();
Here is the 'magic'. I changed my method from:
private async Task<string> DoSomethingAsync() {
var result = await DoSomethingElseAsync();
return result;
}
To
private string DoSomethingSync() {
string result = null;
var runSync = Task.Factory.StartNew(async () => {
result = await DoSomethingElseAsync();
}).Unwrap();
runSync.Wait();
return result;
}
I know performance is affected because of the context switch, but at least it works as expected and you can be sure that it won't deadlock.

Categories