Automated test for a async Command in MVVM - c#

I have an asynchronous Command class, like so:
public AsyncDelegateCommand(Func<Task> execute, Func<bool> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
}
public virtual bool CanExecute(object parameter)
{
if(executing)
return false;
if(canExecute == null)
return true;
return canExecute();
}
public async void Execute(object parameter) // Notice "async void"
{
executing = true;
CommandManager.InvalidateRequerySuggested();
if(parameter != null && executeWithParameter != null)
await executeWithParameter(parameter);
else if(execute != null)
await execute();
executing = false;
CommandManager.InvalidateRequerySuggested();
}
And it is called like so:
FindProductCommand = new AsyncDelegateCommand(TryToFindProduct, () => CanFindProduct() && connector.HasConnection);
private async Task TryToFindProduct()
{
//code
}
When I unit tests, it works just fine, since I'm returning instantly from tasks.
However, when writing my integration test, I run into trouble. I am not able to await Execute, since it is void, and I am not able to change it to Task. I end up doing this: :/
findProductViewModel.FindProductCommand.Execute(null);
Thread.Sleep(2000);
var informationViewModel = findProductViewModel.ProductViewModel.ProductInformationViewModel;
Assert.AreEqual("AFG00", informationViewModel.ProductGroup);
Is there a better solution for this test? Maybe something that is reliant on how long it actually takes, and doesn't estimate how long to wait.

You can refer to a good blog post by #StephenCleary: https://msdn.microsoft.com/en-us/magazine/dn630647.aspx
async void is generally to be avoided, so he introduces a new interface (and its base implementation) for an async command: IAsyncCommand. This interface contains a method async Task ExecuteAsync(object parameter) that you could await in your tests.
public interface IAsyncCommand : ICommand
{
Task ExecuteAsync(object parameter);
}
public abstract class AsyncCommandBase : IAsyncCommand
{
public abstract bool CanExecute(object parameter);
public abstract Task ExecuteAsync(object parameter);
public async void Execute(object parameter)
{
await ExecuteAsync(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
protected void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
The simplest implementation of such an async command would look like this:
public class AsyncCommand : AsyncCommandBase
{
private readonly Func<Task> _command;
public AsyncCommand(Func<Task> command)
{
_command = command;
}
public override bool CanExecute(object parameter)
{
return true;
}
public override Task ExecuteAsync(object parameter)
{
return _command();
}
}
But there are more advanced variants that you can find in the linked blog post. You can use the IAsyncCommands in your code all the way, so you can test them. The MVVM framework you use will also be happy, because that interface is based on the ICommand.

Is there a better solution for this test? Maybe something that is reliant on how long it actually takes, and doesn't estimate how long to wait.
Certainly: Make the command awaitable and await it. async void methods are bad practice and are only meant to be used for event handlers.
There are awaitable commands available in Mvvm.Async and ReactiveUI that you can use or at least take a look at for reference.

If you have a state to check for, you should probably just use SpinWait.SpinUntil:
It will be much more reliable than Thread.Sleepas it allows you to check if a condition is true before continuing.
e.g.
findProductViewModel.FindProductCommand.Execute(null);
SpinWait.SpinUntil(() => findProductViewModel.ProductViewModel.ProductInformationViewModel != null, 5000);
var informationViewModel = findProductViewModel.ProductViewModel.ProductInformationViewModel;
Assert.AreEqual("AFG00", informationViewModel.ProductGroup);

Related

Populate ObservableCollection with data from awaited Task.Run

I am making Xamarin application and I have a problem with display data in my list view. So, basically I have web service from where I fetch data (that endpoint is non-async), so I don't want to block UI thread of my application, so I wrap the call to web service in Task.Run and await that task.
public class HomeDetailPageViewModel : ViewModelNavigatable
{
public ObservableCollection<CarViewModel> cars;
public ObservableCollection<CarViewModel> Cars
{
get { return this.cars; }
}
public HomeDetailPageViewModel(INavigationService navigationService)
:base(navigationService)
{
this.cars = new ObservableCollection<CarViewModel>();
AppearingCommand = new AsyncCommand(this.OnAppearingCommandExecuted);
}
public IAsyncCommand AppearingCommand { get; set; }
public async Task OnAppearingCommandExecuted()
{
using (UserDialogs.Instance.Loading("Loading..."))
{
this.Cars.Clear();
IEnumerable<Car> carsFromEndpoint = await Task.Run(() => CarEndpoint.GetAll(client.Context)).ConfigureAwait(false);
Device.BeginInvokeOnMainThread(() =>
{
foreach (var carFromEndpoint in carsFromEndpoint.ToList())
this.Cars.Add(new CarViewModel
{
Manufacturer = carFromEndpoint.Code,
Model = carFromEndpoint.Name,
Price = carFromEndpoint.Price,
Year = carFromEndpoint.Year
});
});
}
}
}
As I said CarEndpoint.GetAll(client.Context) is synchronous endpoint. If I use:
Task.Run(() => CarEndpoint.GetAll(client.Context)).Result or
CarEndpoint.GetAll(client.Context)
everything works as expected but that is not acceptable because it's block UI thread until Task is finished. I know it is not a good idea to use Task.Run to make fake asynchronous calls, but I don't see another way to keep app responsive, because I cannot change the endpoint of web service.
Thank you for the answer.
Cheers :)
I know it is not a good idea to use Task.Run to make fake asynchronous calls
Using Task.Run to unblock a UI thread - even in a fake-asynchronous way - is fine.
I cannot change the endpoint of web service.
This sentence doesn't make as much sense. All web services are asynchronous by nature. However, it's possible that your client-side library is strictly synchronous, in which case Task.Run is a fine way to unblock the UI while calling it. But you'll be working around a limitation in the client-side library, not the web service itself.
I have a problem with display data in my list view.
Your problem is likely due to the IEnumerable<T>, not Task.Run. Here's some code I expect would work; the key is to move the ToList inside the Task.Run delegate:
public async Task OnAppearingCommandExecuted()
{
using (UserDialogs.Instance.Loading("Loading..."))
{
this.Cars.Clear();
List<Car> carsFromEndpoint = await Task.Run(() => CarEndpoint.GetAll(client.Context).ToList());
foreach (var carFromEndpoint in carsFromEndpoint)
this.Cars.Add(new CarViewModel
{
Manufacturer = carFromEndpoint.Code,
Model = carFromEndpoint.Name,
Price = carFromEndpoint.Price,
Year = carFromEndpoint.Year
});
}
}
Notes:
BeginInvokeOnMainThread is unnecessary if you remove the ConfigureAwait(false); the await resumes on the UI thread for us. In fact, BeginInvokeOnMainThread is a code smell.
You probably don't want an asynchronous command here; you just want to asynchronously load data.
When you're using Async commands in MVVM, the main problem is NotSupportedException while modifying the ObservableCollection. All the rest don't cause any issues if you're careful with concurrency.
Here's a class representing ObservableCollection for use from multiple threads which forwards all actions to SynchronizationsContext of the Thread where it was constructed.
Just use it instead of ObservableCollection (not mine, grabbed from GitHub)
public class AsyncObservableCollection<T> : ObservableCollection<T>
{
private readonly SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
public AsyncObservableCollection() : base() { }
public AsyncObservableCollection(IEnumerable<T> collection) : base(collection) { }
public AsyncObservableCollection(List<T> list) : base(list) { }
private void ExecuteOnSyncContext(Action action)
{
if (SynchronizationContext.Current == _synchronizationContext)
action();
else
_synchronizationContext.Send(_ => action(), null);
}
protected override void InsertItem(int index, T item) => ExecuteOnSyncContext(() => base.InsertItem(index, item));
protected override void RemoveItem(int index) => ExecuteOnSyncContext(() => base.RemoveItem(index));
protected override void SetItem(int index, T item) => ExecuteOnSyncContext(() => base.SetItem(index, item));
protected override void MoveItem(int oldIndex, int newIndex) => ExecuteOnSyncContext(() => base.MoveItem(oldIndex, newIndex));
protected override void ClearItems() => ExecuteOnSyncContext(() => base.ClearItems());
}
And this AsyncRelayCommand class that I've made with help on StackOverflow (Russian Community). It doesn't freeze anything.
public interface IAsyncCommand : ICommand
{
Task ExecuteAsync(object param);
}
public class AsyncRelayCommand : IAsyncCommand
{
private bool _isExecuting;
private readonly SynchronizationContext _context;
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public AsyncRelayCommand(Action<object> execute, Predicate<object> canExecute = null)
=> (_execute, _canExecute, _context) = (execute, canExecute, SynchronizationContext.Current);
private void InvalidateRequerySuggested()
{
if (_context.Equals(SynchronizationContext.Current))
CommandManager.InvalidateRequerySuggested();
else
_context.Send(_ => CommandManager.InvalidateRequerySuggested(), null);
}
public bool CanExecute(object parameter) => !_isExecuting && (_canExecute == null || _canExecute(parameter));
public async Task ExecuteAsync(object parameter)
{
if (CanExecute(parameter))
{
try
{
_isExecuting = true;
InvalidateRequerySuggested();
await Task.Run(() => _execute(parameter));
}
finally
{
_isExecuting = false;
InvalidateRequerySuggested();
}
}
}
public void Execute(object parameter) => _ = ExecuteAsync(parameter);
}
Usage as with regular RelayCommand class from this article.
private IAsyncCommand _myAsyncCommand;
// "lazy" instantiation with single instance
public IAsyncCommand MyAsyncCommand => _myAsyncCommand ?? (_myAsyncCommand = new AsyncRelayCommand(parameter =>
{
}));
<Button Content="Click me!" Command="{Binding MyAsyncCommand}" />
CommandParameter is also supported.
With this you don't need pushing collecton change calls into UI Thread, use it as in usual sync code. And Thread.Sleep() or heavy job in the command will not freeze UI because it will run on a separate thread.
Usage with your code
private IAsyncCommand _appearingCommand;
public AsyncObservableCollection<CarViewModel> cars; // are you sure that it must be public?
public HomeDetailPageViewModel(INavigationService navigationService)
:base(navigationService)
{
this.cars = new AsyncObservableCollection<CarViewModel>();
}
public AsyncObservableCollection<CarViewModel> Cars
{
get => this.cars;
}
public IAsyncCommand AppearingCommand => _appearingCommand ?? (_appearingCommand = new AsyncRelayCommand(parameter =>
{
// edit: fixed regarding to the accepted answer
List<Car> carsFromEndpoint = CarEndpoint.GetAll(client.Context).ToList();
foreach (var carFromEndpoint in carsFromEndpoint)
this.Cars.Add(new CarViewModel
{
Manufacturer = carFromEndpoint.Code,
Model = carFromEndpoint.Name,
Price = carFromEndpoint.Price,
Year = carFromEndpoint.Year
});
}));

.net core - Passing an unknown number of IProgress<T> to class library

I have a console app which uses a class library to execute some long running tasks. This is a .net core console app and uses the .net core Generic Host. I also use the ShellProgressBar library to display some progress bars.
My Hosted service looks like this
internal class MyHostedService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private readonly IMyService _myService;
private readonly IProgress<MyCustomProgress> _progress;
private readonly IApplicationLifetime _appLifetime;
private readonly ProgressBar _progressBar;
private readonly IProgressBarFactory _progressBarFactory;
public MyHostedService(
ILogger<MyHostedService> logger,
IMyService myService,
IProgressBarFactory progressBarFactory,
IApplicationLifetime appLifetime)
{
_logger = logger;
_myService = myService;
_appLifetime = appLifetime;
_progressBarFactory = progressBarFactory;
_progressBar = _progressBarFactory.GetProgressBar(); // this just returns an instance of ShellProgressBar
_progress = new Progress<MyCustomProgress>(progress =>
{
_progressBar.Tick(progress.Current);
});
}
public void Dispose()
{
_progressBar.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_myService.RunJobs(_progress);
_appLifetime.StopApplication();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Where MyCustomProgress looks like this
public class MyCustomProgress
{
public int Current {get; set;}
public int Total {get; set;}
}
and MyService looks something like so (Job1, Job2, Job3 implement IJob)
public class MyService : IMyService
{
private void List<IJob> _jobsToRun;
public MyService()
{
_jobsToRun.Add(new Job1());
_jobsToRun.Add(new Job2());
_jobsToRun.Add(new Job3());
}
public void RunJobs(IProgress<MyCustomProgress> progress)
{
_jobsToRun.ForEach(job =>
{
job.Execute();
progress.Report(new MyCustomProgress { Current = _jobsToRun.IndexOf(job) + 1, Total = _jobsToRun.Count() });
});
}
}
And IJob is
public interface IJob
{
void Execute();
}
This setup works well and I'm able to display the progress bar from my HostedService by creating a ShellProgressBar instance and using the one IProgress instance I have to update it.
However, I have another implementation of IMyService that I also need to run that looks something like this
public class MyService2 : IMyService
{
private void List<IJob> _sequentialJobsToRun;
private void List<IJob> _parallelJobsToRun;
public MyService()
{
_sequentialJobsToRun.Add(new Job1());
_sequentialJobsToRun.Add(new Job2());
_sequentialJobsToRun.Add(new Job3());
_parallelJobsToRun.Add(new Job4());
_parallelJobsToRun.Add(new Job5());
_parallelJobsToRun.Add(new Job6());
}
public void RunJobs(IProgress<MyCustomProgress> progress)
{
_sequentialJobsToRun.ForEach(job =>
{
job.Execute();
progress.Report(new MyCustomProgress { Current = _jobsToRun.IndexOf(job) + 1, Total = _jobsToRun.Count() });
});
Parallel.ForEach(_parallelJobsToRun, job =>
{
job.Execute();
// Report progress here
});
}
}
This is the one I'm struggling with. when _parallelJobsToRun is executed, I need to be able to create a new child ShellProgressBar (ShellProgressBar.Spawn) and display them as child progress bars of let's say 'Parallel Jobs'.
This is where I'm looking for some help as to how I can achieve this.
Note: I don't want to take a dependency on ShellProgressBar in my class library containing MyService
Any help much appreciated.
I am a little confused by your description, but let's see if I understand what you are up to. So if you wrap all of this in a class, then taskList1 and taskList2 could be class variables. (By the way taskList1/2 should be named better: say parallelTaskList and whatever . . . anyway.) Then you could write a new method on the class CheckTaskStatus() and just iterate over the two class variables. Does that help or have I completely missed your question?
Can you modify it like this?
public Task<ICollection<IProgress<int>>> StartAsync(CancellationToken cancellationToken)
{
var progressList = _myServiceFromLibrary.RunTasks();
return Task.FromResult(progressList);
}
public ICollection<IProgress<int>> RunTasks()
{
var taskList1 = new List<ITask> { Task1, Task2 };
var plist1 = taskList1.Select(t => t.Progress).ToList();
var taskList2 = new List<ITask> { Task3, Task4, Task5 }:
var plist2 = taskList2.Select(t => t.Progress).ToList();
taskList1.foreach( task => task.Run() );
Parallel.Foreach(taskList2, task => { task.Run() });
return plist1.Concat(plist2).ToList();
}
Task.Progress there is probably a progress getter. realistically IProgress should probably be injected via Tasks constructors. But the point is your public interface doesn't accept list of tasks, thus it should just return collection of progress reports.
How to inject progress reporters into your tasks is a different story that depends on tasks implementations and it may or may not be supported. out of the box.
However what you probably should do is to supply progress callback or progress factory so that progress reporters of your choice are created:
public Task StartAsync(CancellationToken cancellationToken, Action<Task,int> onprogress)
{
_myServiceFromLibrary.RunTasks(onprogress);
return Task.CompletedTask;
}
public class SimpleProgress : IProgress<int>
{
private readonly Task task;
private readonly Action<Task,int> action;
public SimpleProgress(Task task, Action<Task,int> action)
{
this.task = task;
this.action = action;
}
public void Report(int progress)
{
action(task, progress);
}
}
public ICollection<IProgress<int>> RunTasks(Action<Task,int> onprogress)
{
var taskList1 = new List<ITask> { Task1, Task2 };
taskList1.foreach(t => t.Progress = new SimpleProgress(t, onprogress));
var taskList2 = new List<ITask> { Task3, Task4, Task5 }:
taskList2.foreach(t => t.Progress = new SimpleProgress(t, onprogress));
taskList1.foreach( task => task.Run() );
Parallel.Foreach(taskList2, task => { task.Run() });
}
you may see here, that it really is mostly question about how your tasks are going to call IProgress<T>.Report(T value) method.
Honestly I would just use an event in your task prototype.
It's not really clear exactly what you want because the code you posted doesn't match the names you then reference in your question text... It would be helpful to have all the code (the RunTasks function for example, your IProgress prototype, etc).
Nevertheless, an event exists specifically to signal calling code. Let's go back to the basics. Let's say you have library called MyLib, with a method DoThings().
Create a new class that inherits from EventArgs, and that will carry your task's progress reports...
public class ProgressEventArgs : EventArgs
{
private int _taskId;
private int _percent;
private string _message;
public int TaskId => _taskId;
public int Percent => _percent;
public string Message => _message;
public ProgressEventArgs(int taskId, int percent, string message)
{
_taskId = taskId;
_percent = percent;
_message = message;
}
}
Then on your library's class definition, add an event like so:
public event EventHandler<ProgressEventArgs> Progress;
And in your console application, create a handler for progress events:
void ProgressHandler(object sender, ProgressEventArgs e)
{
// Do whatever you want with your progress report here, all your
// info is in the e variable
}
And subscribe to your class library's event:
var lib = new MyLib();
lib.Progress += ProgressHandler;
lib.DoThings();
When you are done, unsubscribe from the event:
lib.Progress -= ProgressHandler;
In your class library, now you can send back progress reports by raising the event in your code. First create a stub method to invoke the event:
protected virtual void OnProgress(ProgressEventArgs e)
{
var handler = Progress;
if (handler != null)
{
handler(this, e);
}
}
And then add this to your task's code where you want it:
OnProgress(new ProgressEventArgs(2452343, 10, "Reindexing google..."));
The only thing to be careful about is to report progress sparingly, because each time your event fires it interrupts your console application, and you can really bog it down hard if you send 10 million events all at once. Be logical about it.
Alternate way; If you own the code IProgress<T> and Progress
IProgress<T>
{
IProgress<T> CreateNew();
Report(T progress);
}
Progress<T> : IProgress<T>
{
Progress(ShellProgressClass)
{
// initialize progressBar or span new
}
....
IProgress<T> CreateNew()
{
return new Progress();
}
}
you can later improvise to have one big progressBar (collection of Sequential or Parallel) and what not
Your MyService could have a dependency similar to:
public interface IJobContainer
{
void Add(IJob job);
void RunJobs(IProgress<MyProgress> progress, Action<IJob>? callback = null); // Using an action for extra work you may want to do
}
This way you don't have to worry about reporting progress in MyService (which doesn't feel like it should be MyService's job anyway. The implementation could look something like this for the parallel job container:
public class MyParallelJobContainer
{
private readonly IList<IJob> parallelJobs = new List<IJob>();
public MyParallelJobContainer()
{
this.progress = progress;
}
public void Add(IJob job) { ... }
void RunJobs(IProgress<MyProgress> progress, Action<IJob>? callback = null)
{
using (var progressBar = new ProgressBar(options...))
{
Parallel.ForEach(parallelJobs, job =>
{
callback?.Invoke(job);
job.Execute();
progressBar.Tick();
})
}
}
}
MyService would then look like this:
public class MyService : IMyService
{
private readonly IJobContainer sequentialJobs;
private readonly IJobContainer parallelJobs;
public MyService(
IJobContainer sequentialJobs,
IJobContainer parallelJobs)
{
this.sequentialJobs = sequentialJobs;
this.parallelJobs = parallelJobs;
this.sequentialJobs.Add(new DoSequentialJob1());
this.sequentialJobs.Add(new DoSequentialJob2());
this.sequentialJobs.Add(new DoSequentialJob3));
this.parallelJobs.Add(new DoParallelJobA());
this.parallelJobs.Add(new DoParallelJobB());
this.parallelJobs.Add(new DoParallelJobC());
}
public void RunJobs(IProgress<MyCustomProgress> progress)
{
sequentialJobs.RunJobs(progress, job =>
{
// do something with the job if necessary
});
parallelJobs.RunJobs(progress, job =>
{
// do something with the job if necessary
});
}
The advantage of this way is that MyService only has one job and doesn't have to worry about what you do once the job is completed.
From my understanding of your issue the question is how do you display progress across both completion of the synchronous jobs and parallelized jobs.
In theory the parallel jobs could start and finish at the same time, so you could treat the parallel jobs as a single job. Instead of using the count of sequential jobs as your total, increase that number by one. This might be satisfactory for a small number of parallel jobs.
If you want to add progress between the parallel jobs, you will need to handle multi-threading in your code because the parallel jobs will be running concurrently.
object pJobLock = new object();
int numProcessed = 0;
foreach(var parallelJob in parallelJobs)
{
parallelJob.DoWork();
lock (pJobLock)
{
numProcessed++;
progress.Report(new MyCustomProgress { Current = numProcessed, Total = parallelJobs.Count() });
}
}

Await on abstracted asynchronous task

I am very new to the async/await usage. I am trying to abstract the asynchrony and await conditionally in the UI. I have an abstract base class:
public abstract class Base
{
public abstract bool IsRunning { get; }
public abstract Task<bool> Run();
}
and from it some derived instances, first one being synchronous:
internal class Derived1 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived1(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return false; }
}
public override Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
return task;
}
}
and a derived class for an asynchronous implementation:
internal class Derived2 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived2(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return task != null && task.Status == TaskStatus.Running; }
}
public override Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
return task;
}
}
Then in the UI, I would like to await on asynchronous task (if user specified so in a run-time config), as follows:
internal class CaseMenuHandler
{
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool ok = true;
if( something_holds ) {
ok = await baseCaseRunner.Run();
}
else {
ok = baseCaseRunner.Run().Result;
}
}
catch (Exception e)
{
LogError(...);
}
}
}
Hope this is clear. Can I do the above, specifically awaiting conditionally inside an if block? Ideally I would like to make the Base class only return bool and not Task<bool> for the Run method, and only have the Derived2 class override to return a Task<bool>, but I am not clear on how to do that. Perhaps I should return the task.Result inside the Run method of Derived2? If there's a better way to this including the abstraction or any other corrections, please let me know. Appreciate any ideas.
EDIT #1
The Run method form for the synchronous implementation in Derived1 has been clarified in the responses below. I am not allowed to change the signature of the DoSomething method though, so given that, my Run method in Derived2 (asynchronous implementation) looks as follows now (thanks to #Stripling's comments):
public override async Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
task.Start();
return await task;
}
EDIT #2:
When I try the above (also tried putting a task.Start() call after the task definition, I get the following error:
Cross-thread operation not valid: Application accessed domain object from a thread other than a legal thread.
Can I do the above, specifically awaiting conditionally inside an if block?
You can, but you shouldn't have to. If you do things right, there's no great advantage to specifically invoking a synchronous task in a blocking fashion: as a general rule, you can just await the Task that's returned, and if it represents a synchronous task then the await will be resolved synchronously with very little overhead.
When I say "if you do things right", here's the right way:
// synchronous
public override Task<bool> Run()
{
var result = DoSomething();
return Task.FromResult(result);
}
// asynchronous
public override async Task<bool> Run()
{
var result = await DoSomethingAsync();
return result;
}
awaiting the result of the first example above will not do any thread-switching or anything like that. awaiting the result of the second might, depending on the implementation of DoSomethingAsync(). There's no particular need for a layer of abstraction: you can always check a Task to whether it's completed or not, and awaiting an already-completed task will always return a value immediately.
I don't see how your synchronous version is synchronous, you still use the Task.Run(, I would have expected
internal class Derived1 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived1(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return false; }
}
public override Task<bool> Run()
{
bool ok = DoSomething();
return Task.FromResult(ok);
}
}
If you do it that way instead of the way you are doing it, your other code just becomes
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool ok = true;
ok = await baseCaseRunner.Run();
}
catch (Exception e)
{
LogError(...);
}
}
}
The asynchronous version will run asynchronously and the synchronous version will run synchronously.
Your "async version" is not really async either, see Stripling's answer for the correct way to do that method.
Then in the UI, I would like to await on asynchronous task (if user specified so in a run-time config)
First off, I just have to say that this is a really bad idea. Some things should be configurable, and some should not. The asynchrony of operations should not be configurable. Period. This is a horrible design, and the first thing I would do is push back hard against ridiculous "requirements" like this. It literally makes the same amount of sense as a configurable flag for whether or not to throw exceptions.
That said, it can be done. It's painful, difficult to maintain, and completely useless at the end of the day. But hey, I assume you're getting paid for this so it's all good, eh?
If you must do this for political reasons (there are absolutely no valid technical reasons), then I recommend you use the Boolean Argument Hack from my article on brownfield async. One problem with just blocking (Result) is that it doesn't work if Run uses await (for reasons described on my blog).
The boolean argument hack simply adds a boolean argument indicating whether the method is expected to complete synchronously or not.
public abstract class Base
{
public abstract Task<bool> RunAsync(bool sync);
}
The semantics here are that if sync is true, then the task returned from RunAsync must already be completed.
Your implementation then looks like:
internal class Derived1 : Base
{
public override async Task<bool> RunAsync(bool sync)
{
IsRunning = true;
try
{
if (sync)
return DoSomething();
return await Task.Run(() => DoSomething());
}
finally
{
IsRunning = false;
}
}
}
And it's called like:
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool sync = !something_holds;
bool ok = await baseCaseRunner.RunAsync(sync);
}
catch (Exception e)
{
LogError(...);
}
}
}
Note that it can always be called with await, but OnRun will actually be synchronous if sync is true. This is due to the "await fast path" - the fact that await first checks whether the task is already complete, and if it is, it continues synchronously (as described in my async intro blog post).
Use Task.FromResult to return a task that contains the result that was computed synchronously, and await.
bool ok = DoSomething();
return Task.FromResult(ok);
As a side note I'd not put synchronous code in a method that was generally intended to be asynchronous (or that is synchronous in other classes/places) and vice versa. I'd use different interfaces/base classes for a synchronous and an asynchronous implementation.
interface IRunnable
{
bool IsRunning;
bool Run();
}
interface IRunnableAsync
{
bool IsRunning;
Task<bool> RunAsync();
}

How to Unit Test DelegateCommand that calls async methods in MVVM

I am new to Unit Testing MVVM and using PRISM on my project. I am implementing Unit Testing on our current project and not having luck finding resources online that would tell me how totest DelegateCommand that calls async method. This is a follow up question to my post - How to Unit Test a ViewModel with async method. on how to unit test an async methods in MVVM and was answered that public methods can be tested using async TestMethod. This scenario will work only if the method that I want to test are public methods.
The problem is I want to test my DelegateCommand as this are the only public details that I want to expose on other classes and everything else are private. I can expose my private methods as public but I will never do this as its a bad design. I am not sure on how to go about this - Is DelegateCommand needs to be tested, or there are some other work around this? I am interested to know how other go about this and somehow lead me to the right path.
Here are my codes again
async void GetTasksAsync()
{
this.SimpleTasks.Clear();
Func<IList<ISimpleTask>> taskAction = () =>
{
var result = this.dataService.GetTasks();
if (token.IsCancellationRequested)
return null;
return result;
};
IsBusyTreeView = true;
Task<IList<ISimpleTask>> getTasksTask = Task<IList<ISimpleTask>>.Factory.StartNew(taskAction, token);
var l = await getTasksTask; // waits for getTasksTask
if (l != null)
{
foreach (ISimpleTask t in l)
{
this.SimpleTasks.Add(t); // adds to ViewModel.SimpleTask
}
}
}
also here is the command in my VM that calls the async method above
this.GetTasksCommand = new DelegateCommand(this.GetTasks);
void GetTasks()
{
GetTasksAsync();
}
and now my Test Method goes like
[TestMethod]
public void Command_Test_GetTasksCommand()
{
MyViewModel.GetTaskCommand.Execute(); // this should populate ViewModel.SimpleTask
Assert.IsTrue(MyBiewModel.SimpleTask != null)
}
Currently what I am getting is that my ViewModel.SimpleTask = null this is because it does not wait for the async method to finish.
I wrote an AsyncCommand class that returns a Task object from the Execute method. You then need to implement ICommand.Execute explicitly, awaiting the Task from your Execute implementation:
public class AsyncCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public Func<Task> ExecutedHandler { get; private set; }
public Func<bool> CanExecuteHandler { get; private set; }
public AsyncCommand(Func<Task> executedHandler, Func<bool> canExecuteHandler = null)
{
if (executedHandler == null)
{
throw new ArgumentNullException("executedHandler");
}
this.ExecutedHandler = executedHandler;
this.CanExecuteHandler = canExecuteHandler;
}
public Task Execute()
{
return this.ExecutedHandler();
}
public bool CanExecute()
{
return this.CanExecuteHandler == null || this.CanExecuteHandler();
}
public void RaiseCanExecuteChanged()
{
if (this.CanExecuteChanged != null)
{
this.CanExecuteChanged(this, new EventArgs());
}
}
bool ICommand.CanExecute(object parameter)
{
return this.CanExecute();
}
async void ICommand.Execute(object parameter)
{
await this.Execute();
}
}
You can then pass async Task-returning methods to the command class:
public class ViewModel
{
public AsyncCommand AsyncCommand { get; private set; }
public bool Executed { get; private set; }
public ViewModel()
{
Executed = false;
AsyncCommand = new AsyncCommand(Execute);
}
private async Task Execute()
{
await(Task.Delay(1000));
Executed = true;
}
}
In your unit tests, you simply await the Execute method:
[TestMethod]
public async Task TestAsyncCommand()
{
var viewModel = new ViewModel();
Assert.IsFalse(viewModel.Executed);
await viewModel.AsyncCommand.Execute();
Assert.IsTrue(viewModel.Executed);
}
The UI, on the other hand, will call the explicitly implemented ICommand.Execute method which takes care of awaiting the task.
(*) In the meantime I noticed that if you follow common naming conventions, the Task-returning method should actually be named ExecuteAsync.
In Prism 6, you can create DelegateCommand and DelegateCommand<T> from async handler.
For example:
startParsingCommand=DelegateCommand
.FromAsyncHandler(StartParsingAsync,CanStartParsing)
.ObservesProperty(()=> IsParserStarted);
Since I cannot add comments, for completeness sake, in PRISM 6 you could try:
ParsingCommand = new DelegateCommand<string>(async (x) => await StartParsing(x));

