Async void on subscribed Prism methods - c#

I understand you should try not to do async void with the exception of event handlers. Does that exception of event handlers include Prism events? Is my example below ok to do?
Module A's View has a DataGrid and when the user clicks a record it publishes the SelectionChangedEvent, the event is subscribed in Module B and might take a while to complete.
public class ModuleA
{
private ObservableCollection<Company> carCollectionOC = new ObservableCollection<Company>();
private void CarCollection_CurrentChanged(object sender, EventArgs e)
{
Company company = (Company)(sender as ICollectionView).CurrentItem;
this.eventAggregator.GetEvent<SelectionChangedEvent>().Publish(company.Brand);
}
}
Module B subscribes and does async void.
public class ModuleB
{
private ObservableCollection<Vehicle> vehicleOC = new ObservableCollection<Vehicle>();
private VehicleService vehicleService;
public ModuleB(IEventAggregator eventAggregator)
{
this.vehicleService = new VehicleService();
this.eventAggregator.GetEvent<SelectionChangedEvent>()
.Subscribe(this.SubscribedMethod,
ThreadOption.UIThread,
false);
}
private async void SubscribedMethod (string brand)
{
this.vehicleOC = await this.GetData(brand);
}
private List<Vehicle> GetVehicles(string carBrand)
{
Console.WriteLine("finishing GetVehicles");
return this.vehicleService.GetVehicleList(carBrand);
}
private async Task<ObservableCollection<Vehicle>> GetData(string carBrand)
{
vehicleListFromService = await Task.Run(() => this.GetVehicles(carBrand));
this.vehicleOC.Clear();
foreach (var vehicle in vehicleListFromService)
this.vehicleOC.Add(vehicle);
return this.vehicleOC;
}
}

Certainly, even stephen clearly (an authority on this subject as far as i am concerned) says:
To summarize this first guideline, you should prefer async Task to
async void. Async Task methods enable easier error-handling,
composability and testability. The exception to this guideline is
asynchronous event handlers, which must return void. This exception
includes methods that are logically event handlers even if they’re not
literally event handlers (for example, ICommand.Execute
implementations).
https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
Personally, I always wrap the contents of an async void method in a try-catch and deal with the exception, regardless of the method's contents. I've written a simple helper class to aid with that.

Does that exception of event handlers include Prism events?
Yes. The subscriber has to be Action, that means void MyHandler() (or async void MyHandler()).

Related

Proper way to have a list of sync or async methods called in a safe manner

