Search code examples
c#wpfmultithreadingbackgroundworker

Using BackgroundWorker WPF and getting error: Cannot access a disposed object


I am fairly new to multi threading, therefore please excuse any obvious mistakes which may be present - I am still learning!

I currently have a program which reads in from a port using TCPClient and NetworkStream and outputs the data to a text box in a WPF program. Nonetheless, when trying to read in multiple times from the stream, it slows the program down quite noticeably and the more it has to read, the longer it takes for the program to open. Therefore I decided to try and implement threading and I am trying to use Background Worker.

Here is the code I have in the MainWindow:

InitializeComponent();

    try
    {
        client.Connect(address, port); //connect to the client 
        nwStream = client.GetStream(); //read in data from stream
        readInTxtBox.Text = ("Connection Open");
        BackgroundWorker worker = new BackgroundWorker(); 

        worker.DoWork += worker_DoWork; 
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync();

    }
    catch (SocketException ex)
    {
        readInTxtBox.Text = ex.ToString(); //write out the error
    }
    finally
    {
        client.Close();
    }

This is the worker_DoWork and worker_RunWorkerCompleted methods:

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    if (Dispatcher.CheckAccess())
    {
        ReadIn();
    }
    else
    {
        Dispatcher.BeginInvoke(new Action(() =>
        {
            ReadIn();
        }));
    }
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Dispatcher.BeginInvoke(new Action(() =>
    {
        OutputToTextBoxInput();

    }));

}

When stepping through, it does go to the Dispatcher.BeginInvoke action on the worker_DoWork, and fails on the first line of the ReadIn() method :

private void ReadIn()
{
    byte[] b = Utilities.ReadInBytes(client, nwStream); //fails here!
    hex = Utilities.ConvertByteToHex(b);
    nwStream.Close();
}

It fails on the following line of the ReadInBytes method, with the error: Cannot access a disposed object.

public static byte[] ReadInBytes(TcpClient client, NetworkStream nwStream)
{
    byte[] bytesToRead = new byte[client.ReceiveBufferSize]; //FAILS HERE
    int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
    ArraySegment<byte> segment = new ArraySegment<byte>(bytesToRead, 0, bytesRead);

    return segment.ToArray();
} 

The client and network stream are declared as public statics. I have had this problem when using invoke and when not. I have also tried BeginInvoke and the same problem has occurred. Any help would be massively appreciated as well as any explanations on where I have gone wrong!


Solution

  • The problem is, that you dispose the client in the finally block, but use it in the DoWork methods which is running later.

    To solve it, create, connect and clode the client in the DoWork event :).


    As mentioned in a comment, you should not dispatch your code in the DoWork method! Just call ReadIn there. You want to run the code in background, so that the GUI remains resposable - it makes no sense to push it to the GUI thread!

    It is also not required to dispatch the code in the RunWorkerCompleted event handler, because the background work does it for you ;).