1

This is a logging class with a constructor:

public QFXLogger(
        int maxFileSize,
        TraceLevel logLevel)
    {
        this.maxFileSize = maxFileSize;
        logSwitch.Level = logLevel;
        //Configure log listener
        traceListener = new FileLogTraceListener();
        traceListener.DiskSpaceExhaustedBehavior = DiskSpaceExhaustedOption.DiscardMessages;
        traceListener.CustomLocation = @".\Log";
        traceListener.BaseFileName = "QFXLog";
        traceListener.AutoFlush = true;
        //Remove all other listeners
        Trace.Listeners.Clear();
        //Add QFX listener
        Trace.Listeners.Add(traceListener);
        //Write header
        WriteSessionHeader();
    }

And this is the destrcutor:

~QFXLogger()
    {
        WriteSessionFooter();
        traceListener.Close();
    }

I just want to write a footer to the underlying stream before the logger gets GC. Without the destructor everything is fine, but with it I get the following:

Unhandled Exception: System.ObjectDisposedException: Cannot access a closed file
.
at System.IO.__Error.FileNotOpen()
at System.IO.FileStream.Flush(Boolean flushToDisk)
at System.IO.FileStream.Flush()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Flush()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.ReferencedStream.CloseS
tream()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.CloseCurrentStream()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.Write(String message)
at System.Diagnostics.TraceInternal.Write(String message)
at System.Diagnostics.Trace.Write(String message)
at QFXShell.QFXLogger.WriteSessionFooter()
at QFXShell.QFXLogger.Finalize()

It seems to me that the underlying stream was already closed.

How can I suppress this closing(of the underlying stream) or is this another issue?

Juergen
  • 3,489
  • 6
  • 35
  • 59
  • @Ramhound WriteSessionFooter does nothing but this: Trace.Write(footerString); The problem is that I would like to write an end statement before the app gets closed. – Juergen Oct 18 '11 at 13:47
  • This ObjectDisposedException happened to me when calling Stream.Dispose() in my class' IDisposable interface implementation, but stopped happening after I removed call function calls to Stream.Flush(). – user8128167 Apr 17 '14 at 17:05
  • Ooops, spoke too soon. Resolved the issue by ensuring my Dispose(bool isFreeingManagedResources) function was protected virtual, as Kelly Leahy explains on his site. Previously, I had it as private. – user8128167 Apr 17 '14 at 17:32

2 Answers2

2

Finalizers (destructors) in c# should not be used in this method. Finalizers are intended only to release unmanaged resources. When a finalizer is called, access to other .net objects is not guaranteed and should only release unmanaged resources that you directly allocated.

Finalize operations have the following limitations:

  • The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already finalized when the finalizer of Object A starts.

What you need to do is implement the IDisposable Interface to properly close your logging file. Some additional information can be found at Kelly Leahy's IDisposable and Garbage Collection.

If you are not in a situation where a disposable class will help (global object, etc.) you can always implement a Close method yourself to ensure the file is valid before it is released.

Joshua
  • 8,112
  • 3
  • 35
  • 40
1

It is too late for you to close the tracer object in the destructor. In this moment a lot of objects which are not needed any more can be already disposed.

I would propose to implement a IDisposable interface with a public Dispose method and to call this method as soon as you know that you are not going to need this QFXLogger object any more. In this Dispose method, I would check if the tracer object is not NULL, open and then I would call Close on it.

See Proper use of the IDisposable interface for more details.

Community
  • 1
  • 1
Tomas Walek
  • 2,516
  • 2
  • 23
  • 37