Troy Jennings
Troy Jennings

Reputation: 432

OleDBConnection or nearby code throwing InvalidComObjectException, but no actual effect on behaviour

using (OleDbCommand cmd = new OleDbCommand(cmdText, WFConn))
{
    int val = 0;

    AddParameterToODBComm(cmd, Type);
    AddParameterToODBComm(cmd, Year);

    try
    {
        WFConn.Open();
        OleDbDataReader reader = cmd.ExecuteReader();
        reader.Read();
        val = (int)reader[0];
    }
    catch (Exception ex) { MessageBox.Show(ex.Message); return 0; }
    finally { WFConn.Close(); }

    return (int)(val * ((int)numCount.Value * 0.01)); //Throws an InvalidComObjectException, but still works. 
}

This code block is working exactly as I want it to (return a % of the size of the recordset), but every time it runs I'm pulled into the debugger on the last line with the COM object that has been separated from its underlying RCW cannot be used exception.

Beforehand, the return (int) etc etc was inside the try block, and the exception was happening on the Connection.Close() in the finally block.

I've got this happening in two places with the same issue. Thing is that if I continue the program everything works exactly how it's expected to. I've checked other questions relating to this exception on SO, but they refer to manually disposing/releasing COM objects, which I'm not trying to do here.

What's going on here that I'm just not seeing? It's definitely related to closing the connection - I could leave it open, but I've had an issue with expecting it to be open and it not being.

Upvotes: 1

Views: 120

Answers (1)

Jaycee
Jaycee

Reputation: 3118

I believe that in calling the close method on the connection without calling it on the reader, you will get an exception. A quick fix could just be to call reader.Close() prior to WFConn.Close().

Alternatively, ensure WFConn is wrapped in a using statement - fresh connection. Then there is no need to explicitly close the connection. It will automatically be closed and disposed via the using statement, same goes for the reader. Example of OleDbCommand use

public void ReadMyData(string connectionString)
{
    string queryString = "SELECT OrderID, CustomerID FROM Orders";
    using (OleDbConnection connection = new OleDbConnection(connectionString))
    {
        using (OleDbCommand command = new OleDbCommand(queryString, connection))
        {
            connection.Open();
            using (OleDbDataReader reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    Console.WriteLine(reader.GetInt32(0) + ", " + reader.GetString(1));
                }
            }
        }
    }
}

As OleDbDataReader is an IDisposable it is good practice to wrap it in a using statement as well as the connection, so its unmanaged resources can be released earlier rather than waiting until the garbage collector calls the reader's finalize method. This protects you against forgetting to call close on the reader as well on the connection. The compiler will generate a try/finally block for you with close/dispose added for each. You are correctly observing the IDisposable pattern with your use of the OleDbCommand instance.

Upvotes: 3

Related Questions