Dan Hall
Dan Hall

Reputation: 1534

STA thread used in Winforms but not when executed as a Console app

I have an assembly that runs under an STA thread within a sandbox from a third party, within this thread i have created a duplex WCF client that needs to execute methods on the original STA thread.

The current implementation works fine, within the Duplex callback i obtain the synchronization context of the STA thread as follows and use it to Post back to the STA thread:

private readonly SynchronizationContext _syncContext = AsyncOperationManager.SynchronizationContext;

This all runs within a WinForm initialised in the STA thread, great...but i need to move the WCF duplex proxy so it instead runs under a class instance within the main STA thread. When i remove the winform i end up getting a completely new thread from the above SynchronizationContext.

To clarify:

Winforms:-

Without WinForm (class instance):-

Executing on thread 11 instead of 1 means my methods fail to execute properly within the sandbox, there is no difference in the code between variants other than that one runs under a winform. Does anyone know how i can keep the duplex callback method execution in the main STA thread without using the winform?

Upvotes: 1

Views: 596

Answers (1)

dymanoid
dymanoid

Reputation: 15227

You're acquiring the synchronization context using the AsyncOperationManager.SynchronizationContext property. That property uses SynchronizationContext.Current under the hood.

That means, the obtained SynchronizationContext depends on the environment you're accessing the property in:

  • the thread you're accessing the property on, and
  • the type of the application.

As you can read in the docs:

The default implementation is the free-threaded implementation.

So, if the current thread's synchronization context is not set, you will get a default free-threaded SynchronizationContext instance. It will Send callbacks by synchronous execution on caller thread and Post callbacks to the ThreadPool (so "random" worker threads will pick them up).

In a Windows Forms app, the main thread's SynchronizationContext will be initialized to a WindowsFormsSynchronizationContext instance for you. That instance will Post the callbacks to the main UI thread.

In a WPF app, this will be a DispatcherSynchronizationContext.

In a console app, there will be no SynchronizationContext for the main thread. Thus, the free-threaded option I mentioned above kicks in, so you get a free-threaded SynchronizationContext instance that posts to the ThreadPool. That pretty much explains the behavior you observe.

If you need that synchronization, you can implement your own thread-affine SynchronizationContext for the main thread of your console app. That is not easy though. In a console app, you have no message loop and no dispatcher that could manage the callback queue. You can take a look on this great answer by Stephen Cleary for an idea of an asynchronous SynchronizationContext. You will need to create a 'main loop' manually though.

Upvotes: 5

Related Questions