mercredi 4 février 2015

How to guarantee that Task.Factory.StartNew runs on the UI thread?

I'm aware that there are several similar questions on this and other websites, but the standard way of doing this doesn't appear to work in my situation for some reason. The normal way to accomplish this requirement is to use TaskScheduler.FromCurrentSynchronizationContext() as the TaskScheduler input parameter in the relevant Task.Factory.StartNew overload:



// Set uiTaskScheduler whilst on the UI thread
TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
...
Task.Factory.StartNew(() => SomeMethodToRunAsynchronously(),
CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler);


It appears that this is enough to schedule a Task to run on the UI thread, but it doesn't seem to work in my situation. In my case, I have a UiThreadManager class which among other things has a RunAsynchronously method in it:



public Task RunAsynchronously(Action method)
{
return Task.Run(method);
}


This part works just fine. The problem that I face is that when running unit tests, this class is replaced with a MockUiThreadManager class (both implement an IUiThreadManager interface which is used by the application code) and I can't seem to force this method to run on the UI thread:



public Task RunAsynchronously(Action method)
{
return Task.Factory.StartNew(() => method(),
CancellationToken.None, TaskCreationOptions.None, UiTaskScheduler);
}


The MockUiThreadManager class has a static UiTaskScheduler property which is set (like below) on the UI thread, so I assumed that all code passing through the above method would run as expected on that thread:



SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
MockUiThreadManager.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();


However, when running a unit test, I noticed that it finished before the code that it was testing. I therefore added some breakpoints and called System.Threading.Thread.CurrentThread.ManagedThreadId in the Visual Studio Immediate Window at each breakpoint and sure enough, when the code passed through the above method, the thread ID changed.


So basically, I'm looking for a way to fake a Task based asynchronous call for the RunAsynchronously method that is run during unit tests that will ensure that the method actually runs synchronously on the UI thread. Does anybody see what I have done wrong, or have any other suggestions?


Aucun commentaire:

Enregistrer un commentaire