0

I'm just playing around a bit with this neat code from Codeproject

There is a safe invocation method for controls:

public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> call) where T : ISynchronizeInvoke
{
   if (isi.InvokeRequired) { 
      IAsyncResult result = isi.BeginInvoke(call, new object[] { isi }); 
      object endResult = isi.EndInvoke(result); return (TResult)endResult; 
   }
   else
      return call(isi);
}

Scenario 1: Windows Forms app with an WebBrowser control on it. This call returns what it should (the returning result is of no matter at the moment, just for testing around):

private void button1_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(StartStuff));
    thread.Start();
}

private void StartStuff()
{        
    var document = webBrowser1.SafeInvoke(o => o.Document);    
}

So far so good, nice job from the guy that created this fragment of safe invocation.

Scenario 2: Next I would like to run some unit tests that handle some WebBrowser based stuff. This little test shall demonstrate this:

[Test, Category("Thread Safety")]
public void TestIfThreadRaisesException()
{
    /* create STA thread where the browser will live and die in */
    Thread thread = new Thread(RunSTAContent);
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join();
}

private static void RunSTAContent()
{   /* simulate cross thread access to control */
    var stdBrowser = new System.Windows.Forms.WebBrowser();
    Task.Run(async () => await RunUnProblematicContent(stdBrowser)).Wait();
}

private static async Task RunUnProblematicContent(System.Windows.Forms.WebBrowser browser)
{
    await Task.Delay(1000);
    var doc = browser.SafeInvoke(o => o.Document);
    //...
}

This way, I get an infinite call to SafeInvoke, more precisely it ends here:

object endResult = isi.EndInvoke(result);

Do you have a hint why the invocation never ends? Is it more because of my self made STA thread? Might it be a console runner problem in combination with NUnit?

stev-e
  • 436
  • 6
  • 15
  • 3
    There is no message loop on your STA thread (`Application.Run`) which is mandatory for `Invoke` support. – Ivan Stoev Jan 31 '17 at 21:28
  • Ohhh, that seems absolutely plausible, and obviously... I will check it tomorrow and will provide feedback. Thanks a lot – stev-e Jan 31 '17 at 22:23
  • 2
    @stev-e: On a side note, I always discourage the use of `InvokeRequired`. The "safe invoke" approach is an anti-pattern. Code should always know where it is running, and thread jumps should be explicit. – Stephen Cleary Feb 01 '17 at 14:35

1 Answers1

0

As stated in Ivans comment the message loop was missing. I came across this class that I can use for this purpose :)

MessageLoopApartment

stev-e
  • 436
  • 6
  • 15