Type 'T' is not awaitable - c#

i am creating a task scheduler so i am trying to make some kind of repeating function that accepts Task and awaits it but i get a strange Exception of Type 'T' is not awaitable
public static Task<T> Interval<T>(TimeSpan pollInterval, Func<T> action, CancellationToken token)
{
return Task.Factory.StartNew(
async () =>
{
for (; ; )
{
if (token.WaitCancellationRequested(pollInterval))
break;
await action();
}
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
So can anyone tell me how could i await a that generic Task cuz i want the function to accept any Task, Task, bool or any other type ?

You don't need to start a long running task for this - just make your method asynchronous directly:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
while(true)
{
await Task.Delay(pollInterval, token);
action();
}
}
This will cause the Action to run on the current context. If that is not required, you can use:
await Task.Delay(pollInterval, token).ConfigureAwait(false);
action();
This will cause the Action to not run on the same synchronization context of the caller, and potentially use a ThreadPool thread.
Edit in response to comments:
If you don't want the resulting task to come back canceled, but just return when the token is fired, you could use:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
action();
}
catch(OperationCanceledException e)
{
// Swallow cancellation - dangerous if action() throws this, though....
break;
}
}
}
Edit 2:
If you want to pass in async lambdas, you should make the method take an Func<Task>, not Action:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Func<Task> actionTask, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
}
catch(OperationCanceledException e)
{
// Swallow cancellation
break;
}
await actionTask();
}
}
Edit in response to chat:
If you want to poll, but use the results of an operation, you could use:
public static async Task RunAtIntervalAsync<T>(TimeSpan pollInterval, Func<Task<T>> fetchOperation, Action<T> operationOnResult, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
}
catch(OperationCanceledException e)
{
// Swallow cancellation
break;
}
// Get a value
T value = await fetchOperation();
// Use result (ie: update UI)
operationOnResult(value);
}
}
You could then call this via:
RunAtIntervalAsync(TimeSpan.FromSeconds(1),
async () => { await Task.Delay(1000); return "Foo"; },
result => UpdateUI(result),
token);

You can't.
You can make a function that takes a generic asynchronous function – a function that returns a Task<T>.
That would be a Func<Task<T>>.
You can also make a function that takes a generic synchronous function, which is what you have now.
You can't make a single function that can take either, but you can make two overloads.
On an unrelated note, your function never actually uses the return value of the function.
Therefore, you shouldn't make it generic at all; you should instead take a Func<Task> or an Action.

Check an example here post.
Agree with SLaks, you need to make the generic parameter T of Func awaitable in order to use the await.
For example if T is a string the code would "await" for a function that returns just a string.
The await is valid only for Tasks. For more info check this explanation MSDN Blog; the example is in VB.net.

Related

Cancel an internal task using CancellationToken in ASP.NET Core2.2

I have a method that contains an infinite loop. I call that method from main method and I want to cancel it if it takes more that 2 seconds.
I tried these approaches
Task.WhenAny with cancellation of the non completed tasks and timeout
How can I cancel Task.WhenAll?
How to cancel a task using a CancellationToken and await Task.WhenAny
and lots of other links, but non has worked.
here is my code
static void Main(string[] args)
{
var cts = new CancellationTokenSource(2000);
var task = Task.Run(() => RunTask(), cts.Token);
await task;
}
public static void RunTask()
{
while (true)
{
Console.WriteLine("in while");
}
}
I also tried to cancel my token but it didn't work.
It is not possible to Dispose the task.
I don't have access to RunTask source code. I just can run it.
I cannot send CancellationToken to my method. How can I terminate RunTask() method?
Cancellation tokens are a way to request cancellation. It's up to the running code to accept that request and actually stop the work. It's not like killing a process. For example, if you had something like:
public static void RunTask(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine("in while");
}
}
Then, when it's canceled, the loop will end. However, given that the current code doesn't offer any method of canceling and you cannot modify it, then there is no way to cancel it.
What about this approach:
static void Main(string[] args)
{
var cts = new CancellationTokenSource(2000);
var task = Task.Run(() => RunTask(cts.Token), cts.Token);
await task;
}
public static void RunTask(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
Console.WriteLine("in while");
}
}

Chaining async methods