I have a use case where I made an EventManager class that essentially have two methods. One takes a method pointer in the form of an Action<eventType> to register that method pointer as one of many handlers for eventType. I pass both "normal" methods and async methods to this.
The other takes an instance of an eventType as a signal to raise that event and call all the previously registered handlers.
When an event is raised, I call all the handlers based on their methodInfo and invoke them one by one. I do not await any of them, and treat all the same, even though some are sync and some are async, and that all works well... or so it seemed for a long time.
While I have extensively used the async pattern, there are apparently still details which can kick me in the head at times, and things I am simply unaware of, and I have for a while had issues with random uncaught exceptions, which I am pretty sure comes from this implementation.
After seeking some more advice on good and bad async here, I have redesigned so I can pass either an Action<eventType> or a Func<Task, eventType>, and store it as methodInfo so I can later properly invoke and await the call when it is an async method.
I made a proof of concept, which seems to work correctly, before making sweeping changes in the live project, and would like if someone with more async insight than myself could comment on this. Is this in fact proper and safe now, or am I just headed into a whole other set of problems?
It is a very simplified test case demonstrating the core of my new system. Somewhere you call the eventManager to register a method to handle some event and elsewhere someone else calls the eventManager to raise the event, and the manager calls all relevant handlers while trying to await the async ones. All is running main thread.
In this example, all of this is represented by the Test() method.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
namespace test
{
public static class ext
{
public static async Task InvokeAsync(this MethodInfo #this, object obj, params object[] parameters)
{
dynamic awaitable = #this.Invoke(obj, parameters);
if (awaitable!=null) await awaitable;
}
}
internal class Program
{
static void Main(string[] args)
{
Test(); //what is the proper way to start´this async chain from a non async method?
Console.ReadKey();
}
//a description of an event handler containing the method and object to handle it
private struct RegistredEventHandler
{
public object HandlerObject;
public MethodInfo HandlerMethod;
}
//list of all registered handlers
private static List<RegistredEventHandler> handlerList = new List<RegistredEventHandler>();
//first async method in the chain doing both the registering and the raising of events as a simple test
private static async Task Test()
{
//register an event handler for both the async and the serial method
Func<int, Task> asyncFunc = TestAsync;
var hAsync = new RegistredEventHandler()
{
HandlerObject = asyncFunc.Target,
HandlerMethod = asyncFunc.Method
};
handlerList.Add(hAsync);
Action<int> serialAction = TestSerial;
var hSerial = new RegistredEventHandler()
{
HandlerObject = serialAction.Target,
HandlerMethod = serialAction.Method
};
handlerList.Add(hSerial);
//try invoking and awating both handlers
foreach (var eventHandler in handlerList)
{
await eventHandler.HandlerMethod.InvokeAsync(eventHandler.HandlerObject, new object[] { 10});
}
}
static void TestSerial(int i)
{
Console.WriteLine($"Serial argument {i}");
}
static async Task TestAsync(int i)
{
await Task.Delay(5000);
Console.WriteLine($"Async argument {i}");
}
}

Capture traditional events and report them using IProgress<T>

Suppose I have the following legacy service:
public interface ISomeService
{
event EventHandler<SomeEventArgs> SomethingHappened;
void MakeSomethingHappen();
}
Now I have another service that relies on the one above, but uses async reporting, as follows:
public class OtherService : IOtherService
{
public async Task DoSomethingElse(IProgress<SomeEventArgs> progress)
{
// ...
}
}
I need to capture the events triggered in ISomeService and report them in OtherService using IProgress<T>. My solution to this was:
public async Task DoSomethingElse(IProgress<SomeEventArgs> progress)
{
void handleEvent(object sender, SomeEventArgs e)
{
if (progress != null)
progress.Report(e);
}
_someService.SomethingHappened += progressHandler;
try
{
_someService.MakeSomethingHappen();
}
finally
{
_someService.SomethingHappened -= progressHandler;
}
}
Are there any dangers/problems with this?
No, there is no problem with consuming an event by a Progress<T> object. The only problem would be a possible memory leak in case you forgot to unsubscribe from the event, but your code takes care of that.
I would also like to point out that if you want to get fancy you could do the same thing in a reactive way, by using an IObservable<SomeEventArgs> as an intermediate propagator:
public async Task DoSomethingElse(IProgress<SomeEventArgs> progress)
{
using var subscription = Observable
.FromEventPattern<SomeEventArgs>(
h => _someService.SomethingHappened += h,
h => _someService.SomethingHappened -= h)
.Select(ep => ep.EventArgs)
.Subscribe(progress.ToObserver());
await Task.Run(() =>
{
_someService.MakeSomethingHappen();
});
}
The FromEventPattern, Select and ToObserver are extension methods defined in the System.Reactive package.
Is there a reason you're avoiding Lambda functions? I can't think of any immediate problem with this solution (aside from binding the event to a local handler which may keep the parent in memory even when "MakeSomethingHappen" results in "_someService" own demise).
Still, for the sake of readability, I would go with Lambda handler...

Listen for event and invoke callback, based on specification?

I am currently building out a custom task manager and I'm wondering if it's possible to tell the task manager to listen for a specific event (OnSomething below), and then invoke a callback method when the task raises that event. However, mentally I can't see how it's possible to listen for an event that doesn't exist at the base class level. For example, I have a base class that contains basic information about the task called CustomTask:
public abstract class CustomTask {
public bool IsRunning { get; private set; } = false;
public void Start() {
IsRunning = true;
DoSomething();
IsRunning = false;
}
protected abstract void DoSomething();
}
For the sake of SO readers, I've simplified the definition, but you get the gist of it. It contains basic details, a few methods for starting and canceling, provides basic state management (simplified IsRunning here), etc.
I then have custom tasks that derive from CustomTask, in this case, let's focus on a sample task called CustomTaskA. It contains a definition for an event called OnSomething, which someone, somewhere may want to listen for:
public sealed class CustomTaskA : CustomTask {
protected override void DoSomething() => RaiseOnSomething(this, new EventArgs());
public event EventHandler<EventArgs> OnSomething;
private void RaiseOnSomething(object sender, EventArgs e) => OnSomething?.Invoke(sender, e);
}
Now, the CustomTaskManager registers tasks, tracks them via Guid, manages them and more, but for simplicity:
public sealed class CustomTaskManager {
// Singleton setup.
private static CustomTaskManager _instance = new CustomTaskManager();
public static CustomTaskManager Instance {
get {
// Simplified for SO.
if (_instance == null)
_instance = new CustomTaskManager();
return;
}
}
// Collection of tasks.
private Dictionary<Guid, CustomTask> _tasks = new Dictionary<Guid, CustomTask>();
// Register and start a task.
public bool TryRegisterAndStartTask(CustomTask task, out Guid taskId) {
taskId = Guid.Empty;
try {
// Register task.
taskId = Guid.NewGuid();
_tasks.Add(taskId, task);
// Listen for events.
// Start task.
task.Start();
} catch (Exception e) {
// Log exception.
}
return false;
}
}
When registering and starting a task, I'd like to tell the task manager I want to listen for OnSomething, and if OnSomething is invoked, I want the task manager to call a method OnSomethingWasRaised. For example:
TaskManager.Instance.TryRegisterAndStartTask(task, out Guid taskId, task.OnSomething, OnSomethingWasRaised);
private static void OnSomethingWasRaised(object sender, EventArgs e) {
Console.WriteLine("Woohoo!");
}
I know the specifying and invoking a callback method is entirely possible, and listening for events is plausible with reflection.
Is there a way (with or without using reflection) to listen for a specified event defined on a derived object and then invoke a specified callback method?
NOTE: Please excuse any syntactical errors as I hand-typed the snippets to keep them minimal.
Problem with (proposed) approach like this:
TryRegisterAndStartTask(task, out Guid taskId, task.OnSomething, OnSomethingWasRaised);
is that you cannot pass event as argument, or store it in variable, because event is just a set of two methods (add and remove), just like property is a set of two methods get and set.
You can of course change event to "raw" delegate:
public EventHandler<EventArgs> OnSomething;
This one you can pass by reference:
public bool TryRegisterAndStartTask(CustomTask task, ref EventHandler<EventArgs> del, EventHandler<EventArgs> sub, out Guid taskId) {
taskId = Guid.Empty;
// subscribe
del += sub;
...
}
CustomTaskManager.Instance.TryRegisterAndStartTask(task, ref task.OnSomething, OnSomethingWasRaised, out var taskId);
But that's usually not a good idea, since you are losing private scope of events - with events one can only add\remove delegates, with raw delegate anyone can do anything, like invoking or setting to null.
If regular event stays - that means reflection is the only way to achieve your goal, and even worse - you'll have to reference to the event you want to subscribe to by string name, not by an actual reference, though you can use nameof(task.OnSomething). Then, you are losing compile time validation of subscription delegate type. Say you want to subscribe to event Action Something but passing Func<string> delegate there. It will compile fine with reflection approach, and fail only at runtime.
Still if you insist that will look something like this:
public bool TryRegisterAndStartTask(CustomTask task, string eventName, Delegate sub, out Guid taskId) {
taskId = Guid.Empty;
// subscribe
var ev = task.GetType().GetEvent(eventName, BindingFlags.Public | BindingFlags.Instance);
var addMethod = ev.GetAddMethod(); // this can be null or private by the way
addMethod.Invoke(task, new [] {sub});
...
}
And called like this:
var task = new CustomTaskA();
EventHandler<EventArgs> handler = OnSomethingWasRaised;
CustomTaskManager.Instance.TryRegisterAndStartTask(task, nameof(task.OnSomething), handler, out var taskId);
Ugly, unsafe, and not worth it in your scenario, in my opinion.

How to call async method from PropertyChanged?

I have an WPF application based on MVVM architecture. I am implementing the common and widely used INotifyPropertyChanged interface on my ViewModels, because I need to react on user interaction.
But how do I perform an asynchronous action (e.g. loading some data) from within the synchronous PropertyChanged event handler without using async void 'hacks'?
Thanks in advance!
EDIT
The main reason why i need to avoid async void is because I am working in an test driven environment. Async void methods are not testable :(
Actually, this is not about async void.
Usually you want to fire async operation and let your property setter return.
Sample snippet:
private string carManufacturerFilter;
public string СarManufacturerFilter
{
get { return carManufacturerFilter; }
set
{
if (carManufacturerFilter != value)
{
carManufacturerFilter = value;
OnPropertyChanged();
// fire async operation and forget about it here;
// you don't need it to complete right now;
var _ = RefreshCarsListAsync();
}
}
}
private async Task RefreshCarsListAsync()
{
// call some data service
var cars = await someDataService.GetCarsAsync(carManufacturerFilter)
.ConfigureAwait(false);
// ...
}
Note, that there are a lot of things to add here:
since this is fire-and-forget approach, you need to block user input until operation is running. In other words, there should be some sort of busy indicator;
you may want to delay async operation firing. This is usually applicable, when there are string properties. You don't want to fire async operation after each char typed by user. Instead it's desirable to wait user to complete input;
there could be several properties, which fire the same async operation (imagine complex data filter). Some of them should fire operation immediately (e.g. checkbox), some of them need delay before firing;
you need to handle exceptions inside async method and display errors somehow.
P.S. I strongly recommend you to take a look at Reactive UI.
The reason async void is supported is to allow using await in event handlers, which are usually void.
If you want it to be testable, write the entire code in another async Task method and have the event handler call it directly. Test this method in your tests.
void OnPropertyChanged(PropertyChangedEventArgs e)
{
OnPropertyChangedAsync(e)
}
// Test this method
async Task OnPropertyChangedAsync(PropertyChangedEventArgs e)
{
...
}
Little late to the party but I'd say this. First, notice that INotifyPropertyChanged says that your view model will implement
public event PropertyChangedEventHandler? PropertyChanged;
Secondly, if you inspect PropertyChangedEventHandler, you'll see that it's a delegate, of course:
public delegate void PropertyChangedEventHandler(object? sender, PropertyChangedEventArgs e);
So why not implement your own delegate using Func<>? For example, if you're looking to stick with the (object? sender, PropertyChangedEventArgs e) parameter pattern that PropertyChanged uses, then I would implement something like
public Func<object?, PropertyChangedEventArgs, Task>? PropertyChangedAsync { get; set; }
in the same place (or in place of) public event PropertyChangedEventHandler? PropertyChanged;.
From there you can "wire it up" just as you would PropertyChanged:
ViewModel.PropertyChanged += OnViewModelPropertyChanged;
ViewModel.PropertyChangedAsync += OnViewModelPropertyChangedAsync;
private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Do something (synchronously) with the notification
}
private Task OnViewModelPropertyChangedAsync(object? sender, PropertyChangedEventArgs e)
{
// Do something (asynchronously) with the notification
return Task.CompletedTask;
}
By the way, if you really want to get fancy, you could also create a custom PropertyChangedEventHandler event with an interface very similar to INotifyPropertyChanged. Obviously, the only difference is you'd want to return Task or Task<T> instead of void. The solution that I mentioned above using Func<object?, PropertyChangedEventArgs, Task> is just a lot more concise (one line).
You can't. INotifyPropertyChanged doesn't support async calls. You need to do a hack, or rethink you strategy.
INotifyPropertyChanged is not intended for async actions. Its goal is to enable a class notify the UI that its data has changed. The UI works in a dedicated thread, so cross-thread operations must be avoided.
You should use the "dreaded" async void approach.
You can also use Dispatcher.BeingInvoke (async () => { … await …} ), but it will be the same as using async void.

async/await in MVVM without Void methods

I want to use async/await on my windows phone 8 MVVM project and I'm struggling to find a good way to implement my ICommands using this api.
I've been reading a few articles about the subject and I bumped into this one from MSDN below, which states that I have to avoid async voids since it gets difficult to catch unhandled exceptions:
http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
In another question I asked about the subject, someone also said that I shouldn't use async voids. Unless with events.
But the problem is that all examples I can find on the internet use async voids.
This two articles I found are examples:
http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/ and
http://blog.mycupof.net/2012/08/23/mvvm-asyncdelegatecommand-what-asyncawait-can-do-for-uidevelopment/
The last one is an implementation of ICommand using async/await, but it also uses async voids.
I'm trying to come up with a solution for this, so I wrote this implementation of ICommand based on the RelayCommand:
public delegate Task AsyncAction();
public class RelayCommandAsync : ICommand
{
private AsyncAction _handler;
public RelayCommandAsync(AsyncAction handler)
{
_handler = handler;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (value != _isEnabled)
{
_isEnabled = value;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
ExecuteAsync();
}
private Task ExecuteAsync()
{
return _handler();
}
}
And I'm trying to use it like this:
in the constructor:
saveCommand = new RelayCommandAsync(SaveSourceAsync);
then:
private async Task SaveSourceAsync()
{
await Task.Run(() => { Save(); });
}
private void Save()
{
// Slow operation
}
The problem is that I'm not feeling comfortable with this and any other implementation as I don't know which is the best and optimal.
Can anyone give some light on how I should use it, preferably with MVVM?
In the referenced article, I did point out that ICommand.Execute is practically an event handler, so it would be considered an exception from the "avoid async void" guideline:
To summarize this first guideline, you should prefer async Task to async void... The exception to this guideline is asynchronous event handlers, which must return void. This exception includes methods that are logically event handlers even if they’re not literally event handlers (for example, ICommand.Execute implementations).
Regarding your ICommand implementation, it actually introduces a flaw by not using async void: the ICommand.Execute implementation will discard the Task without observing its exceptions. So that implementation will ignore any exceptions raised by the async delegate.
In contrast, the blog post you linked to has an async void ICommand.Execute which awaits the Task, allowing the exception to propagate to the UI synchronization context. Which - in this case - is the desired behavior because it's the same behavior you get when a synchronous ICommand.Execute raises an exception.
If you have the inclination, I'd like you to try out an ICommand or two that I've written for possible future inclusion in my AsyncEx library. The first one is a simple command very similar to the one in the blog you posted. The second one is a much more complete "asynchronous command" implementation including cancellation, progress reporting, and automatic management of CanExecute. I'd appreciate any feedback.

Categories