Search code examples
async-awaitresharperusingc#-8.0

Resharper suggesting to convert Using statements to single "await Using"?


Resharper suggests to improve using statements with await key word to single line await using statements. As an example, the following code snippet :

    private async Task<string> ReadResponseAsync(HttpContext context)
    {
        var originalBody = context.Response.Body;

        try
        {
            using (var responseStream = new MemoryStream())
            {
                context.Response.Body = responseStream;
                await _next(context).ConfigureAwait(false);

                var response = context.Response;
                response.Body.Seek(0, SeekOrigin.Begin);

                using (var responseReader = new StreamReader(response.Body))
                { 
                    var responseContent = await responseReader
                    .ReadToEndAsync()
                    .ConfigureAwait(false);

                    response.Body.Seek(0, SeekOrigin.Begin);

                    await responseStream.CopyToAsync(originalBody)
                    .ConfigureAwait(false);
                    return responseContent;
                }
            }
        }
        finally
        {
            context.Response.Body = originalBody;
        }
    }

after applying successive Resharper suggestions the code becomes the following :

    private async Task<string> ReadResponseAsync(HttpContext context)
    {

        var originalBody = context.Response.Body;

        try
        {
            await using var responseStream = new MemoryStream();
            context.Response.Body = responseStream;
            await _next(context).ConfigureAwait(false);

            var response = context.Response;
            response.Body.Seek(0, SeekOrigin.Begin);

            using var responseReader = new StreamReader(response.Body);
            var responseContent = await responseReader
                .ReadToEndAsync()
                .ConfigureAwait(false);

            response.Body.Seek(0, SeekOrigin.Begin);

            await responseStream.CopyToAsync(originalBody)
                .ConfigureAwait(false);
            return responseContent;
        }
        finally
        {
            context.Response.Body = originalBody;
        }
    }

Are these two code snippets similar ? What is actually being improved here ? I am not understanding this feature of C# for using statements.


Solution

  • Two things changed when you accepted that recommendation:

    1. await using, which you can use on types that implement the new IAsyncDisposable. It's the same as the regular using, except it calls DisposeAsync() instead of Dispose().

    2. The change from a using block, to just a statement. This recommendation is just to minimize nesting in your code. Once the object falls out of scope, then Dispose()/DisposeAsync() is called. You can read more about it in the documentation.

    Those are two separate features that you can use independently of each other (you can use await using with a block, or use using as a statement), but both are brand new in the language.