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

Version 2.0.0 causes error : MSB4801: The task factory "CodeTaskFactory" is not supported on the .NET Core version of MSBuild. #51

Closed
ManfredLange opened this issue Jun 11, 2018 · 11 comments

Comments

@ManfredLange
Copy link

ManfredLange commented Jun 11, 2018

Problem

We have a library project (SDK csproj file format) that targets net462. It uses PackageReference, not packages.config.

When we add nuget package microsoft.codedom.providers.dotnetcompilerplatform version 2.0.0 to this project it builds fine within VS2017 v15.7.3. However, we get the following error when compiling the project with command dotnet build from a command line (e.g. PowerShell):

error : MSB4801: The task factory "CodeTaskFactory" is not supported on the .NET Core version of MSBuild

The project also references package Microsoft.Net.Compilers version 2.8.2. PowerShell is version 5.1.17134.48. We have installed dotnet SDK version 2.1.300. This is reported both in VS and in the PowerShell. This is also the version we have in the solution's global.json file.

Steps To Reproduce

  1. Install .NET SDK 2.1 (v2.1.300)
  2. Using Visual Studio 2017, version 15.7.3, create empty solution
  3. Add a sample netstandard 2.0 class library, e.g. SampleLib.csproj
  4. Edit the csproj file to target net462 instead of netstandard2.0
  5. Add nuget package Microsoft.CodeDom.Providers.DotNetCompilerPlatform version 2.0.0
  6. Build project within VS => success
  7. Open Powershell in folder containing the csproj file
  8. Execute dotnet build SampleLib.csproj => build fails with the error reported in this issue

The only workaround we found is falling back to using msbuild instead of dotnet build. We would prefer the latter. Note that our actual project is one of a set of about 75 projects. All others build fine with dotnet build.

Is there a workaround / resolution for this? What else can we try/test to diagnose/resolve this?

@Jinhuafei
Copy link
Contributor

@ManfredLange Thanks for reporting the issue. A new task which relies on CodeTaskFactory was added to make sure Roslyn compiler service is terminated before copying Roslyn bits. The DotNetCompilerPlatform package currently doesn't work dotnet build yet, but here is a hacky way to workaround the issue. You can add following target to the samplelib.csproj.

<Target Name="CheckIfShouldKillVBCSCompiler" />

BTW, all the targets used in DotNetCompilerPlatform nupkg are for Roslyn bits deployment(copying to bin folder) and I don't think they are working with packagereference currently. How do you deploy the Roslyn bits? Also how DotNetCompilerPlatform is used in your project?

@ManfredLange
Copy link
Author

ManfredLange commented Jun 12, 2018

Yes, I can confirm your workaround resolves the problem in the sample project. It didn't resolve it in our actual production project where it perhaps never gets to the target due to compile errors caused by other issues when mixing new/old project file formats.

We have converted all of our projects from packages.config to PackageReference and that works just fine. It is my understanding that this is the recommended way to references nupkg'es. PackageReference has also been backported to the old format csproj (of which we still have one left).

In the sample project PackageReference also works in that we can manually delete the roslyn folder in the output directory and the rerun dotnet build successfully. The roslyn folder will be recreated with your workaround in place.

To answer your questions: In our case the latest version (2.0.0) of DotNetCompilerPlatform nupkg copies the Roslyn binaries to $(TargetDir)/roslyn. We use DotNetCompilerPlatform in an ASP.NET MVC (old style, target full .NET framework, i.e. net462). We are using new C# features in the Razor views/partials. The challenge begins with rendering partials to string containing HTML that are part of AJAX call responses. We want to test those in isolation by instantiating the controller then invoking the method that handles the AJAX request. Obviously there is not proper Razor engine so we use Westwind.RazorHosting for rendering partials. This package has just been amended to work with Roslyn thanks to @RickStrahl. To make it work, though, the following needs to be added to the config file of the assembly using Roslyn - Web.config - in our case as well as in the config file for the project containing the tests (app.config on our case):

   <system.codedom>
      <compilers>
         <compiler language="c#;cs;csharp" extension=".cs"
           type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
           warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/>
         <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
           type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
           warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
      </compilers>
   </system.codedom>

This addition is a suggestion by Rick Strahl @RickStrahl. See this issue for details.

In addition to that in the old style ASP.NET MVC project we also had to reference Microsoft.Net.Compilers (version 2.8.2 as of writing) which - theoretically - should not be required as building it would not create the Roslyn folders and binaries in the output folder. By having the reference to this package the Roslyn binaries will be deployed, too.

Bottom line: We want to test rendering of partials by instantiating the controller and then invoking the appropriate method from a unit test. The same method therefore needs to run both within ASP.NET MVC hosting (i.e. valid HttpContext) as well as outside of it. Using Westwind.Razorhosting allows us to do just that. Roslyn is required because we use new C# features within views/partials, e.g. string interpolation.

I'm sure there are ways to do all of this better. However, we have a fairly large code base and for many changes we need incremental approaches, e.g. converting 77 projects in a single solution from old to new project file format, from packages.config to PackageReference or moving from net462 to netstandard2.0/netcoreapp2.1, or moving from "ASP.NET MVC 5" to "ASP.NET Core MVC".

@ManfredLange
Copy link
Author

@Jinhuafei Further to this: We experience this issue at the moment in two project of our code base. We were able to resolve it in one case with your workaround. As mentioned in my previous post, it didn't seem to work for the other one. We'll continue to experiment.

