locked
Cannot write to a closed TextWriter

    Question

  • In Unit-Tests I want have all output of all trace-sources available in each unit-test output, so I can debug more easily. for this purpose I add a ConsoleTraceListener to all Sources.

    This works fine, when running one unit-test, but executing a batch causes the following error:

    Test method WZ.Hermes.Border.Daemon.UnitTests.MonitorHandlerTest.ExecuteMonitor_EmptyMonitor threw exception:  System.ObjectDisposedException: Cannot write to a closed TextWriter..
       at System.IO.__Error.WriterClosed()
       at System.IO.StringWriter.Write(String value)
       at System.IO.TextWriter.SyncTextWriter.Write(String value)
       at System.Diagnostics.TextWriterTraceListener.Write(String message)
       at System.Diagnostics.TraceListener.WriteHeader(String source, TraceEventType eventType, Int32 id)
       at System.Diagnostics.TraceListener.TraceEvent(TraceEventCache eventCache, String source, TraceEventType eventType, Int32 id, String format, Object[] args)
       at System.Diagnostics.TraceSource.TraceEvent(TraceEventType eventType, Int32 id, String format, Object[] args)
       at WZ.Hermes.Border.Daemon.Monitor.MonitorHandler..ctor(Boolean loadActiveMonitors) in C:\Projekte\Team\Tilfried.Weissenberg\WZ.Hermes\WZ.Hermes.Border.Daemon\WZ.Hermes.Border.Daemon\Monitor\MonitorHandler.cs:line 129
       at WZ.Hermes.Border.Daemon.UnitTests.MonitorHandlerTest.ExecuteMonitor_EmptyMonitor() in C:\Projekte\Team\Tilfried.Weissenberg\WZ.Hermes\WZ.Hermes.Border.Daemon\WZ.Hermes.Border.Daemon.UnitTests\MonitorHandlerTest.cs:line 141

    Any ideas on how to overcome this or what the best strategy is to capture all TraceSource output to the unit-test context?

    Wednesday, February 07, 2007 12:27 PM

Answers

  • Tilfried, do you really have to use your own trace source? You can easily get trace output from Unit Tests if you use the Trace class, like Trace.WriteLine. The issue with trace sources seems to be a bug/missing feature (no support for custom trace sources) on our side. As a workarounf you can try to create Tracer for each test method in TestInitialize/TestCleanup, you should not get the failure in this way, but I am not sure if you would be able to get console trace for 2nd method.

    Thank you,
    Michael

    Tuesday, February 13, 2007 10:54 AM

