devfunkd
devfunkd

Reputation: 3234

WPF verify call not made from GUI thread

I've tried various methods from other SO questions over the last week and this is the best approach I found yet, but I do not know how to unit test this with NUnit.

private void VerifyDispatcherThread()
    {
        var context = SynchronizationContext.Current;

        if (context != null && context is DispatcherSynchronizationContext)
        {
            Log.For(this).Info("WARNING! - Method Should Not Be Called From Dispatcher Thread.");

            if (DispatcherThreadSafetyEnabled)
            {
                throw new ThreadStateException("Method Should Not Be Called From Dispatcher Thread.");
            }
        }
    }

HERE IS OUR TEST (Not Working)

        [Test]
        public void Should_throw_exception_when_called_from_dispatcher()
        {
            // Arrange
            var called = false;
            Boolean? success = null;

            var httpClient = new HttpClient(HttpTimeOut);

            // This emulates WPF dispatcher thread
            SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());

            Dispatcher dispatcher = Dispatcher.CurrentDispatcher;

            // Act
            dispatcher.BeginInvoke(delegate()
            {
                try
                {
                    ConfigurationManager.AppSettings.Set("DispatcherThreadSafetyEnabled", "true");
                    httpClient.Post("http://Foo", "content xml");
                    success = true;
                }
                catch
                {
                    success = false;
                }
                finally
                {
                    ConfigurationManager.AppSettings.Set("DispatcherThreadSafetyEnabled", "false");
                }
                called = true;
            });

            // this part is a bit ugly
            // spinlock for a bit to give the other thread a chance
            var timeout = 0;
            while (!called && timeout++ < 1000)
                Thread.Sleep(1);

            // Assert
            Assert.IsNotNull(success, "Method was never invoked");
            Assert.IsFalse(success.Value, "Expected to fail");
        }

DispatcherThreadSafetyEnabled is a app.config setting we have so we can toggle only logging or throwing exceptions.

What we are trying to do is verify the calling method isn't using the GUI thread when invoked. It appears to be working but we are having a hard time trying to unit test this.

Here's hoping someone has done this and can help us out with our challenge.

Upvotes: 0

Views: 285

Answers (1)

Suresh
Suresh

Reputation: 4149

The current SynchronizationContext is set to different implementations by different frameworks (Winforms, WPF, etc).

Quoting from this MSDN article:

WindowsFormsSynchronizationContext (System.Windows.Forms.dll: System.Windows.Forms) Windows Forms apps will create and install a WindowsFormsSynchronizationContext as the current context for any thread that creates UI controls.

DispatcherSynchronizationContext (WindowsBase.dll: System.Windows.Threading) WPF and Silverlight applications use a DispatcherSynchronizationContext, which queues delegates to the UI thread’s Dispatcher with “Normal” priority. This SynchronizationContext is installed as the current context when a thread begins its Dispatcher loop by calling Dispatcher.Run.

Since you are only testing for not null and the type of the SynchronizationContext, try setting current SynchronizationContext to an instance of DispatcherSynchronizationContextby calling SynchronizationContext.SetSynchronizationContext from your unit tests. Sample code below:

SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));

Please note this is not a recommended in a Winforms/WPF application though.

Upvotes: 1

Related Questions