2

So I don't know how to ask this question and might be one reason I am having issues finding the answers anywhere.

So my setup is that I have a class

public class Connection
{
    public static event EventHandler LogggedIn;
    public static TDConnection TDC {get;set;}
    public string Authenticate(){...}
    public static void Login()
    {
        if (Connection.TDC.Connected)
        {
            _bw = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };
            _bw.DoWork += ConnectToProject_DoWork;
            _bw.RunWorkerCompleted += ConnectToProject_RunWorkerCompleted;

            _bw.RunWorkerAsync(Connection.TDC);
        }
    }

    private static void ConnectToProject_DoWork(object o, DoWorkEventArgs e)
    {
        Connection.TDC.ConnectProjectEx(Connection.Domain, Connection.Project, Connection.UserName, Utilities.Encryption.AESEncryption.Decrypt(Connection.Password, "fsd*#(dfs(((>>>???fdjs"));
    }

    private static void ConnectToProject_RunWorkerCompleted(object o, RunWorkerCompletedEventArgs e)
    {
        LogggedIn(null, new EventArgs());
    }
}

In my main class I instantiate a new Connection and call Login which opens a new connection to ALM in TDConnection. In my thread I want to use this already open connection inside of my thread. From what I have read, if I do this my UI will block because I am using the methods for the member on the UI thread even though I am inside of the background worker.

One solution I have found to do this:

private static void ConnectToProject_DoWork(object o, DoWorkEventArgs e)
    {
        TDConnection conn = new TDConnection();
        conn.InitConnectionEx(QCURL);

        conn.Login();

        conn.ConnectProject();

        e.Result = conn;
    }

I would prefer not to do this because I have already logged in and it takes extra time to do this.

I have tried passing Connection.TDC in with _bw.RunorkerAsync(Connection.TDC) but this does not work either obviously.

Is there any way I can use the already established connection and not block the UI while it is connecting?

Smeiff
  • 259
  • 1
  • 6
  • 17
  • 2
    There is no UI code here. Are you calling a method on this class from your UI thread that will block until the background worker has completed? – pstrjds Aug 31 '12 at 16:15
  • 1
    Your WorkerReportsProgress and Cancellation settings are misleading (because unused). – H H Aug 31 '12 at 16:26
  • Sorry. I am using the Connection.Login in a Winform button click event handler. Since the connection will open in a thread I have wired up an event handler to fire when the connection has been established. Because it is being called from my Winform, it blocks my UI. – Smeiff Aug 31 '12 at 16:59

1 Answers1

6

This is common with COM objects. Just like .NET classes, many COM coclasses are not thread safe. In .NET you get to shoot your own foot if you use a .NET class in a thread-unsafe way. Not in COM, it guarantees that a coclass that advertizes itself as not thread-safe will be used in a thread-safe way.

Which it does by automatically marshaling a method call from a worker thread to the thread that created the object. You can see where that goes, you created the TDC object on the main thread. So when you call it from the BackgroundWorker, it will still execute the call on the main thread.

The only way to solve this is to create the object on the same thread that you use it. Which typically also means that you can't use BackgroundWorker, you may well need to create a Thread and call its SetApartmentState() method to switch it to STA.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Do you know of a good example I can look at for this? I haven't heard of SetApartmentState and at first glance I haven't found too many helpful articles. – Smeiff Aug 31 '12 at 18:26
  • Maybe I'm missing something but switching it to the STA Thread means that its still going to block isn't it? Maybe I don't understand your example but if I call the Connecton.TDC.ConnectToProject inside of the STA Thread it is still going to block correct? – Smeiff Aug 31 '12 at 18:42
  • Of course. The point is that the blocking happens on a thread *other* than your main thread. – Hans Passant Aug 31 '12 at 18:45
  • So basically if I had more code to execute after calling the login thread it would execute while it logged in? What I need is the UI not to be blocked. I think I will just go with my original work around if there is no way around it. Thanks for the help! – Smeiff Aug 31 '12 at 18:52