All replies

  • Tilfried, thank you for reporting this issue.  I'm unable reproduce the behaviour you describe on Visual Studio 2005 SP1; can you provide a small sample project that accurately reproduces the problem?

    Thanks,

    Ryan Vogrinec

    Monday, February 12, 2007 6:04 PM
  • Here's the code:

    Test-File:

    using System;
    using System.Text;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System.Diagnostics;

    namespace ConsoleTraceListenerBug {

    [TestClass]
    public class ListenerBug {

    internal static TraceSource Tracer = new TraceSource(typeof(ListenerBug).Namespace, SourceLevels.All);

    [TestMethod]
    public void Log_FirstTest() {
    ListenerBug.Tracer.TraceEvent(TraceEventType.Information, 0, "Should work! ConsoleTraceListener sends to console which in turn is picked-up by and logged with Unit-Test output");
    }

    [TestMethod]
    public void Log_SecondTest() {
    ListenerBug.Tracer.TraceEvent(TraceEventType.Information, 0, "This one should not work, if ConsoleTraceListener is configured!");
    }

    }

    }

    And add this in the (to be created) app.config:

    <?xml version="1.0" encoding="utf-8" ?>
    <
    configuration>
    <
    system.diagnostics>
    <
    sources>
    <
    source name="ConsoleTraceListenerBug">
    <
    listeners>
    <
    add name="Console" type="System.Diagnostics.ConsoleTraceListener" traceOutputOptions="DateTime" />
    </
    listeners>
    </
    source>
    </
    sources>
    </
    system.diagnostics>
    </
    configuration>

    As expected, the first UT succeeds, the second fails with above exception. If you run one at a time, you don't have this problem. If you remove the CONSOLE listener, all works fine, but the UT will not capture any of the output of any TraceSource - which is what I would need for debugging, if a UT fails!

    Tuesday, February 13, 2007 7:36 AM
  • Tilfried, do you really have to use your own trace source? You can easily get trace output from Unit Tests if you use the Trace class, like Trace.WriteLine. The issue with trace sources seems to be a bug/missing feature (no support for custom trace sources) on our side. As a workarounf you can try to create Tracer for each test method in TestInitialize/TestCleanup, you should not get the failure in this way, but I am not sure if you would be able to get console trace for 2nd method.

    Thank you,
    Michael

    Tuesday, February 13, 2007 10:54 AM
  • Thanks, michael, for your response. TraceSources are an integral part of our tracing/diagnostics/debugging strategy in all our DLLs and Webs. I was only using the tracesource within the Unit-Test to illustrate the bug. of course the trace-sources I'm trying to capture are actually in various DLLs for which I am writing unit-tests...
    Tuesday, February 13, 2007 1:34 PM
  • I hope you provide a fix for VS2005 aswell - not everyone is going to switch to orcas when it comes out!

    I really hope that VS will also make it into the windowsupdates at one point in time! It's a pain finding all kinds of bugs and shortcomings and having no hopes of getting fixes quickly. You're providing us with tools to have shorter iterations and faster bug-fixing - I sure hope they will be used by yourselves to provide us with just that!

    Wednesday, February 14, 2007 8:06 AM
  • In fact VS sems to participate in Windows update already. If you don't have SP1 yet, go to windowsupdate.com and scan for updates. You should see Visual Studio SP1 as high priority updates and "Visual Studio" vategory in the left pane among Windows, Office, etc updates.

    Thanks,
    Michael

    Thursday, February 15, 2007 6:23 AM
  • nice! but I did mean smaller fixes, not just SP's.
    Tuesday, February 20, 2007 4:53 PM
  • This error is still present in VS 2008.

    Using a shared LINQ DataContext among multiple tests throws an ObjectDisposedExcetpion with the following stacktrace


    System.IO.__Error.WriterClosed()
    System.IO.StringWriter.Write(Char[] buffer, Int32 index, Int32 count)
    System.IO.TextWriter.WriteLine(String value)
    System.IO.TextWriter.SyncTextWriter.WriteLine(String value)
    System.Data.Linq.SqlClient.SqlProvider.LogCommand(TextWriter writer, DbCommand cmd)
    System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult)
    System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries)
    System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
    System.Data.Linq.ChangeDirector.StandardChangeDirector.DynamicInsert(TrackedObject item)
    System.Data.Linq.ChangeDirector.StandardChangeDirector.Insert(TrackedObject item)
    System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
    System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)



    The solution is to rebuild your DataContext for each test.

    I feel that this should have been caught by MS during unit testing :)

    Monday, January 12, 2009 3:33 PM
  • any resolution to
    System.ObjectDisposedException: Cannot write to a closed TextWriter
    problem?

    I've known about it for a while and it is not fun to deal with. Any easy workarounds?
    Tuesday, June 30, 2009 11:31 PM
  • this worked for me... before each test runs, 1) clear the current trace listeners, 2) install a new console listener.   maybe not the "right" solution, but it got rid of the object disposed issue for the batch test run.

    eg.

    [TestInitialize()]
    public void MyTestInitialize() {
    Trace.Listeners.Clear();
    Trace.Listeners.Add(new ConsoleTraceListener());
    }
    

     

     

    Wednesday, November 24, 2010 6:44 AM