Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RoslynCodeTaskFactory fails to load System.Text.Json #5737

Closed
wilsoncg opened this issue Sep 14, 2020 · 2 comments
Closed

RoslynCodeTaskFactory fails to load System.Text.Json #5737

wilsoncg opened this issue Sep 14, 2020 · 2 comments
Labels
bug needs-triage Have yet to determine what bucket this goes in.

Comments

@wilsoncg
Copy link

Issue Description

RoslynCodeTaskFactory fails to load System.Text.Json.

From my understanding, System.Text.Json is part of the .net core shared framework. Using the RoslynCodeTaskFactory with System.Text.Json should just work out of the box. This would enable a custom build step to output a valid JSON file.

I have .net Core 3.1.302 sdk installed, along with msbuild 16.6

Steps to reproduce

Create a custom inline task which attempts to use System.Text.Json serializer.

  • Create a new console project from template:

dotnet new console --language c# -o csprojthrowaway

  • Add the following to the .csproj file
<UsingTask
    TaskName="WriteJson"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
    <ParameterGroup>
      <Lines ParameterType="System.String[]" Required="true" />
      <JsonString ParameterType="System.String" Output="true" />
    </ParameterGroup>
    <Task>    
      <Code Type="Fragment" Language="cs">
<![CDATA[
var data = new { posts = new[] { "a" ,"b" } };
JsonString = System.Text.Json.JsonSerializer.Serialize(data);
]]>
      </Code>
    </Task>
  </UsingTask>
  <Target Name="Test" AfterTargets="Build">
    <WriteJson Lines="@()">
      <Output TaskParameter="JsonString" PropertyName="_JsonString" />
    </WriteJson>
    <Message Text="Run = $(_JsonString)" Importance="High" />
  </Target>
  • Attempt to build

dotnet build -t:rebuild -v minimal .\csprojthrowaway.csproj

Expected behaviour

msbuild should correctly compile the auto generated csharp, execute the .cs file and return a JSON string.

Actual behaviour

msbuild reports error, Json namespace cannot be resolved:

tmp1B37.tmp(59,14): error CS0234: The type or namespace name 'Json' does not exist in the namespace 'System.Text' (are you missing an assembly reference?) [D:\Projects\web\csprojthrowaway\csprojthrowaway.csproj]
csprojthrowaway.csproj(32,5): error : The source file for this compilation can be found at: "C:\Users\craig\AppData\Local\Temp\tmp1B37.tmp"
csprojthrowaway.csproj(32,5): error MSB4175: The task factory "RoslynCodeTaskFactory" could not be loaded from the assembly "C:\Program Files\dotnet\sdk\3.1.302\Microsoft.Build.Tasks.Core.dll". The task factory must return a value for the "TaskType" property.

If we attempt to add reference <Reference Include="System.Text.Json" /> results in a different error:

tmpF393.tmp(59,46): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. [D:\Projects\web\csprojthrowaway\csprojthrowaway.csproj]

If we attempt to add reference <Reference Include="System.Runtime" /> we reach the end of the line:

csprojthrowaway.csproj(30,5): error MSB3755: Could not find reference "System.Runtime". If this reference is required by your code, you may get compilation errors.

Background context

MSDN Documentation for MSBuild states

RoslynCodeTaskFactory uses the cross-platform Roslyn compilers to generate in-memory task assemblies for use as inline tasks. RoslynCodeTaskFactory tasks target .NET Standard and can work on .NET Framework and .NET Core runtimes

MSDN Documentation for System.Text.Json states

The library is built-in as part of the .NET Core 3.0 shared framework.

Version information

Microsoft (R) Build Engine version 16.6.0+5ff7b0c9e for .NET Core
C:\Program Files\dotnet\sdk\3.1.302\Microsoft.Build.Tasks.Core.dll

PS D:\Projects\web\csprojthrowaway> dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   3.1.302
 Commit:    41faccf259

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19041
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.1.302\

Host (useful for support):
  Version: 5.0.0-preview.7.20364.11
  Commit:  53976d38b1

.NET SDKs installed:
  1.1.13 [C:\Program Files\dotnet\sdk]
  2.0.2 [C:\Program Files\dotnet\sdk]
  2.1.4 [C:\Program Files\dotnet\sdk]
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.300 [C:\Program Files\dotnet\sdk]
  2.1.403 [C:\Program Files\dotnet\sdk]
  2.1.602 [C:\Program Files\dotnet\sdk]
  2.2.203 [C:\Program Files\dotnet\sdk]
  3.0.100 [C:\Program Files\dotnet\sdk]
  3.1.100 [C:\Program Files\dotnet\sdk]
  3.1.302 [C:\Program Files\dotnet\sdk]
  5.0.100-preview.7.20366.6 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.1.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.0-preview.7.20365.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 1.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.0-preview.7.20364.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.0-preview.7.20366.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Binlog

msbuild.binlog.zip

@wilsoncg wilsoncg added bug needs-triage Have yet to determine what bucket this goes in. labels Sep 14, 2020
@jeffkl
Copy link
Contributor

jeffkl commented Sep 15, 2020

At the moment this is by design. The RoslynCodeTaskFactory compiles your code against .NETStandard2.0 for maximum compatibility. .NET Standard 2.0 is supported on .NET Framework v4.7.2+ and .NET Core 2.0+. If RoslynCodeTaskFactory compiled your task against .NET Core 3.0 so it could use System.Text.Json, the task would fail to run on .NET Framework MSBuild (MSBuild.exe).

This could get your code base into a state where it builds for you but not on someone else's machines with a different runtime.

https://docs.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support

.NET Framework won't support .NET Standard 2.1 or later versions. For more details, see the announcement of .NET Standard 2.1.

Even if you compiled an actual task assembly against netstandard2.1 or netcoreapp3.0, it would fail when running under MSBuild.exe.

For example:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Build" Version="16.6.0" ExcludeAssets="Runtime" />
    <PackageReference Include="Microsoft.Build.Framework" Version="16.6.0" ExcludeAssets="Runtime" />
    <PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.6.0" ExcludeAssets="Runtime" />
    <PackageReference Include="System.Text.Json" Version="4.7.2" ExcludeAssets="Runtime" />
  </ItemGroup>
</Project>

This fails to restore even since Microsoft.Build doesn't support netstandard2.1. But it will work under .NET Core 3.0+:

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Text.Json;

namespace netstandard21tasklibrary
{
    public class MyTask : Task
    {
        public override bool Execute()
        {
            JsonDocument document = JsonDocument.Parse("{\"Foo\": \"Bar\"}");

            foreach (JsonProperty jsonProperty in document.RootElement.EnumerateObject())
            {
                Log.LogMessage(MessageImportance.High, $"{jsonProperty.Name}: {jsonProperty.Value}");
            }

            return !Log.HasLoggedErrors;
        }
    }
}
C:\>dotnet msbuild netstandard21task.proj
Microsoft (R) Build Engine version 16.8.0-preview-20451-02+51a1071f8 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Foo: Bar

It fails under .NET Framework MSBuild.exe since that only targets .NET Framework v4.7.2:

D:\>msbuild D:\netstandard21task.proj
Microsoft (R) Build Engine version 16.8.0-preview-20452-03+5dee11854 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 9/14/2020 4:55:57 PM.
Project "D:\netstandard21task.proj" on node 1 (default targets).
D:\netstandard21task.proj(4,5): error MSB4018: The "MyTask" task failed unexpectedly.
D:\netstandard21task.proj(4,5): error MSB4018: System.IO.FileNotFoundException: Could not load file or assembly 'System.Text.Json, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2dd
d51' or one of its dependencies. The system cannot find the file specified.
D:\netstandard21task.proj(4,5): error MSB4018: File name: 'System.Text.Json, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
D:\netstandard21task.proj(4,5): error MSB4018:    at netstandard21tasklibrary.MyTask.Execute()
D:\netstandard21task.proj(4,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
D:\netstandard21task.proj(4,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext()
D:\netstandard21task.proj(4,5): error MSB4018:
D:\netstandard21task.proj(4,5): error MSB4018: WRN: Assembly binding logging is turned OFF.
D:\netstandard21task.proj(4,5): error MSB4018: To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
D:\netstandard21task.proj(4,5): error MSB4018: Note: There is some performance penalty associated with assembly bind failure logging.
D:\netstandard21task.proj(4,5): error MSB4018: To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].
D:\netstandard21task.proj(4,5): error MSB4018:
Done Building Project "D:\netstandard21task.proj" (default targets) -- FAILED.


Build FAILED.

So until .NET Framework has the necessary assemblies for .NET Standard 2.1, we can't update RoslynCodeTaskFactory to compile task assemblies against anything but .NET Standard 2.0.

The only workaround is to compile your task assembly and ship System.Text.Json in a package along side it. This will make MSBuild load System.Text.Json when loading your task.

@wilsoncg
Copy link
Author

Ah right. Thanks for the very detailed explanation.
I had to read it a couple of times to put the pieces in place, but your examples & output helped greatly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug needs-triage Have yet to determine what bucket this goes in.
Projects
None yet
Development

No branches or pull requests

2 participants