I'm attempting to chain together a few async methods I've created and I believe there is some fundamental misunderstanding on my part about how this works
Here's a representation of my code:
public async Task<bool> LoadFoo()
{
return await Foo.ReadAsync("bar").ContinueWith((bar) =>
{
Foo.ReadAsync("baz").ContinueWith((baz) =>
{
Foo.ReadAsync("qux").ContinueWith((qux) =>
{
return true;
});
return true;
});
return true;
});
}
public void LoadEverything()
{
LoadFoo().ContinueWith((blah) =>
{
OtherLoadMethod();
});
}
Now I was expecting when LoadEverything() was called that all of the ReadAsync methods in LoadFoo ("bar", "baz" and "qux") would run and complete, and after they all completed then the .ContinueWith in LoadEverything would run so that OtherLoadMethod() wouldn't execute until the "bar", "baz" and "qux" ReadAsync methods finished.
What I am actually seeing is that LoadFoo gets called and then OtherLoadMethod starts to run before getting to the final completion in LoadFoo (the ContinueWith of the "qux" ReadAsync).
Can someone help clear up my misunderstanding here? Why wouldn't the execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?
Why wouldn't execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?
Because that's how await works. The continuations you register are just that: continuations. They are not executed synchronously in the current method. You are telling the framework that when the current task completes, the continuation should be executed. The Task object returned by ContinueWith() allows you to observe the completion if and when it happens. There would be no need to even return a Task object, if the ContinueWith() method blocked until the continuation was executed.
Likewise, the Task<bool> returned by your LoadFoo() method represents the overall completion of the method, including the await...ContinueWith() that you're returning. The method returns prior to completion of the continuation, and callers are expected to use the returned task if they need to wait for the continuation to complete.
All that said, I don't understand why you're using ContinueWith() in the first place. You obviously have access to await, which is the modern, idiomatic way to handle continuations. IMHO, your code should look something like this (it's not clear why you're returning Task<bool> instead of Task, since the return value is only ever true, but I assume you can figure that part out yourself):
public async Task<bool> LoadFoo()
{
await Foo.ReadAsync("bar");
await Foo.ReadAsync("baz");
await Foo.ReadAsync("qux");
return true;
}
public async Task LoadEverything()
{
await LoadFoo();
await OtherLoadMethod();
}
You can also use Unwrap:
public async Task<bool> LoadFoo()
{
await Foo.ReadAsync("bar")
.ContinueWith(_ => Foo.ReadAsync("baz")).Unwrap()
.ContinueWith(_ => Foo.ReadAsync("qux")).Unwrap();
return true;
}
public async Task LoadEverything()
{
await LoadFoo().ContinueWith(_ => OtherLoadMethod()).Unwrap();
}
Did not expect the top solution in search engine was fixing a misunderstanding but not actually the solution of the topic itself.
Chaining call can make great context focus when developing, async is good, and it is better if you know what u r doing.
Code:
//thanks for TheodorZoulias's review and input
public static class TaskHelper
{
public static async Task<TOutput> ThenAsync<TInput, TOutput>(
this Task<TInput> inputTask,
Func<TInput, Task<TOutput>> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
return output;
}
public static async Task<TOutput> ThenAsync<TInput, TOutput>(
this Task<TInput> inputTask,
Func<TInput, TOutput> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = continuationFunction(input);
return output;
}
public static async Task<TInput> ThenAsync<TInput>(
this Task<TInput> inputTask,
Action<TInput> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
continuationFunction(input);
return input;
}
public static async Task<TInput> ThenAsync<TInput>(
this Task<TInput> inputTask,
Func<TInput, Task> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
return input;
}
public static async Task<TOutput> ThenAsync<TOutput>(
this Task inputTask,
Func<Task<TOutput>> continuationFunction,
bool continueOnCapturedContext= true)
{
await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = await continuationFunction().ConfigureAwait(continueOnCapturedContext);
return output;
}
public static async Task ThenAsync(
this Task inputTask,
Action continuationFunction,
bool continueOnCapturedContext= true)
{
await inputTask.ConfigureAwait(continueOnCapturedContext);
continuationFunction();
}
}

Why is await exiting?

Given the following code:
public async Task Send() // part of Sender class
{
// sync code
}
// //
private async Task HandleMessage()
{
// await sender.Send(); // exits HandleMessage immediately
sender.Send().Wait(); // works as expected, waiting to complete
DoOtherStuff(); // doesn't get hit with await
return;
}
RunRecurringTask(async () => await HandleMessage(), result);
public void RunRecurringTask(Action action, RecurringTaskRunResult result)
{
action();
result.DoStuff();
}
I thought that await tells the thread to come back when the awaited thing is complete, but it looks like for some reason that's not happening: the remaining code is never hit and everything just... stops. What could be causing this?
This is a console application in an Azure WebJob, for what it's worth. When Wait is used, I get the expected results, however with await, the job just completes.
You should never do async void unless you are writing a event handler. A Action with the async modifier is a async void method. You need to make the argument a Func<Task> and then do await action() in your RunRecurringTask
private async Task HandleMessage()
{
await sender.Send();
DoOtherStuff();
return;
}
RunRecurringTask(async () => await HandleMessage(), result);
//You also could do
//RunRecurringTask(() => HandleMessage(), result);
public async Task RunRecurringTask(Func<Task> action, RecurringTaskRunResult result)
{
await action();
result.DoStuff();
}
If you had other methods that where not marked with async you will need to change all of them up the call stack till you get to the entry point from the SDK. The SDK understands how to handle functions with a async Task return type since the 0.4.0-beta version.

Task T.IsCancelled = false; How can I make this true?

