Search code examples
c#asp.net-corestreamreaderusing

StreamReader with using statement difference?


I am using StreamReader as shown below in my code:

string json = await new StreamReader(context.Request.Body).ReadToEndAsync();
// ... use json variable here in some other code

And I stumbled upon using statement. Is there any difference between my first statement vs using the using statement with StreamReader?

Should I be using using statement with StreamReader here in prod code?

        string json;
        using (var reader = new StreamReader(context.Request.Body))
        {
            json = await reader.ReadToEndAsync();
        }

Solution

  • Is there any difference between my first statement vs using the using statement with StreamReader

    Yes. The difference is that when you wrap StreamReader in a using statement it will clear up some resources directly instead of waiting for the garbage collector. More specifically it will call Dispose() on StreamReader. You should almost always use using when the class implements IDisposable.

    If your app simply uses an object that implements the IDisposable interface, you should call the object's IDisposable.Dispose implementation when you are finished using it.

    Thanks to .NET Core being open source we can take a look at the source for StreamReader:

    protected override void Dispose(bool disposing)
    {
        if (m_stream != null)
        {
            if (disposing)
            {
                m_stream.Close();
            }
    
            m_stream = null;
            m_buffer = null;
            m_curBufPos = 0;
            m_curBufLen = 0;
        }
    
        m_disposed = true;
    }
    

    As you can see it calls Close() on the stream, which (according to the docs) in turn will call Dispose() on the stream itself.

    Correctly disposing objects can be crucial when working with larger objects or streams. However, I will try to target your other question.

    Should I be using using statement with StreamReader here in prod code?

    Yes, no and maybe. In your partical case you have a context.Request.Body as a Stream (which I assume is from HttpContext). There is no need for the StreamReader to close that particular stream. It will be disposed correctly (later) anyway. Also, there might be some other resource that need access to that particual stream later in the pipeline.

    Generally, if the class implements IDisposable then you should wrap it in a using. But here I think that you have two better choices:

    1. If you actually have a json (as your variable suggest), you can deserialize it directly using JsonSerializer found in System.Text.Json.JsonSerializer:

    YourModel model = await System.Text.Json.JsonSerializer.DeserializeAsync<YourModel>(context.Request.Body);
    

    UPDATE: Or if you are using .NET 5 you have access to HttpResponseJsonExtensions and can use ReadFromJsonAsync. Then you can simply try the following:

    YourModel model = await context.Request.ReadFromJsonAsync<YourModel>();
    

    Thanks to caius-jard.

    2. Use the overload of StreamReader that doesn't close the stream.

    string json;
    using (var reader = new StreamReader(stream, Encoding.UTF8, true, -1, true))
    {
        json = await reader.ReadToEndAsync();
    }
    

    So, to sum up. Yes, there is a difference when using using. However, in your particular case you have better options.