I have a void event handler that consists of exactly one line that's a call to an awaitable method.
void Handler( object sender, EventArgs args ) => AwaitableMethod();
Changing the return type to Task isn't an option, so it's fire-and-forget no matter the syntactic sugar. Even so, Visual Studio puts a green squiggly under the unawaited call, suggesting I make the handler async void and await the call.
async void Handler( object sender, EventArgs args ) => await AwaitableMethod();
My understanding is that adding async void and await in this case would just be useless overhead. Does Visual Studio know something that I don't know, or is it just being unnecessarily annoying?
My understanding is that adding async void and await in this case would just be useless overhead.
No.
If Handler returned a Task, then that would be true and eliding async/await would be fine; the code without async/await would just return the Task directly instead of "unwrapping" it with await and "wrapping" it back into a Task with async.
However, that's not the case here; Handler returns void, so the code without async/await will just ignore the returned Task, which is wrong the vast majority of the time (hence the compiler warning). Specifically, ignoring the Task will ignore any exceptions from that Task. It's also not possible for your code to know when an ignored Task has completed, but presumably that's acceptable since your handler is returning void.
There is a "registration" that async void methods do so that the framework is aware there is a task still in progress, so the framework knows when it's safe to shut down. The only .NET provided framework that actually cares about that is ASP.NET pre-Core; all other .NET-provided frameworks (including all UI frameworks) ignore that "registration".
In this particular case, it depends mostly on your error handling.
If AwaitableMethod asynchronously throws, it will throw on the UI thread on the second version.
I would suggest to avoid event handlers in this case and use something like this instead if possible.
public class Eventful
{
private readonly List<Func<Task>> _handlers = new List<Func<Task>>();
public void AddHandler(Func<Task> handler) => _handlers.Add(handler);
private async Task RunHandlers()
{
foreach (var handler in _handlers)
{
await handler();
}
}
}
public class Consumer
{
public Consumer()
{
var eventful = new Eventful();
eventful.AddHandler(async () =>
{
await DoAsyncTask();
});
}
private static async Task DoAsyncTask()
{
await Task.CompletedTask;
}
}
Related
I want to use delegate for my async events. But whole topic seems difficult to me.
I don't know how to register events and how to register handlers that has the same logic for all raises. By this I mean that I want to have async event handler with always the same logic that is always invoked when appropriate event is invoked.
From what I've seen I would have to use a static class for handler like this. But I can't use static class, because my handler need to use some dependencies.
My understanding of this looks like:
I really don't understand how to use async events and generally how to properly define, use and handle events. Please explain it and give me easy example. Thank you in advance.
Async
When working with async methods, you usually return a Task to the caller to wait for.
async Task MyAsyncMethod()
{
// async will implicitly create a new task and return it.
return;
}
var task = MyAsyncMethod();
// execute the task
await task;
// the task is done
If you don't, the async keyword will execute the method because it can't create a task.
async void MyAsyncMethod()
{
return;
}
// the method execution is started, because it's async
MyAsyncMethod();
Events
Usually, the event source (MyAppEvents) only cares about raising events, it doesn't know how many listeners there are, so it can't excepted them a return value.
To define an event, you need 2 things
the event handlers signature
the event definition (its name basically)
// event handlers signature
public delegate SomeReturnValueType MyEventDelegate(FirstArgType arg1);
// event definition
public event MyEventDelegate MyEventName;
You could think that you could use SomeReturnValueType to return values from the handlers, but if you do so
var result = MyEventName.Invoke();
result would be set to the last handler's return value.
Mixing both
If you define your handlers to return a Task and try to await them when raising the event, you'll only await the last handler's task.
// task only represents the last handler
var task = MyAsyncEvent.Invoke();
await task;
Doing this may lead to confusion, so I'd recommand to define the handlers delegate to not return a Task, so nobody is attempted to await.
public delegate void MyAsyncMethod();
When raising an event, the execution will continue as the event source doesn't (and shouldn't) know about the handlers.
Workaround
Making use of dependency injection, you could define services as your event handlers.
public interface IEventHandler<in TEvent>
{
Task ExecuteAsync(TEvent #event);
}
// custom handler
public class CustomEventHandler : IEventHandler<CustomEvent>
{
public Task ExecuteAsync(CustomEvent #event)
{
// do logic
}
}
// the event source
public class MyAppEvents
{
private readonly IEnumerable<IEventHandler<CustomEvent>> _handlers;
public MyAppEvents(IEnumerable<IEventHandler<CustomEvent>> handlers)
{
_handlers = handlers;
}
private async Task RaiseCustomEventAsync()
{
var #event = new CustomEvent();
var tasks = _handlers.Select(h => t.Execute(#event));
// execute all task and await them
await Task.WhenAll(tasks);
}
}
In ASP.NET Core, you can use the EventBus pattern to define, raise, and handle async events,the EventBus is a service that acts as a message broker between different parts of your application,you can use it to register events and handlers, and then raise events as needed.
I am working on an old WinForms application. I'm trying to make a piece of code run asynchronously, so it doesn't block the UI thread. I'm having some difficulties applying the pattern. Here's a simplified version of my code (before modifications):
void InitializeMyGui()
{
//some code
if(someObject.SomeConditionIsMet())
{
//some code
}
else
{
//some other code
}
// some more code
}
This method is called from two places. One is the constructor:
public MyGui()
{
// some code
InitializeMyGui();
// some more code
}
The other is a method that is triggered by an event handler (this application is older than async/await, event driven programming was used to achieve asynchronous execution)
private void OnSomeOtherStuffFinishedLoading(object sender, EventArgs e)
{
// some code
InitializeMyGui();
// some more code
}
Problem is SomeConditionIsMet() contains a database call, so it needs to be asynchronous to avoid long operations blocking the UI thread if the DB call is slow. No worries, I've modified my methods thusly:
public async Task<bool> SomeConditionIsMet() {
//some code
await dbAdapter.ExecuteAsync();
//process and return result
}
Now InitializeMyGui() obviously needs to await SomeConditionIsMet():
async void InitializeMyGui()
{
//some code
bool conditionMet = await someObject.SomeConditionIsMet();
if(conditionMet)
{
//some code
}
else
{
//some other code
}
// some more code
}
And herein lies the problem. InitializeMyGui() is now async, and should be awaited. Indeed, everything I've read regarding async/await explicitly states you should await async calls all the way to the top. But while I could probably make OnSomeOtherStuffFinishedLoading() async and have it await InitializeMyGui(), I can't make the constructor async.
In this case, it's not such a big deal. InitializeMyGui() is a void, it's not returning any value. But if I understand it correctly, if I don't await the method, the execution will continue before it returns, and the code that comes after, (in my pseudocode marked // some more code) could - and in all likelihood will - execute before InitializeMyGui() finishes.
What I'm missing is a way to say "Hey, run this async method, and then continue with this code here, but do it all asynchronously so that you're not blocking the UI thread" but without making the calling mehtod itself async. Is there a way to do this?
EDIT:
I came up with this:
Task.Run(InitializeMyGui()).ContinueWith(t => {// some other code});
Will this work, or am I somehow violating the sanctity of the UI thread?
First off, InitializeMyGui should be async Task, not async void.
To solve your problem, you need to accept that you now have an additional state in your application. Previously, the code would block the UI thread until it was ready to show the complete UI (after the DB call). What you're doing by making it asynchronous is freeing up that UI thread. But then the UI has to show something. So what you really have is a new "loading" kind of state in your app.
So, the best solution is to have your constructor (synchronously) initialize to the loading state, and then have it update to the loaded state. I wrote an article about this technique - it uses MVVM/WPF, but the concepts are the same.
The natural way to do this is to use async/await rather than ContinueWith:
public MyGui()
{
// some code
Loaded = ContinueConstructionAsync();
async Task ContinueConstructionAsync()
{
await InitializeMyGui();
// some more code
}
}
public Task Loaded { get; }
This code also adds a new property that can be awaited if other parts of the code depend on this type being loaded.
Make the constructor private, and use a static factory method to call it and your initialization code. A static method can of course be async.
class MyGui
{
private MyGui()
{
}
private async Task InitializeMyGui()
{
}
static public async Task<MyGui> CreateInstance()
{
var instance = new MyGui();
await instance.InitializeMyGui();
return instance;
}
}
Now you can instantiate an instance using async code:
var myInstance = MyGui.CreateInstance();
On closing of my application I have to do some clean up activity and I have written something like this in ClassA.cs
protected override void OnExit(ExitEventArgs e)
{
Cleanup();
base.OnExit(e);
}
private async Task Cleanup()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (databaseInitialisation != null)
{
await databaseInitialisation.InitialiseDatabase();
}
databaseFile?.Dispose();
}
I have one more class ClassB.cs
public class DatabaseInitialisation : IDatabaseInitialisation
{
private readonly string filterOptimisationPath;
private readonly Task databaseInitialisation;
private IDbConnectionFactory ConnectionFactory { get; }
public async Task InitialiseDatabase() => await databaseInitialisation;
public DatabaseInitialisation(string databaseFilePath, string filterOptimisationPath)
{
this.filterOptimisationPath = filterOptimisationPath;
ConnectionFactory = new SqLiteConnectionFactory(databaseFilePath);
databaseInitialisation = Task.Run(() => CreateDatabase(databaseFilePath));
}
}
so now when I close my application, sometimes when cleanup is called execution of the program going from await is going to onexit method without executing the dispose method
The root of your trouble is that you need to call an async method from a sync method, and you cannot make that method async because it's part of the GUI framework. The general advice here would be to make your calling method async, but since you can't, there are a few ways you can accomplish this:
Option 1 -- Task.Run
Change your OnExit method to launch Cleanup on a thread pool thread and then synchronously wait for that using GetAwaiter().GetResult() to prevent deadlocks. Since this is only running once at shutdown, it should be fine, but launching background threads like this would not be recommended if this were a method that will run often as it could potentially lead to thread pool starvation.
protected override void OnExit(ExitEventArgs e)
{
Task.Run(async () => await Cleanup().ConfigureAwait(false))
.GetAwaiter().GetResult();
base.OnExit(e);
}
Option 2 -- async void and a ManualResetEvent
This approach avoids using .GetAwaiter().GetResult() and launching on a thread pool thread, but any exception thrown in cleanup will cause the application to crash.
protected override void OnExit(ExitEventArgs e)
{
using var signal = new ManualResetEventSlim(false);
Cleanup(signal);
signal.Wait();
base.OnExit(e);
}
private async void Cleanup(ManualResetEventSlim signal)
{
if (databaseInitialisation != null)
{
await databaseInitialisation.InitialiseDatabase();
}
databaseFile?.Dispose();
signal.Set();
}
You could also use one of the Wait overloads to include a timeout.
As a side note, in a GUI application like this, you should really be calling .ConfigureAWait(false) on every task you await that isn't being called directly from a GUI event. Not doing so risks deadlocks.
One caveat to both these solutions is that if your Cleanup method or anything in its call stack, both of these methods will deadlock, and in that case, another solution is needed.
So i have a method that calls methods from another class and is waiting for them to complete before calling another method. The problem i am having is that the method thats being called uses an eventhandler to do actions. Is there a way to delay the return of that method until the eventhandler has done its thing? To clarify, i made an example:
Main class:
class MainClass
{
SomeObject someObject;
private async void MainMethod()
{
someObject = new SomeObject();
await someObject.SomeMethod();
await someObject.SomeOtherMethod();
}
}
SomeObject Class:
class SomeObject
{
public event EventHandler<object> SomethingChanged;
public async Task SomeMethod()
{
Console.WriteLine("fired SomeMethod");
SomethingChanged += SomethingChangedAsync;
Subscribe("<someURL>", SomethingChanged); //this is being done by an api im using...
await api.someApiCall;
Console.WriteLine("here things are happening that would make the event trigger. the method however, is now done with its logic and now returns and instantly goes to SomeOtherMethod but SomethingChangedAsync is not done processing what needs to be done");
}
public async Task SomeOtherMethod()
{
await api.someApiCall;
Console.WriteLine("fired SomeOtherMethod");
}
private async void SomethingChangedAsync(object sender, object e)
{
await api.someApiCall;
Console.WriteLine("doing stuff here that takes some time. i would like SomeMethod to wait with returning until the logic here is finished");
}
}
is there a way i can fix this issue. maybe my approach is completely wrong. i hope someone can help me with this
maybe my approach is completely wrong
Whenever you have the situation where you want to await an async event handler, that's a red flag.
Events are a valid design to use when implementing the Observer design pattern. However, they are sometimes misused as a design when implementing the Strategy or Template Method design patterns. In the synchronous world, you can get away with that kind of substitution - using an event in place of an interface with a single method. But in the asynchronous world, that kind of substitution breaks down.
Another good litmus test is to consider your event and ask "does it really make sense that this has multiple handlers?" If the answer is no, then an event is not the correct design in the first place.
That said, if you really want an "asynchronous event" instead of a more proper interface with an asynchronous method, then there are a couple options. One is to have the event delegate return a Task. You can get the list of handlers manually and invoke each one. You'll just need to decide if you want to start all handlers concurrently or execute them one at a time. (And again, a decision here of "I need to wait them one at a time" is a strong indication that an event is the wrong design choice).
Another option is to use a "deferral", as popularized by UWP. This allows "normal" async void event handlers to be used, as long as they acquire a deferral object. You could do something like this using the DeferralManager from AsyncEx:
public sealed class MyEventArgs : EventArgs, IDeferralSource
{
private readonly IDeferralSource _deferralSource;
public MyEventArgs(IDeferralSource deferralSource)
{
_deferralSource = deferralSource;
}
public IDisposable GetDeferral() => _deferralSource.GetDeferral();
}
public event Action<object, MyEventArgs> MyEvent;
private async Task RaiseEventAsync()
{
var deferralManager = new DeferralManager();
var args = new MyEventArgs(deferralManager.DeferralSource);
MyEvent?.Invoke(this, args);
await deferralManager.WaitForDeferralsAsync();
}
Then any async void handler is expected to acquire a deferral as such:
private async void Handler(object source, MyEventArgs args)
{
using var deferral = args.GetDeferral();
await Task.Yield();
}
I don't know if I am doing something wrong or I found a bug in the Async library, but I have seen an issue when running some async code after I came back to the Synchronized context with continueWith().
UPDATE: The code now runs
using System;
using System.ComponentModel;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
internal static class Program
{
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MainFrameController controller = new MainFrameController(this);
//First async call without continueWith
controller.DoWork();
//Second async call with continueWith
controller.DoAsyncWork();
}
public void Callback(Task<HttpResponseMessage> task)
{
Console.Write(task.Result); //IT WORKS
MainFrameController controller =
new MainFrameController(this);
//third async call
controller.DoWork(); //IT WILL DEADLOCK, since ConfigureAwait(false) in HttpClient DOESN'T change context
}
}
internal class MainFrameController
{
private readonly Form1 form;
public MainFrameController(Form1 form)
{
this.form = form;
}
public void DoAsyncWork()
{
Task<HttpResponseMessage> task = Task<HttpResponseMessage>.Factory.StartNew(() => DoWork());
CallbackWithAsyncResult(task);
}
private void CallbackWithAsyncResult(Task<HttpResponseMessage> asyncPrerequisiteCheck)
{
asyncPrerequisiteCheck.ContinueWith(task =>
form.Callback(task),
TaskScheduler.FromCurrentSynchronizationContext());
}
public HttpResponseMessage DoWork()
{
MyHttpClient myClient = new MyHttpClient();
return myClient.RunAsyncGet().Result;
}
}
internal class MyHttpClient
{
public async Task<HttpResponseMessage> RunAsyncGet()
{
HttpClient client = new HttpClient();
return await client.GetAsync("https://www.google.no").ConfigureAwait(false);
}
}
partial class Form1
{
private IContainer components;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Text = "Form1";
}
#endregion
}
}
The HttpClient code which is async runs well the first time.
Then, I run the second async code and return to the UI context with ContinueWith, and it works well.
I run the HttClient code again, but it deadlock because this time ConfigureAwait(false) does not change the context.
The main problem in your code is due to StartNew and ContinueWith. ContinueWith is dangerous for the same reasons that StartNew is dangerous, as I describe on my blog.
In summary: StartNew and ContinueWith should only be used if you're doing dynamic task-based parallelism (which this code is not).
The actual problem is that HttpClient.GetAsync doesn't use (the equivalent of) ConfigureAwait(false); it's using ContinueWith with its the default scheduler argument (which is TaskScheduler.Current, not TaskScheduler.Default).
To explain in more detail...
The default scheduler for StartNew and ContinueWith is not TaskScheduler.Default (the thread pool); it's TaskScheduler.Current (the current task scheduler). So, in your code, DoAsyncWork as it currently is does not always execute DoWork on the thread pool.
The first time DoAsyncWork is called, it will be called on the UI thread but without a current TaskScheduler. In this case, TaskScheduler.Current is the same as TaskScheduler.Default, and DoWork is called on the thread pool.
Then, CallbackWithAsyncResult invokes Form1.Callback with a TaskScheduler that runs it on the UI thread. So, when Form1.Callback calls DoAsyncWork, it is called on the UI thread with a current TaskScheduler (the UI task scheduler). In this case, TaskScheduler.Current is the UI task scheduler, and DoAsyncWork ends up calling DoWork on the UI thread.
For this reason, you should always specify a TaskScheduler when calling StartNew or ContinueWith.
So, this is a problem. But it's not actually causing the deadlock you're seeing, because ConfigureAwait(false) should allow this code to just block the UI instead of deadlocking.
It's deadlocking because Microsoft made the same mistake. Check out line 198 here: GetContentAsync (which is called by GetAsync) uses ContinueWith without specifying a scheduler. So, it's picking up the TaskScheduler.Current from your code, and will not ever complete its task until it can run on that scheduler (i.e., the UI thread), causing the classic deadlock.
There's nothing you can do to fix the HttpClient.GetAsync bug (obviously). You'll just have to work around it, and the easiest way to do that is to avoid having a TaskScheduler.Current. Ever, if you can.
Here's some general guidelines for asynchronous code:
Don't ever use StartNew. Use Task.Run instead.
Don't ever use ContinueWith. Use await instead.
Don't ever use Result. Use await instead.
If we just do minimal changes (replacing StartNew with Run and ContinueWith with await), then DoAsyncWork always executes DoWork on the thread pool, and the deadlock is avoided (since await uses the SynchronizationContext directly and not a TaskScheduler):
public void DoAsyncWork()
{
Task<HttpResponseMessage> task = Task.Run(() => DoWork());
CallbackWithAsyncResult(task);
}
private async void CallbackWithAsyncResult(Task<HttpResponseMessage> asyncPrerequisiteCheck)
{
try
{
await asyncPrerequisiteCheck;
}
finally
{
form.Callback(asyncPrerequisiteCheck);
}
}
However, it's always questionable to have a callback scenario with Task-based asynchrony, because Tasks themselves have the power of callbacks within them. It looks like you're trying to do a sort of asynchronous initialization; I have a blog post on asynchronous construction that shows a few possible approaches.
Even something really basic like this would be a better design than callbacks (again, IMO), even though it uses async void for initialization:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MainFrameController controller = new MainFrameController();
controller.DoWork();
Callback(controller.DoAsyncWork());
}
private async void Callback(Task<HttpResponseMessage> task)
{
await task;
Console.Write(task.Result);
MainFrameController controller = new MainFrameController();
controller.DoWork();
}
}
internal class MainFrameController
{
public Task<HttpResponseMessage> DoAsyncWork()
{
return Task.Run(() => DoWork());
}
public HttpResponseMessage DoWork()
{
MyHttpClient myClient = new MyHttpClient();
var task = myClient.RunAsyncGet();
return task.Result;
}
}
Of course, there's other design problems here: namely, DoWork is blocking on a naturally-asynchronous operation, and DoAsyncWork is blocking a thread pool thread on a naturally-asynchronous operation. So, when Form1 calls DoAsyncWork, it's awaiting a thread pool task that's blocked on an asynchronous operation. Async-over-sync-over-async, that is. You may also benefit from my blog series on Task.Run etiquette.
Don't use .Result. If you have any code at all that uses async/await, just completely forget it even exists. Even if we get it working today, what you are trying to do will be so incredibly brittle that it won't necessarily work tomorrow.