I have this asynchronous method :
private static async Task Initializ( ) { /*Do Stuff Here*/ }
I want to be able to monitor the task that results from calling this function :
Task T = Class.Initialize( );
if (T.IsCancelled){ /*Do Stuff Here*/ }
I have in place a CancellationTokenSource.
How can I make T (or the function Initialize) utilize that sources token such that if it is cancelled, T.IsCancelled will be true?
EDIT
I do not know for certain but I think the answer to my question lies within using a TaskCompletionSource object. The answer given by Mike has lead me to this conclusion...
From the documentation
A Task will complete in the TaskStatus.Canceled state under any of
the following conditions:
Its CancellationToken was marked for cancellation before the task
started executing,
The task acknowledged the cancellation request on its already signaled
CancellationToken by throwing an OperationCanceledException that bears
the same CancellationToken.
The task acknowledged the cancellation request on its already signaled
CancellationToken by calling the ThrowIfCancellationRequested method
on the CancellationToken.
Updated:
Use this method:
async Task<Task> UntilCompletionOrCancellation(Task asyncOp, CancellationToken ct)
{
var tcs = new TaskCompletionSource<bool>();
using(ct.Register(() => tcs.TrySetResult(true)))
await Task.WhenAny(asyncOp, tcs.Task);
return asyncOp;
}
Consuming task:
var cts = new CancellationTokenSource();
await UntilCompletionOrCancellation(Class.Initialize, cts.Token);
if (!Class.Initialize.IsCompleted)
{
/*Do Stuff Here*/
}
Another approach is to remove async from Initialize
private static Task Initialize()
{
var tcs = new TaskCompletionSource();
//use TrySetResult or TrySetCancelled
return tcs.Task;
}
You can await this task and check whether is canceled or completed.
It is enough to just throw an OperationCanceledException from your asynchronous method.
The following writes true to the console:
public static void Main()
{
Console.WriteLine(DoSomethingAsync().IsCanceled);
}
private static async Task DoSomethingAsync()
{
throw new OperationCanceledException();
}
A nicer way to support cancellation is to have your asynchronous method take a CancellationToken as a parameter, it may then use this token to check for cancellation, e.g:
public static async Task DoSomethingAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
}
You need to call CancellationToken.ThrowIfCancellationRequested() inside the method and let the exception bubble up.
CancellationTokenSource cts = new CancellationTokenSource();
Task T = Class.Initialize(cts.Token);
if (T.IsCancelled){ /*Do Stuff Here*/ }
private static async Task Initializ(CancellationToken token )
{
/*Do Stuff Here*/
token.ThrowIfCancellationRequested();
/*Do More Stuff Here*/
}

Using async/await with Dispatcher.BeginInvoke()

I have a method with some code that does an await operation:
public async Task DoSomething()
{
var x = await ...;
}
I need that code to run on the Dispatcher thread. Now, Dispatcher.BeginInvoke() is awaitable, but I can't mark the lambda as async in order to run the await from inside it, like this:
public async Task DoSomething()
{
App.Current.Dispatcher.BeginInvoke(async () =>
{
var x = await ...;
}
);
}
On the inner async, I get the error:
Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type.
How can I work with async from within Dispatcher.BeginInvoke()?
The other answer may have introduced an obscure bug. This code:
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
uses the Dispatcher.Invoke(Action callback) override form of Dispatcher.Invoke, which accepts an async void lambda in this particular case. This may lead to quite unexpected behavior, as it usually happens with async void methods.
You are probably looking for something like this:
public async Task<int> DoSomethingWithUIAsync()
{
await Task.Delay(100);
this.Title = "Hello!";
return 42;
}
public async Task DoSomething()
{
var x = await Application.Current.Dispatcher.Invoke<Task<int>>(
DoSomethingWithUIAsync);
Debug.Print(x.ToString()); // prints 42
}
In this case, Dispatch.Invoke<Task<int>> accepts a Func<Task<int>> argument and returns the corresponding Task<int> which is awaitable. If you don't need to return anything from DoSomethingWithUIAsync, simply use Task instead of Task<int>.
Alternatively, use one of Dispatcher.InvokeAsync methods.
I think you can use below code and then depends of place use it with async and await or without to fire and forget:
public static Task FromUiThreadAsync(Action action)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Dispatcher disp = GetUiDispatcher();
disp.Invoke(DispatcherPriority.Background, new Action(() =>
{
try
{
action();
tcs.SetResult(true);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}));
return tcs.Task;
}
Use Dispatcher.Invoke()
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
(Edit: This answer is wrong, but I'll fix it soon)
Declare this
public async Task DoSomethingInUIThreadAsync(Func<Task> p)
{
await Application.Current.Dispatcher.Invoke(p);
}
Use like this
string someVar = "XXX";
DoSomethingInUIThreadAsync(()=>{
await Task.Run(()=> {
Thread.Sleep(10000);
Button1.Text = someVar;
});
});
DoSomethingInUIThreadAsync receives a delegate that returns a Task, Application.Current.Dispatcher.Invoke accepts a Func callback that can be awaited.

Categories

Resources