Question

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?

Was it helpful?

Solution

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.

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