How to create and use a custom Awaitable in c#?

I'm trying to implement a custom awaiteable to execute await Thread.SleepAsync() without creating any additional threads.
Here's what I've got:
class AwaitableThread : INotifyCompletion
{
public AwaitableThread(long milliseconds)
{
var timer = new Timer(obj => { IsCompleted = true; }, null, milliseconds, Timeout.Infinite);
}
private bool isCompleted = false;
public bool IsCompleted
{
get { return isCompleted; }
set { isCompleted = value; }
}
public void GetResult()
{}
public AwaitableThread GetAwaiter() { return this; }
public void OnCompleted(Action continuation)
{
if (continuation != null)
{
continuation();
}
}
}
And here's how the sleep would work:
static async Task Sleep(int milliseconds)
{
await new AwaitableThread(milliseconds);
}
The problem is that this function returns immidiatly, even though in OnCompleted, IsCompleted is still false.
What am I doing wrong?
Fully implementing the awaitable pattern for production use is a tricky business - you need to capture the execution context, amongst other things. Stephen Toub's blog post on this has a lot more detail. In many cases, it's easier to piggy-back onto Task<T> or Task, potentially using TaskCompletionSource. For example, in your case, you could write the equivalent of Task.Delay like this:
public Task MyDelay(int milliseconds)
{
// There's only a generic TaskCompletionSource, but we don't really
// care about the result. Just use int as a reasonably cheap version.
var tcs = new TaskCompletionSource<int>();
Timer timer = new Timer(_ => tcs.SetResult(0), null, milliseconds,
Timeout.Infinite);
// Capture the timer variable so that the timer can't be garbage collected
// unless the task is (in which case it doesn't matter).
tcs.Task.ContinueWith(task => timer = null);
return tcs.Task;
}
You can now await that task, just like you can await the result of Task.Delay.

Categories