The Danger of using

It is well known that the C# using statement is quite handy, especially when the object including in the using statement needs to be disposed.  However, there is a danger associated with having certain tasks done for you.  That is, that it is easy to forget exactly what is going on.

The scenario is that an HttpModule was being created by a client of ours to log incoming requests and outgoing responses to a web service.  I've done this before and it is not exceptionally difficult.  We created a handler for the BeginRequest event and accessed the Request.InputStream attribute. This stream was used as the basis for a StreamReader, as can be seen in the following code.

HttpApplication app = (HttpApplication)sender;

using (StreamReader sr = new StreamReader(app.Request.InputStream))
{
   
string content = sr.ReadToEnd();
    // Write content to a log file

}

app.Request.InputStream.Position = 0;

Seems innocuous enough.  But it's not.  The result of a call to a web service in which this HttpModule is installed results in an System.Xml.XmlException. The text of the message indicates that the root element of the XML document is missing. For those unfamiliar with streaming problems, this particular error message is frequently caused by an empty stream being processed by ASP.NET.

The root cause can be found in what the using statement does.  In particular, when the sr variable goes out of scope, it is disposed.  This is the non-obvious behavior I'm going about.  Not that it should be surprising that using causes the object to be disposed you understand.  That's the purpose of using after all.  But because you don't see an explicit Dispose or Close method, the solution to the problem is not obvious.  If you look at the definition of the Dispose method on the StreamReader, you will find that the underlying stream is closed. Not good, as it means that the remaining HttpModules and ASP.NET get nothing to work with.  The solution, for those who are interested (as pointed out to me by Marc Durand at Agfa during our debugging session), is to use the GetBytes method on the InputStream.  This keeps the stream open and the data flowing.

Comments

  • bruce August 12, 2004 11:58 AM

    Bruce:

    I think I missed something. You seem to say the solution to the problem is to use GetBytes. Don't you need to remove the using clause on the StreamReader? If not I'd think this would still be closing a resource the code snippet doesn't own: the Request.InputStream.

  • bruce August 13, 2004 12:58 AM

    My bad for not only not being clear, but not giving the right method name. The solution is the opposite method to GetBytes, that being GetString. The actual code that we used can be seen below. StreamReader also works, so long as you don't close the reader, either explicitly (sr.Close) or implcitly as the using statement did.

    HttpApplication app = (HttpApplication)sender;

    long streamLength = app.Request.InputStream.Length;
    byte[] contentBytes = new byte[streamLength];
    app.Request.InputStream.Read(contentBytes, 0, (int)streamLength);
    string content = System.Text.Encoding.UTF8.GetString(contentBytes);
    app.Request.InputStream.Position = 0;

  • bruce February 25, 2005 9:14 AM

    The solution, for those who are interested (as pointed out to me by Marc Durand at Agfa during our debugging session), is to use the GetBytes method on the InputStream. This keeps the stream open and the data flowing.

    How?

  • bruce February 25, 2005 9:17 AM

    Check on my comment dated 8/13/04 for the solution.

Leave a Comment

(required) 
(optional)
(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS