Visual Studio 2017 MSBuild Task Development - msbuild

With developing an custom MSBuild Task with Visual Studio 2017 RC, I have the following problem: As soon as I add other dependencies than just Microsoft.Build.Utilities.Core (using v15.1.0-preview-000458-02 for .NET Core Support), I cannot load the task into another .csproj MSBuild project as the dependencies are not found.
Is there a way to automatically copy all dependencies to the Debug folder?
Or do I have to publish it every time I want to test it?
Update1:
The problem with publish was something local to my environment and has been fixed.
Update2:
It seems that as soon as I change the TargetFramework from netstandard1.4 to netstandard1.6 it isn't even able to load the task at all. As soon as I use netstandard 1.6 it throws a an exception:
The task could not be loaded from the assembly.
Could not load file or assembly 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its
dependencies.

Is there a way to automatically copy all dependencies to the Debug folder? Or do
I have to publish it every time I want to test it?
By default and for good reasons, .NET Core and .NET Standard projects do not copy referenced assemblies into the build folder. Instead, they are resolved them from the NuGet cache.
But if you really need it, this behavior can be changed by overriding the default with the CopyLocalLockFileAssemblies setting.
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Cref: https://github.com/dotnet/sdk/blob/d20405f91a2959fa91fea6285d9a896286727f2a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Sdk.BeforeCommon.targets#L55-L56
Second question
It seems that as soon as I change the TargetFramework from netstandard1.4 to netstandard1.6
To build a task assembly that works on both "MSBuild.exe" and "dotnet.exe msbuild", you should target netstandard1.4 or lower. netstandard1.6 is not compatible with .NET Framework 4.6.1 (which MSBuild.exe runs on.)
If you need API not available in netstandard1.4, you will need to cross-compile your task for .NET Framework and .NET Standard, which is considerably more complex but can be done.

Related

VS 2017 .NetCore MSBuild custom task fails to load Newtonsoft.Json or other dependents

Environment
Visual Studio 2017
.NET Standard 2.0
.NET Framework 4.6.1
MyCustomTask.csproj contains custom MS build tasks and has multi targets to generate a separate dll for .NET Full and .NEt Core runtime.
There is a 3 level dependency on the Nuget Package "Microsoft.Extensions.Configuration.Json" which in turn has a dependency to Newtonsoft.Json package. as shown below.
The build is all fine and the Nuget package for MyCustomTask is generated successfully.
When I install my MyCustomTask Nuget package on target project then the custom build task is getting successfully executed on .NET Full runtime from Visual Studio 2017, but for .NET Core dotnet build command fail to execute the custom build task...
System.IO.FileLoadException: Could not load file or assembly 'Newtonsoft.Json, Version=10.0.0.0, Culture=neutral.
Even if I package all the dependent DLL and place it in same directory of the .netstandard custom task dll I keep getting same error.
Any thoughts how this can be resolved ?
Posting a solution here for those who are experiencing the same issue.
Credit to #MartinUllrich for posting the solution in a comment above. This saved me a lot of trouble.
https://github.com/AArnott/Nerdbank.MSBuildExtension
Ensure your custom task inherits from ContextIsolatedTask and copy the dependent assemblies to same directory as your task assembly.

Distribute custom MS Build Task with .NET Standard and VS 2017 via Nuget

I have a .NET Standard library (1.4) VS 2017 project that contains custom MS Build task (MyTask) that need to be distributed via Nuget package (Let's say MyCustomTask.dll and it contains MyTask and Portable.targets that will be imported by target project)
This Nuget package with custom build task is then used by target .NET Standard (1.4) project cspro file to import the Portable.targets that invoke the Custom Build task.
However, at this point I keep on getting the build error
Could not load file or assembly 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.
I tried .NET Standard (1.4, 1.5 and 1.6) but same error.
The problem is that the consuming application, MSBuild.exe in this case, would need to include all the forwarding assemblies necessary to run netstandard tasks (e.g. depend on the NETStandard.Library).
The best solution in this case is multi-targeting the task library to a .net framework and a .net standard target framework:
<TargetFrameworks>netstandard1.6;net46</TargetFrameworks>
The idea is to have 2 dlls that will contain the task. In the project files contained in the NuGet package instead of using a dll path directly in <UsingTask>, the idea is to using a different dll file based on the $(MSBuildRuntimeType) property, which will be Core on the .NET Core version of MSBuild:
<PropertyGroup>
<_CustomTaskAssemblyTFM Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard1.6</_CustomTaskAssemblyTFM>
<_CustomTaskAssemblyTFM Condition="'$(MSBuildRuntimeType)' != 'Core'">net46</_CustomTaskAssemblyTFM>
<_CustomTaskAssembly>$(MSBuildThisFileDirectory)..\tools\$(_CustomTaskAssemblyTFM)\CustomTaskAssemblyName.dll</_CustomTaskAssembly>
</PropertyGroup>
<UsingTask TaskName="SomeCustomTask" AssemblyFile="$(_CustomTaskAssembly)" />
You can see examples of this in the asp.net core build tools and the .NET Core SDK.

TFS and Microsoft.common.targets assembiles out of sync VS2015

I just upgraded my TFS source to use DevExpress 15.2.5. However, now I get a bunch of warnings in the output such as
C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(1819,5): warning MSB3274: The primary reference "C:\Users\User1\Source\Release\V6.1\CommonBin\Release\WebControls.dll" could not be resolved because it was built against the ".NETFramework,Version=v4.5" framework. This is a higher version than the currently targeted framework ".NETFramework,Version=v3.5".
and
C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(1819,5): warning MSB3275: The primary reference "C:\Users\User1\Source\Release\V6.1\CommonBin\Release\WebControls.dll" could not be resolved because it has an indirect dependency on the assembly "DevExpress.Data.v15.2, Version=15.2.5.0, Culture=neutral, PublicKeyToken=7ea533hgx2169hs3" which was built against the ".NETFramework,Version=v4.0,Profile=Client" framework. This is a higher version than the currently targeted framework ".NETFramework,Version=v3.5".
along with about 30 other similar warnings.
It's obvious that something is out of sync with my assemblies because they are referencing the wrong versions. So I looked at my TFS project .csproj file. The version of DevExpress and .NET framework that are being referenced in there are correct.
I then went to the Microsoft.Common.targets file and opened in Notepad. I noticed that file is referencing the old version of everything. How do I get this in sync with my TFS assemblies?
It looks like you need to change your project to use the .NET framework version 4.5 on the project properties page:
Word of warning this may result in more warnings or errors depending on the .NET APIs you use.

Compile .net 4.0 project on build server with .net 4.5

We're having the seemingly common error
Could not load type 'System.Runtime.CompilerServices.ExtensionAttribute' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
in a project that needs to be compiled against .Net 4.0 but is built on a build server running Windows Server 2012 (with .Net 4.5). The project is a web application that gets deployed to a web server running 2003, where installing .Net 4.5 isn't an option. There it runs against "classic" .Net 4.0
From similar questions, we're trying command-line options to MSBuild:
/property:FrameworkPathOverride="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
We also tried various combinations of
/property:ReferencePath="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
/property:NoStdLib=true
/property:NoCompilerStandardLib=true
The reference assemblies (including the .dll files) are in fact installed in that place on the build server. But when we deploy the website and visit the home page, we get that error. (Interestingly, on a page reload, the error disappears, and the site operates normally.) What are the MSBuild parameters necessary to compile against the .Net 4.0 assemblies?
Update
I turned on ludicrous-level logging on MSBuild, and I see that apparently it is building against the .Net 4.0 reference assemblies:
Resolved file path is "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll
and I didn't see any mention of assemblies outside that folder or the build server's working directory. So it appears to compile properly, but when deployed on the web server, it throws the exception.
As to the exception going away on a page reload, I wonder if that's related to the markup pre-compile step. We're running aspnet_compile on the build server. Maybe if there's an exception coming from a generated assembly, the web server will re-compile it. And the recompiled assembly is fine, because it was created with true .Net 4.0.
Well the answer turned out to be borderline embarrassing. After we confirmed from detailed MSBuild output that it was in fact building the website project against the right reference assemblies, we realized that there are several in-house NuGet packages in the project that had been built against .Net 4.5. One of them was chock full of extension methods, which is what causes the exception. Rebuilding them against .Net 4.0 fixed the problem.
Which brings up an interesting issue. If a 3rd-party NuGet package is compiled for 4.0 but using 4.5 references, we'd be in the same situation, but not able to fix it. So the lesson for package publishers is to ensure your 4.0 version is compiled against the reference assemblies.

Why can't MSBuild ToolsVersion 4.0 build older projects?

We're using Cruse Control to manage our build process.
AS we convert vs2008 projects to vs2010, we're leaving the target framework set at 3.5 for web and class library projects.
At this point we're not going through and converting all our solutions to vs2010; not if we don't have to.
I recently updated the MSbuild project files that cruise control uses to point at MSBuild 4.0 so our build process would be able to build vs2010 projects.
C:\windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe
All was well until a web project that was targeting the 4.0 framework was committed.
At which point this error popped up:
CS0433: The type 'System.Web.Routing.RouteCollection' exists in both c:\Windows\Microsoft.NET\assembly\GAC_32\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll and c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\System.Web.Routing.dll in Global.asax.cs(15, 43)
At which point I became aware of the Windows/Microsoft.NET/Assembly folders.
Now... All the MSBuild projects, even though they were using MSBuild 4.0, still had the tools version set at 3.5.
So why was a 3.5 targeted build looking at the new 4.0 assembly folders and finding this conflict? Probably because I was using MSBuild 4.0. But if I can change the toolVersion that MSBuild uses, you'd think I can tell it to target 3.5 without worrying about these potential conflicts.
To resolve this issue, I went to the relevant MSBuild project files that cruise control uses and changed their toolsVersion to 4.0. This got passed that conflict error. But now everytime it tries to build a project that's in a solution that we haven't yet converted to a vs2010 project, it breaks with an error like this:
MyProject.csproj in SomeFilePath:
LC0000: 'Could not load file or assembly or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.' in LC(0, 0)
If I open the solution that contains that project in Visual Studio 2010 and do the conversion, build it and commit that and force another build, I get passed that error only to find that another not yet converted project is tossing that same error.
So now I am for sure using MSBuild 4.0 and for real targeting the 4.0 framework. Why can't 4.0 build 3.5 projects or vs2008 solution projects?
The issue is that you have migrated part of your projects to to visual studio 2010. Any 2008 project that references a 2010 project (by project reference) will give you this compile time error. Try updating all .csproj files to 2010 and try rebuilding again.