Why do I get an Invalid Operation Exception (non STA thread?) running this MSpec test on TeamCity?

StackOverflow https://stackoverflow.com/questions/15364328

  •  23-03-2022
  •  | 
  •  

Question

As part of the migration of my app to .NET 4, I'm struggling to get some of the WPF unit tests working again with TeamCity.

On all the tests that are somehow using a WPF control (a ListItem for example), I get an exception I didn't get before:

System.InvalidOperationException: The calling thread must be STA, because many UI components require this.

I understand what it means, and after checking, it turns out that my thread is indeed MTA, not STA.

My problem is that I have no idea on how to fix this, and where this problem could be coming from... Is it a setting on TeamCity? MSpec? Again, it worked before I switched to .NET 4.

I tried many different solutions, but nothing worked.

I'm also a bit puzzled by the fact that no-one reported this before (with my specific stack of TeamCity + MSpec + WPF test), which might mean I'm doing something very wrong somewhere.

If you have a clue, please let me know!

Full exception:

System.InvalidOperationException: The calling thread must be STA, because many UI components require this.


 at System.Windows.Input.InputManager..ctor()
   at System.Windows.Input.InputManager.GetCurrentInputManagerImpl()
   at System.Windows.Input.KeyboardNavigation..ctor()
   at System.Windows.FrameworkElement.EnsureFrameworkServices()
   at System.Windows.FrameworkElement..ctor()
   at System.Windows.Controls.Control..ctor()
   at MyCompany.Dashboard.Client.Plugins.Common.Controls.Grids.CashflowGrid.ViewModel.ConfigureViewModel.CreateItem(String name) in d:\Program Files\JetBrains\BuildAgent2\work\6dd9af6ae2f9bbb9\Code\Src\MyCompany\Dashboard\Client\Plugins\Common\Controls\Grids\CashflowGrid\ViewModel\ConfigureViewModel.cs:line 171
   at MyCompany.Dashboard.Client.Plugins.Common.Controls.Grids.CashflowGrid.ViewModel.ConfigureViewModel.Initialise(Type type, IList`1 currentSelection, Action`1 selectionChangedCallback) in d:\Program Files\JetBrains\BuildAgent2\work\6dd9af6ae2f9bbb9\Code\Src\MyCompany\Dashboard\Client\Plugins\Common\Controls\Grids\CashflowGrid\ViewModel\ConfigureViewModel.cs:line 37
   at UnitTests.Plugins.Common.Controls.Grids.CashflowGrid.ViewModel.when_some_items_are_selected_on_the_chosen_list.<.ctor>b__1() in d:\Program Files\JetBrains\BuildAgent2\work\6dd9af6ae2f9bbb9\Code\Src\UnitTests.Plugins.Common\Controls\Grids\CashflowGrid\ViewModel\ConfigureViewModelTests.cs:line 82

For this exception, the code is simply trying to instantiate a ListBoxItem, nothing fancy, but doing that on a MTA thread breaks it.

What I tried:

  • Setting the current thread to STA

    Thread.CurrentThread.SetApartmentState(ApartmentState.STA)

It of course doesn't work because it's only possible before the thread starts

  • Run the code in a separate thread that was initialised as STA: very complex since, due to the nature of MSpec, different methods are called at different time so you can't run EVERYTHING under the same thread. More precisely, you can't run the "Establish context" on the same thread as the "Because of" statement.

  • Use the STAThread attribute... yes but where? never worked anywhere I tried

Example of a failing test:

public class StaTestExample
{
    Establish context = () => _control = new ListBox();

    It should_not_be_null = () => _control.ShouldNotBeNull();

    protected static Control _control;
}
Was it helpful?

Solution

It now works.

But the problem is we just can't explain it. And it still fails on a different build server, but we don't care about this one.

In case someone gets that problem, here what we did:

  • Disabling test coverage
  • Disabling the MSPec task: the build goes green
  • Re-enabling coverage and MSpec: it works...

The odd thing is that exact process was applied on a different build server (an old one we don't use anymore), and it still fails.

There's nothing else we could think of that changed.

So it's a bit of a mystery... I hope it won't come back to bite us!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top