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

.NET Core MSBuild cannot load tasks built against MSBuild 4.0 #2111

Closed
ghost opened this issue May 19, 2017 · 11 comments
Closed

.NET Core MSBuild cannot load tasks built against MSBuild 4.0 #2111

ghost opened this issue May 19, 2017 · 11 comments

Comments

@ghost
Copy link

ghost commented May 19, 2017

It seems that the dependencies of a task DLL built with VS2015 cannot be loaded when using those tasks in dotnet msbuild. Here's a reproducer using simple dummy files.

A primitive custom task, SimpleTaskThatExtends:

using Microsoft.Build.Utilities;

namespace SimpleTaskLibrary
{
    public class SimpleTaskThatExtends : Task
    {
        public override bool Execute()
        {
            Log.LogMessage("Simple task that extends Task");
            return true;
        }
    }
}

A primitive targets file using the above task:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <UsingTask TaskName="SimpleTaskThatExtends" AssemblyFile=".\bin\debug\SimpleTaskThatExtends.dll" />

  <Target Name="dummy">
    <SimpleTaskThatExtends />
  </Target>

</Project>

msbuild works:

msbuild /t:dummy Simple.targets

I get:

Microsoft (R) Build Engine version 15.1.548.43366
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 5/19/2017 10:42:08 AM.
Project "C:\Users\me\Documents\Visual Studio 2015\Projects\SimpleTaskLibrary\SimpleTaskLibrary\Simple.targets
" on node 1 (dummy target(s)).
dummy:
  Simple task that extends Task
Done Building Project "C:\Users\me\Documents\Visual Studio 2015\Projects\SimpleTaskLibrary\SimpleTaskLibrary\
Simple.targets" (dummy target(s)).


Build succeeded.
    0 Warning(s)
    0 Error(s)

The same command but run through dotnet doesn't work:

dotnet msbuild /t:dummy Simple.targets

I get:

Microsoft (R) Build Engine version 15.1.1012.6693
Copyright (C) Microsoft Corporation. All rights reserved.

C:\Users\me\Documents\Visual Studio 2015\Projects\SimpleTaskLibrary\SimpleTaskLibrary\Simple.targets(9,5): error MSB4062: The "SimpleTaskThatExtends" task could not be loaded from the assembly C:\Users\me\Documents\Visual Studio 2015\Projects\SimpleTaskLibrary\SimpleTaskLibrary\.\bin\debug\SimpleTaskThatExtends.dll. Could not load file or assembly 'Microsoft.Build.Utilities.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified. Confirm that the <UsingTask> declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.

If instead of extending Task in Microsoft.Build.Utilities I implement ITask in Microsoft.Build.Framework, then it works because it doesn't need to load Microsoft.Build.Utilities.v4.0.

I tried copying Microsoft.Build.Utilities.Core.* (.dll and .xml) in the same directory as the task dll. I tried both the net46 and netstandard1.3 versions. But the output is exactly the same.

I've read #658 and I was under the impression that the problem there and in #858 was fixed in 15.1.1012, which is the version I have (as you can see in the last output).

The bigger picture is that I have a task library that I would like to use in the builds of both VS2015 and .NET Core projects. I would rather not have two versions of the tasks. Is there something fundamentally wrong with that?

@ghost
Copy link
Author

ghost commented May 23, 2017

The short answer is that this is only the tip of the iceberg.

I could get past this error by removing the Microsoft.Build.Utilities.v4.0 reference,
and adding instead the Microsoft.Build.Utilities NuGet dependency.

That solved the issue in the simplified reproducer I posted here, but in my real application I got further strange errors like:

error MSB4018: System.IO.FileNotFoundException: Could not load file or assembly 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. The system cannot find the file specified.

This and the original errors are just a symptom of a bigger problem: it's not safe to execute via dotnet applications that were built in <=VS2015 targeted for .NET Framework instead of .NET Core. When executed by dotnet, the runtime has a subset of .NET Framework features, and when the application tries to use something not in the runtime, it will of course crash. In my example my code is some Task implementations compiled with VS2015, executed as part of dotnet msbuild.

The solution seems to be to convert my .NET Framework application to .NET Core.

@ghost ghost closed this as completed May 23, 2017
@dasMulli
Copy link
Contributor

dasMulli commented May 23, 2017

Your best option probably is multitargeting your tasks to a version of .net standard / .net core and .net framework like this and then use a different assembly based on $(MSBuildRuntimeType) (UsingTask example.

@ManfredLange
Copy link

ManfredLange commented Sep 19, 2017

@dasMulli Looks as if both of the links provided in your latest comment are now broken. Do you have updated links for your suggestion?

@dasMulli
Copy link
Contributor

dasMulli commented Sep 20, 2017

too bad.. updated them to permalinks

@praeclarum
Copy link

Hello, is there a fix for this? There are a lot of nuget DLLs that don't work int dotnet because of this.

@jamesmontemagno
Copy link
Member

jamesmontemagno commented Dec 31, 2017

I was able to dig through: dotnet/efcore#8336

And add this:

<PackageReference Include="Xamarin.Forms" Version="2.4.0.38779">
      <ExcludeAssets>build</ExcludeAssets>
    </PackageReference>

I could build originally via msbuild, but not dotnet build due to this, which caused issues in VSTS for building. After adding this, it got farther, but since I have xaml pages in there it seems to fail to generate anything :(

@jrahma
Copy link

jrahma commented May 31, 2018

i keep getting:

/Users/jassim/.nuget/packages/xamarin.forms/2.4.0.280/build/netstandard1.0/Xamarin.Forms.targets(3,3): Error MSB4062: The "Xamarin.Forms.Build.Tasks.FixedCreateCSharpManifestResourceName" task could not be loaded from the assembly /Users/jassim/.nuget/packages/xamarin.forms/2.4.0.280/build/netstandard1.0/Xamarin.Forms.Build.Tasks.dll. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask. (MSB4062) (ZayedAlKhair)

@taori
Copy link

taori commented Aug 10, 2018

Same problem while loading C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Xamarin\iOS\Xamarin.iOS.Tasks.dll

chrisdunelm added a commit to chrisdunelm/google-api-dotnet-client that referenced this issue Aug 21, 2018
.NET SDK 2.1 introduces a problem when depending on packages that contain build tasks built with pre-VS2017 tooling. This is a work-around which excludes the problematic tasks. See dotnet/msbuild#2111
chrisdunelm added a commit to googleapis/google-api-dotnet-client that referenced this issue Aug 21, 2018
.NET SDK 2.1 introduces a problem when depending on packages that contain build tasks built with pre-VS2017 tooling. This is a work-around which excludes the problematic tasks. See dotnet/msbuild#2111
@Legends
Copy link

Legends commented Jul 13, 2020

@dasMulli

Your best option probably is multitargeting your tasks to a version of .net standard / .net core and .net framework ....

Just one little question:
Why use multi-targeting here? Isn't using netstandard20 enough?
It should run on all platforms using netstandard20 only?!

@dasMulli
Copy link
Contributor

Why use multi-targeting here? Isn't using netstandard20 enough?
It should run on all platforms using netstandard20 only?!

At least at the time of writing (2017) i believe VS didn't carry all necessary forwarding assemblies to load and run netstandard2.0 dlls. I believe this has now been mostly done, maybe @rainersigwald can comment on that.

(Basically when you reference a .NET Standard assembly / project, the build system will add some additional dlls for older versions of .NET Framework. Applications not built with this logic needed to add these assemblies manually in order to load .NET Standard assemblies).

Also do note that some Tasks like(d) to do some form of isolation using AppDomain on .NET Framework or AssemblyLoadContext on .NET Core so they needed to target both frameworks in order to use these specific APIs (e.g. to load a different version of Newtonsoft.Json than is included in Visual Studio).

@rainersigwald
Copy link
Member

.NET 4.7.2+ (which is now required by MSBuild) does handle netstandard2.0 assemblies pretty well. If your task has no dependencies, you can usually get away with just a .NET Standard implementation. When referencing other libraries, especially but not limited to native code, things can get hairy, and multitargeting is often still required.

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

No branches or pull requests

9 participants