2

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();
        }
AndyP
  • 527
  • 1
  • 14
  • 36
  • Why believe us? https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement – TheGeneral Sep 06 '21 at 03:58
  • In regards to your particular situation `context.Request.Body` will be disposed regardless as its owned and managed by the framework. Stream reader can take a construction overload to keep the stream open, though its not really useful here. Further more, since this is likely json there are other ways to achieve this, i.e. passing the stream/body directly to a json deserializer (among others). – TheGeneral Sep 06 '21 at 04:06
  • There's a new using syntax that might make for less broken up/nested code: `using var reader = new StreamReader(...); var json = reader.Read...`. Check it out – Caius Jard Sep 06 '21 at 05:50
  • You can probably skip all this low level string/reader finagling by the way and have the http request unpack your json to a class for you, see https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httprequestjsonextensions.readfromjsonasync?view=aspnetcore-5.0#Microsoft_AspNetCore_Http_HttpRequestJsonExtensions_ReadFromJsonAsync__1_Microsoft_AspNetCore_Http_HttpRequest_System_Threading_CancellationToken_ – Caius Jard Sep 06 '21 at 06:05
  • 1
    Although I agree that this is a question regarding `using`. I do think that this question specifically asks how to handle `using` with `HttpRequest`, thus make it more specific than the suggested duplicate. – smoksnes Sep 06 '21 at 06:23

2 Answers2

3

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.

smoksnes
  • 10,509
  • 4
  • 49
  • 74
  • 1
    Maybe chuck a bit in about having the request deser on your behalf - https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httprequestjsonextensions.readfromjsonasync?view=aspnetcore-5.0#Microsoft_AspNetCore_Http_HttpRequestJsonExtensions_ReadFromJsonAsync__1_Microsoft_AspNetCore_Http_HttpRequest_System_Threading_CancellationToken_ - beats buying a dog and barking ones self ! – Caius Jard Sep 06 '21 at 06:05
  • 1
    Thanks! I actually looked for this since I knew that I used it somewhere. But couldn't find it. I'll add it to my answer. – smoksnes Sep 06 '21 at 06:07
0

Check out this link

https://www.c-sharpcorner.com/UploadFile/manas1/usage-and-importance-of-using-in-C-Sharp472/

In short: "using" statement ensures that managed/unmanaged resource object disposes correctly and you don't have to call "Dispose" method explicitly even there is any execeptions occured within the using block

You can read further from Microsoft official site too

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement#:~:text=The%20using%20statement%20calls%20the,t%20be%20modified%20or%20reassigned.

Niyas Ali
  • 203
  • 2
  • 9