await using not working in net standard 2

I have an issue I can’t solve, I have a library with this definition

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0;net7.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
    <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
  </ItemGroup>
</Project>

And after a http call with HttpClient I try to do this :

await using var stream = await response.Content.ReadAsStreamAsync();

Which produce this error :

[CS8417] ‘Stream’: type used in an asynchronous using statement must be implicitly convertible to ‘System.IAsyncDisposable’ or implement a suitable ‘DisposeAsync’ method. Did you mean ‘using’ rather than ‘await using’?

The issue is clearly with NETSANDARD2_0, if I remove it, it works well.

I don’t understand why it fails, as I have added the Microsoft.Bcl.AsyncInterfaces.

>Solution :

The problem is that in .NET Standard 2.0, Stream doesn’t implement IAsyncDisposable.

It’s entirely feasible to use await using within a .NET Standard 2.0 project if you’re using types that actually implement IAsyncDisposable – although you also need to specify a LangVersion in the project file, as otherwise the default version of C# is used, which is 7.3 for .NET Standard 2.0. For example:

using System;
using System.IO;
using System.Threading.Tasks;

class Test
{
    static async void TestAwaitUsing()
    {
        // This is fine
        await using var working = new Sample();

        // This fails, because MemoryStream doesn't implement IAsyncDisposable
        await using var failing = new MemoryStream();
    }

    class Sample : IAsyncDisposable
    {
        public ValueTask DisposeAsync()
        {
            throw new NotImplementedException();
        }
    }
}

Project file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>latest</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
  </ItemGroup>

</Project>

Now it’s entirely possible that in whatever platform the code is running on, Stream does actually implement IAsyncDisposable – but it’s hard to make use of that in an elegant way.

For example, this compiles and will do the right thing if the application platform supports it:

await using var awkward = (IAsyncDisposable) new MemoryStream();
var stream = (MemoryStream) awkward;
// Now use things from stream

This will throw InvalidCastException if you’re running on a platform which doesn’t support it, however. If you can possibly change your target to .NET Standard 2.1 or a more recent one (e.g. .NET 6) that would be better. If you actually need to run your code with .NET Framework, you just won’t be able to use await using with Stream.

Leave a Reply