Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper Way to Dispose: object not disposed along all exception paths

I get this message for line 84 and line 85 (the two, stacked using lines):

CA2000 : Microsoft.Reliability : In method 'RavenDataAccess.GetRavenDatabase()', object '<>g_initLocal9' is not disposed along all exception paths. Call System.IDisposable.Dispose on object '<>g_initLocal9' before all references to it are out of scope.

DocumentStore implements IDisposable.

Why? How else can I dispose the DocumentStore objects? They're created in a using block, and I dispose of them in my catch block. How should this be fixed?

private static IDocumentStore GetRavenDatabase()
{
    Shards shards = new Shards();

    try
    {
        using (DocumentStore docStore1 = new DocumentStore { Url = ConfigurationManager.AppSettings["RavenShard1"] })  // Line 84
        using (DocumentStore docStore2 = new DocumentStore { Url = ConfigurationManager.AppSettings["RavenShard2"] })  // Line 85
        {
            shards.Add(docStore1);
            shards.Add(docStore2);
        }

        using (ShardedDocumentStore documentStore = new ShardedDocumentStore(new ShardStrategy(), shards))
        {
            documentStore.Initialize();

            IndexCreation.CreateIndexes(typeof(RavenDataAccess).Assembly, documentStore);

            return documentStore;
        }
    }
    catch
    {
        shards.ForEach(docStore => docStore.Dispose());

        throw;
    }
}
like image 426
Bob Horn Avatar asked Oct 08 '22 03:10

Bob Horn


1 Answers

You have to ensure that you dispose all your newly created Disposable objects along any possible exception path. See below:

private static IDocumentStore GetRavenDatabase()
{
    Shards shards = new Shards();
    DocumentStore docStore1 = null;
    DocumentStore docStore2 = null;

    ShardedDocumentStore shardedDocumentStore = null;
    ShardedDocumentStore tempShardedDocumentStore = null;

    try
    {
        docStore1 = new DocumentStore();
        docStore1.Url = ConfigurationManager.AppSettings["RavenShard1"];
        docStore2 = new DocumentStore();
        docStore2.Url = ConfigurationManager.AppSettings["RavenShard2"];

        shards.Add(docStore1);
        shards.Add(docStore2);

        tempShardedDocumentStore = new ShardedDocumentStore(new ShardStrategy(), shards);
        tempShardedDocumentStore.Initialize();

        IndexCreation.CreateIndexes(typeof(RavenDataAccess).Assembly, tempShardedDocumentStore);

        docStore1 = null;
        docStore2 = null;

        shardedDocumentStore = tempShardedDocumentStore;
        tempShardedDocumentStore = null;

        return shardedDocumentStore;
    }
    finally
    {
        if (tempShardedDocumentStore != null) { tempShardedDocumentStore.Dispose(); }
        if (docStore1 != null) { docStore1.Dispose(); }
        if (docStore2 != null) { docStore2.Dispose(); }
    }
}

CA seems to have a problem with the inline property initializers but if you break them out this should work. Key thing is to ensure that no matter where an exception is thrown in the try block, all your new objects that can be disposed are cleaned up.

By setting the temp references you no longer need to null (docStore1, docStore2, and tempShardedDocumentStore) just prior to returning, you can check in the finally block to see if they in fact were set to null, if not, an exception occurred somewhere and you can dispose of them before execution leaves this method.

Note docStore1 and docStore2 are temporary references as they are added to the Shards collection.

like image 74
Jim Avatar answered Oct 12 '22 11:10

Jim