Skip to content

Weird UWP reference in unexpected places #1059

@petroemil

Description

@petroemil

The symptom

We ran into an interesting bug (?) recently, while updating our services to .NET Core we suddenly started receiving strange build errors, like:

The type 'IAsyncAction' is defined in an assembly that is not referenced. You must add a reference to assembly 'Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime'.

The type 'IAsyncActionWithProgress<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime'.

The type 'IAsyncOperation<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime'.

The type 'IAsyncOperationWithProgress<,>' is defined in an assembly that is not referenced. You must add a reference to assembly 'Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime'.

These errors were pointing to lines where we directly awaited IObservables, like

await Observable.Return("Hello World");

The clue

As I've been rigorously scanning through our dependencies and project file definitions, one thing stood out, that the System.Reactive NuGet package has a reference to System.Runtime.InteropServices.WindowsRuntime for netstandard2.0 target. ( link ).

This on its own though is not causing any immediate trouble...

The realization

I created a clean project with reference to Rx and tried to await an IObservable... and it worked just fine, so I figured, the issue will be somewhere else... So I started stripping down the dependencies from our original project, until it finally built successfully.

And then I found that because we migrated to .NET Core, we no longer had implicit access to certain Windows specific APIs, so we referenced Microsoft.Windows.Compatibility and by doing that we must have activated a special scenario for Rx's platform services, or something where it started to try to be WinRT compatible and give us those errors when trying to await on an IObservable.

The solution

The solution was to either reference the more specific compatibility packages, like System.Configuration.ConfigurationManager and System.ServiceProcess.ServiceController and/or to explicitly use the ToTask() extension method before attempting to await an IObservable.

The question

With all this, I'm still a little confused about why Rx has reference to WinRT Interop package for its .NET Standard (cross platform) target? I'd guess this weird issue would never have came up in the first place if it wouldn't have that reference.

Repro

csproj file

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Windows.Compatibility" Version="3.0.0" />
    <PackageReference Include="System.Reactive" Version="4.1.6" />
  </ItemGroup>

</Project>

Program.cs

using System;
using System.Reactive.Linq;
using System.Threading.Tasks;

namespace Repro
{
    class Program
    {
        static async Task Main(string[] args)
        {
            await Observable.Return("Hello World");
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions