I have a snippet that looks like this,
private void btn_Click(object sender, EventArgs e)
{
try
{
var res = Task.Run(() => DoTask(param1, param2));
if(res.IsCompleted)
{
MessageBox.Show("Done");
}
MessageBox.Show("DoTask isn't called yet.");
}
catch
{
MessageBox.Show("Something wrong");
}
}
The DoTask method looks like this
private async Task<bool> DoTask(int p1, int p2)
{
// run long tasks
}
I'd want to show Done message after the task is done. But this never works. Instead the message DoTask isn't called yet. is always called before DoTask does tasks.
Panagiotis' answer is the way to go. Should you have the same situation in a method that is not an event handler and you can't use async for some reason, here's the next best option:
Task<bool> task = Task.Run(() => DoTask(param1, param2));
bool res = task.GetAwaiter().GetResult();
To get Result from Task.Run without await
The proper way to get a result from an asynchronous task is to use await:
private async void btn_Click(object sender, EventArgs e)
{
try
{
var res = await Task.Run(() => DoTask(param1, param2));
if(res)
{
MessageBox.Show("Done");
}
MessageBox.Show("DoTask isn't called yet.");
}
catch
{
MessageBox.Show("Something wrong");
}
}
Note that you should usually avoid async void, but since this code is an event handler, the async void is OK.
Simple Way:
bool result = DoTask(paran1, param2).Result;
No need to use Task.Run(). But you can use it in the following way (BAD WAY):
bool result = Task.Run(() => DoTask(paran1, param2).Result).Result;
Related
I have the 3 methods below in a razor file
protected override async Task OnInitializedAsync()
{
EditContext = new EditContext(_projectModel);
EditContext.OnFieldChanged += EditContext_OnFieldChanged;
}
private async Task EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
await SetOkDisabledStatus();
}
This method is an async method and I have to await it anywhere it is been called
private async Task SetOkDisabledStatus()
{
if (EditContext.Validate())
{
OkayDisabled = null;
await JsRuntime.InvokeVoidAsync("Animate");
}
else
{
OkayDisabled = "disabled";
}
}
I am using the EditContext for validation in a Blazor server application.
I have been getting the error message on this line below in the OnInitializedAsync() method and not sure how to proceed with it.
EditContext.OnFieldChanged += EditContext_OnFieldChanged;
Error Message:
Task MyProject.EditContext_OnFieldChanged(object, FieldChangedEventArgs)'
has the wrong return type.
Expected a method with void EditContext_OnFieldChanged(object?, FieldChangedEventArgs e)
Please note that I am using sonarqube to check all my code.
You can assign an async lambda to the event handler, like this:
EditContext.OnFieldChanged +=
async (sender,args) => await EditContext_OnFieldChanged(sender,args);
But, you should be aware that the EditContext/Form will not await your task. Anything you do in that async task will be out of sync with the editcontext.
You should probably include a cancellation token in your async code as well, so that multiple changes to a field do not fire multiple validation tasks at the same time.
Async validation is hard - make sure you test every possible scenario.
Generated Blazor eventhandlers (like #onclick="...") are flexible about return type and parameters but EditContext.OnFieldChanged is not, it has a fixed delegate type.
Make the following change:
//private async Task EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
private async void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
await SetOkDisabledStatus();
StateHasChanged(); // make sure OkayDisabled takes effect
}
On another note, you can probably make OkayDisabled a boolean and use disabled="#OkayDisabled" where you need it.
Blazor makes the disabled attribute disappear when you assign it with false.
Alternative: keep the validation synchronous. That might prevent some problems as #Mister Magoo points out. And then let only the Animation run async.
private void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
SetOkDisabledStatus();
}
private void SetOkDisabledStatus()
{
if (EditContext.Validate())
{
OkayDisabled = null;
_ = JsRuntime.InvokeVoidAsync("Animate"); // no await, on purpose
}
else
{
OkayDisabled = "disabled";
}
}
StateHasChanged() should not be needed in this scenario.
I have initiated some async infinite loops in my WinForm application, but each time I am trying to break out of them, the program hangs up. I have read some similar topics where people suggested using CancellationTokens, but I am not able to adapt them to my needs. Here is the relevant part of my code.
static bool processStop = false;
static bool processStopped = false;
//Called once
private async void ProcessData()
{
while (!processStop)
{
await Task.Run
(
() =>
{
//Do stuff and call regular not async methods
}
);
}
processStopped = true;
}
//Button click handler to exit WinForm
btnExit.Click += (senders, args) =>
{
processStop = true;
//Programm hangs up here
while (!processStopped);
FormMain.Close();
}
Edited the code
The variables are static.
The Close method is the default Close() method for Forms.
The problem is that the call to Task.Run continues on the main thread. processStop = true; and while (!processStopped); execute synchronously one after the other. This doesn't let the ProcessData method continue its execution and a deadlock occures.
I see a couple of solutions:
Use ConfigureAwait(false) with Task.Run:
private async void ProcessData()
{
while (!processStop)
{
await Task.Run
(
() =>
{
//Do stuff and call regular not async methods
}
).ConfigureAwait(false);
}
processStopped = true;
}
This will cause the ProcessData to continue on a thread pool and you already use a thread pool by calling Task.Run, so it is not a great solution
Wrap the whole process in Task.Run:
static volatile bool processStop = false;
static volatile bool processStopped = false;
//Called once
private async void ProcessData()
{
await Task.Run(() =>
{
while (!processStop)
{
...
}
processStopped = true;
});
}
This would require changing the form of the method passed to work with the loop in it.
Make ProcessData a synchronous method to process CPU-intensive tasks and call it properly. CancellationToken would be the preferred way to cancel the task:
private void ProcessData(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
// do work
}
}
And call it with this:
Task processingTask;
CancellationTokenSource cts;
void StartProcessing()
{
cts = new CancellationTokenSource();
processingTask = Task.Run(() => ProcessData(cts.Token), cts.Token);
}
btnExit.Click += async (senders, args) =>
{
cts.Cancel();
try
{
await processingTask;
}
finally
{
FormMain.Close();
}
}
If you want to spin a bunch of tasks without blocking you can do this:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Called once
private async Task ProcessData()
{
int count = 0;
while (true)
{
await Task.Run
(
() =>
{
this.Invoke(new Action(() => {
label2.Text = (count++).ToString();
label1.Text = DateTime.Now.ToString(); }));
Thread.Sleep(100);
}
);
}
Debugger.Break(); //you will never see this hit at all
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
private async void button2_Click(object sender, EventArgs e)
{
await ProcessData();
}
}
}
The common description of why async void is part of C# is for event handlers. For example:
private async void button_Click(object sender, RoutedEventArgs e)
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("http://example.com");
var content = await response.Content.ReadAsStringAsync();
this.textBox.Text = content;
}
}
I find this reason unsatisfying, as this kind of event handler can be written without async void like this:
private void button_Click(object sender, RoutedEventArgs e)
{
button_ClickAsync().ForgetTask();
}
private async Task button_ClickAsync()
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("http://example.com");
var content = await response.Content.ReadAsStringAsync();
this.textBox.Text = content;
}
}
static class TaskExtensions { public static void ForgetTask(this Task task) { } }
Why isn't the latter good enough? Why is async void a necessary part of C#? What problem can't be solved without async void?
As you showed yourself, it's not necessary. You can write a functionally identical program to one that uses it without using it. It's useful insofar as there simply are times where you really do want to create an async method that doesn't expose any way of observing the result, such as in the situation you mentioned. Could they have designed the feature in such a way that users could accomplish that another way, yes, you showed one possible way, the C# language designers choose another.
Exceptions from an unawaited async Task method will be unobserved, firing the TaskScheduler.UnobservedTaskException event. For example:
static void Main()
{
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs args) => { Console.WriteLine(args.Exception.InnerException.Message + " unobserved"); };
try
{
ThrowExceptionInAsyncTask();
Console.WriteLine("ThrowExceptionInAsyncTask not caught");
}
catch (Exception)
{
Console.WriteLine("ThrowExceptionInAsyncTask caught");
}
GC.Collect();
try
{
ThrowExceptionInAsyncVoid();
Console.WriteLine("ThrowExceptionInAsyncVoid not caught");
}
catch (Exception)
{
Console.WriteLine("ThrowExceptionInAsyncVoid caught");
}
GC.Collect();
}
static async Task ThrowExceptionInAsyncTask()
{
throw new InvalidOperationException("ThrowExceptionInAsyncTask");
}
static async void ThrowExceptionInAsyncVoid()
{
throw new InvalidOperationException("ThrowExceptionInAsyncVoid");
}
Produces:
ThrowExceptionInAsyncTask not caught
ThrowExceptionInAsyncVoid not caught
ThrowExceptionInAsyncTask unobserved
It is used in two cases as in my own knowledge:
In event handlers. Because event handlers cannot have a return type.
In a method intended to have no return type, and not awaited.
What you did here is a good workaround, but think of it as flexibility in language to make life easier for developers and simplify language syntax. Same example like yours is: Why System.Linq exists in C#?! Why we can use syntax like myIntArray.Max() while we can iterate through the array and find the maximum value!
That doesn't mean there is no other reason, but I'm sharing my thoughts and I hope that helps.
I know how to use tasks and such to get it to work without async/await, but all the examples and video's ive watched i still can't figure it out. Some people have it done by Creating a task in the button click and then awaiting that task?
So far:
private async void button1_Click(object sender, EventArgs e) {
var vari = await GetId();
comboBox1.Items.Add(vari);
}
private Task<string> GetId() {
return Task.Run(() => {
return getstring();
});
}
public string getstring() {
Thread.Sleep(5000);//simulate long task
string d = "Example";
return d;
}
I've tried it a couple different ways, Is this the correct way of doing it? is there a way I can eliminate the running of another task in the GetId() method, and just return a string there?
is there a way I can eliminate the running of another task in the GetId() method, and just return a string there?
Task.Run just executes the operation on a new thread. If you don't do it and call GetId directly, it will just run on the UI thread, blocking the UI for 5 seconds.
Just marking a method async doesn't make it run on a new thread, it only means that the method uses await. If you did this:
private async void button1_Click(object sender, EventArgs e) {
var vari = await GetId();
comboBox1.Items.Add(vari);
}
private async Task<string> GetId() {
Thread.Sleep(5000);//simulate long task
string d = "Example";
return d;
}
it would compile (with a warning because GetId doesn't use await), but it would execute synchronously on the UI thread.
What you could do, however, is replace Thread.Sleep (which is synchronous) with Task.Delay (which is asynchronous):
private async void button1_Click(object sender, EventArgs e) {
var vari = await GetId();
comboBox1.Items.Add(vari);
}
private async Task<string> GetId() {
await Task.Delay(5000); //simulate long task
string d = "Example";
return d;
}
In this case, there is no new thread involved. In the background, Task.Delay just sets a kind of timer that will execute the rest of the method (following the await) when the delay is elapsed. The UI thread will be free to do something else in the meanwhile.
For example, I need to use CoreDispatcher for refreshing MVVM properties in the UI Thread.
private void ButtonClick(object sender, RoutedEventArgs e)
{
//Code not compile without keyword async
var dispatcherResult = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
//This method contains awaitable code
await _scanner.ScanAsync();
}
);
dispatcherResult.Completed = new AsyncActionCompletedHandler(TaskInitializationCompleted);
}
private void TaskInitializationCompleted (IAsyncAction action, AsyncStatus status )
{
//Do something...
}
I am expect, then TaskInitializationCompleted handler will fire AFTER ScanAsync method completed, but it fire immediatly after Dispatcher.RunAsync method started and also BEFORE then ScanAsync was completed.
How I can check to really handle async Dispatcher work completed or cancelled?
Instead of registering to the Completed event, you can await RunAsync (Because DispatcherOperation is an awaitable) which will guarantee any code runs only after completion the invocations completion:
private async void ButtonClick(object sender, RoutedEventArgs e)
{
var dispatcherResult = await this.Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
await _scanner.ScanAsync();
});
// Do something after `RunAsync` completed
}