@Jinhuafei
Copy link
Contributor

Thanks for the detail. If you can provide build log(-v diag), I can take a look.

@CZEMacLeod
Copy link

@Jinhuafei Since there is now a RoslynCodeTaskFactory in the latest SDK is it possible/worth switching to use that?

@Jinhuafei
Copy link
Contributor

@CZEMacLeod haven't tried this yet. This may be an option. But we can't just swtich to that, since there are tons of developers still using older version.

@BobMaurer
Copy link

I encountered the same issue and your workaround has fixed me.

Will there ever be a non hacky solution to this?

@WeihanLi
Copy link

WeihanLi commented Jun 4, 2019

Any update here?

StefH added a commit to WireMock-Net/WireMock.Net that referenced this issue Aug 17, 2019
StefH added a commit to WireMock-Net/WireMock.Net that referenced this issue Sep 28, 2019
* wip

* fix

* .

* windows-2019

* <Target Name="CheckIfShouldKillVBCSCompiler" />

* <!--aspnet/RoslynCodeDomProvider#51>

* AllowCSharpCodeMatcher

* CSharpCodeMatcher : IObjectMatcher

* TemplateForIsMatchWithDynamic

* RequestMessageBodyMatcher_GetMatchingScore_BodyAsJson_CSharpCodeMatcher

* fix

*  }

* Better Exception Handling
@StephenMolloy
Copy link
Contributor

I believe #92 will address this issue.

@StephenMolloy
Copy link
Contributor

Should be fixed by #92

jonpryor pushed a commit to xamarin/java.interop that referenced this issue Apr 30, 2020
How do we test the C# output of `generator`?

*A* way is to check the output against "known good" files, which we do.

*Another* way is to use a compiler to ensure that the output compiles,
which we *also* do.

Unfortunately, the "just compile it!" approach has a major flaw, as
the easiest accessible C# compiler is
`Microsoft.CSharp.CSharpCodeProvider`, for use with System.CodeDom,
but *on Windows* `CSharpCodeProvider` only supports up to C# 5.

`generator`, meanwhile, may currently produce C# 8 output.

This conundrum was addressed in commit 968b474 by using the
[Microsoft.CodeDom.Providers.DotNetCompilerPlatform][0] NuGet package
when running on Windows, as that supported C#6+.

Unfortunately, `DotNetCompilerPlatform` does *not* run under .NET Core,
because it uses the MSBuild `CodeTaskFactory` which is not available on
.NET Core.  ([This issue has been fixed][1]; the fix is unreleased.)

Now that we support multitargeting net471 and netcoreapp3.1 (95f698b),
we would like to be able to build *and run* our unit tests under
.NET Core as well as Mono (macOS) or .NET Framework (Windows).

Migrate away from the `DotNetCompilerPlatform` NuGet package and
instead use the [Microsoft.CodeAnalysis.CSharp][2] NuGet package,
which contains an up-to-date C#8 Roslyn compiler.  This new package
supports .NET Core; we just need to update `Compiler.Compile()` to
work in terms of Roslyn SyntaxTrees instead of CodeDom objects.

This allows us to run the `generator` unit tests under .NET Core:

	dotnet test bin\TestDebug\generator-tests.dll

[0]: https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/
[1]: aspnet/RoslynCodeDomProvider#51
[2]: https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp/
jonpryor pushed a commit to xamarin/java.interop that referenced this issue May 6, 2020
How do we test the C# output of `generator`?

*A* way is to check the output against "known good" files, which we do.

*Another* way is to use a compiler to ensure that the output compiles,
which we *also* do.

Unfortunately, the "just compile it!" approach has a major flaw, as
the easiest accessible C# compiler is
`Microsoft.CSharp.CSharpCodeProvider`, for use with System.CodeDom,
but *on Windows* `CSharpCodeProvider` only supports up to C# 5.

`generator`, meanwhile, may currently produce C# 8 output.

This conundrum was addressed in commit 968b474 by using the
[Microsoft.CodeDom.Providers.DotNetCompilerPlatform][0] NuGet package
when running on Windows, as that supported C#6+.

Unfortunately, `DotNetCompilerPlatform` does *not* run under .NET Core,
because it uses the MSBuild `CodeTaskFactory` which is not available on
.NET Core.  ([This issue has been fixed][1]; the fix is unreleased.)

Now that we support multitargeting net471 and netcoreapp3.1 (95f698b),
we would like to be able to build *and run* our unit tests under
.NET Core as well as Mono (macOS) or .NET Framework (Windows).

Migrate away from the `DotNetCompilerPlatform` NuGet package and
instead use the [Microsoft.CodeAnalysis.CSharp][2] NuGet package,
which contains an up-to-date C#8 Roslyn compiler.  This new package
supports .NET Core; we just need to update `Compiler.Compile()` to
work in terms of Roslyn SyntaxTrees instead of CodeDom objects.

This allows us to run the `generator` unit tests under .NET Core:

	dotnet test bin\TestDebug\generator-tests.dll

[0]: https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/
[1]: aspnet/RoslynCodeDomProvider#51
[2]: https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp/
@michaelakin
Copy link

I guess this error in a VS 2019 project when I compile from the command line on a 2.2 and 3.1 project, but if I change the configuration to "Release it builds fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants