Search code examples
c#filestreamdisposeobjectdisposedexception

Should I heed this superficially nonsensical Code Analysis warning?


When I select Analyze > RUn Code Analysis on Solution in Visual Studio 2013, I get, "CA2202 Do not dispose objects multiple times Object 'fs' can be disposed more than once in method 'RoboReporterSQL.SaveReportDataToDB(string, string)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object."

The indicated line of code is:

fs.Close();

And here is the code in context:

    internal static void SaveReportDataToDB(string filename, string 
RESTFilename)
    {
        if (RecordAlreadyExists(RESTFilename)) return;
        string EXCEL_FILE = "application/vnd.ms-excel";
        DateTime begDate = 
RoboReporterConstsAndUtils.GetBeginDate(RESTFilename);
        DateTime endDate = 
RoboReporterConstsAndUtils.GetEndDate(RESTFilename);

        var fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
        BinaryReader br = new BinaryReader(fs);
        Byte[] bytes = br.ReadBytes((Int32)fs.Length);
        br.Close();
        fs.Close();

        using (var sqlConn = new SqlConnection(CPSConnStr))
        {
            var insertStr = "INSERT INTO ReportsGenerated (FileBaseName, 
ContentType, BinaryData, BeginDate, EndDate) " +
                             "VALUES (@FileBaseName, @ContentType, 
@BinaryData, @BeginDate, @EndDate)";

            using (var insertRptsGenerated = new SqlCommand(insertStr))
            {
                insertRptsGenerated.Connection = sqlConn;
                insertRptsGenerated.Parameters.Add("@FileBaseName", 
SqlDbType.VarChar, 100).Value = RESTFilename;
                insertRptsGenerated.Parameters.Add("@ContentType", 
SqlDbType.VarChar, 50).Value = EXCEL_FILE;
                insertRptsGenerated.Parameters.Add("@BinaryData", 
SqlDbType.Binary).Value = bytes;
                insertRptsGenerated.Parameters.Add("@BeginDate", 
SqlDbType.DateTime).Value = begDate;
                insertRptsGenerated.Parameters.Add("@EndDate", 
SqlDbType.DateTime).Value = endDate;
                sqlConn.Open();
                insertRptsGenerated.ExecuteNonQuery();
            }
        }
    }

So the warning is claiming that the FileStream is being closed twice if I call "fs.Close();"

Although I don't refute that with certainty, I question it because I don't see it being elsewhere closed.

After all, it is not in a "using" block, so how is it being closed?

The question is: should I really remove that line of code ("fs.Close();")?

Note: Resharper did not whin[g]e a whit about this - with "fs.Close();" in or out, it raises no warning flags either way.


Solution

  • Frankly you shouldn't be closing those streams explicitly, you should be using using blocks.

    Anyway, it gives you that warning because the stream is already closed. When readers/writers wrap a stream, closing them will close the underlying stream as well. Some of readers/writers give you the option to leave the stream open however.

    In your particular case, you can kill two birds with one stone by using some of the other methods available in the File class. Consider using File.ReadAllBytes() to read in your file.