The below code:
[RequiresSTA]
[Test]
public async Task TestSta()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" - "+Thread.CurrentThread.GetApartmentState());
// *** await something here ***
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" - "+Thread.CurrentThread.GetApartmentState());
new FrameworkElement();
}
Yields the following output:
9 - STA
12 - MTA
And then, throws an InvalidOperationException on new FrameworkElement().
NUnit supports STA thread creation, now supports async tests, but it seems that it doesnt mix both modes by creating a MTA SynchronizationContext.
How do I get this working? Any workaround ?
You can use the AsyncContext
from my AsyncEx
library , which was originally written to support async
unit tests before the unit test libraries supported them.
[RequiresSTA]
[Test]
public Task TestSta()
{
AsyncContext.Run(async () =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" - "+Thread.CurrentThread.GetApartmentState());
// *** await something here ***
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" - "+Thread.CurrentThread.GetApartmentState());
new FrameworkElement();
});
}
I managed to fix this. However, I'm sure that a post on stackoverflow would have avoided me quite a headache :) see my answer below.
A really good article about SynchronizationContext (click here) just gave me the code (and the knowledge) I required.
However, I had to tweak it a bit to avoid a deadlock on StaSynchronizationContext disposal, and to propagate the synchronization context inside the worker thread.
My test now looks like below:
[Test]
[RequiresSTA]
public async Task DoSomeUITest()
{
using (new StaSynchronizationContext())
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + Thread.CurrentThread.GetApartmentState());
// *** await something here ***
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + Thread.CurrentThread.GetApartmentState());
new FrameworkElement();
}
}
Now outputs:
9 - STA
12 - STA
... problem solved !
* edit and disclaimer * Before having awaited something, your code will be running on the STA thread created by NUnit. (thread 9) After the first await, code will be running on the thread created by StaSynchronizationContext (thread 12): even if they're both STA they are not the same thread
Beware instanciating controls before await, and using them after. Just needs a bit more tweaking to switch directly to main thread (we could imagine a "using(await StaSynchronizationContext.Create())" which would make us switch on thread 12 at begining)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.