Visual Studio 2017 not loading AjaxMin MSBuild Task from specified path - visual-studio

I'm attempting update an existing application so that it will load in Visual Studio 2017 (Enterprise - V15.2 (26430.12)) from Visual Studio 2015 (Enterprise) and having issues with the AjaxMin build task.
In Visual Studio 2015, the AjaxMin build task is found in C:\Program Files (x86)\MSBuild\Microsoft\MicrosoftAjax. Visual Studio 2017 looks for it in C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft. Given that all developers on the team may not have VS2017 Enterprise and we've had issues in the past with developers installing the wrong version, I'd like to have it use the AjaxMin NuGet package referenced in the solution.
There are 3 projects in the solution that use the AjaxMin task. I've updated all of them to have the following import:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
...
<Import Project="$(MSBuildProjectDirectory)\..\..\..\packages\AjaxMin.5.14.5506.26202\tools\net40\AjaxMin.targets" />
<Target Name="BeforeBuild">
<ItemGroup>
<JS Include="..." Exclude="..." />
</ItemGroup>
<ItemGroup>
<CSS Include="..." Exclude="..." />
</ItemGroup>
<AjaxMin Switches="..." JsSourceFiles="#(JS)" JsCombinedFileName="..." CssSourceFiles="#(CSS)" CssCombinedFileName="..." />
</Target>
...
</Project>
However, when the build happens, I receive an error saying it can't find the AjaxMin task in the default build extensions directory:
The "AjaxMin" task could not be loaded from the assembly C:\Program
Files (x86)\Microsoft Visual
Studio\2017\Enterprise\MSBuild\Microsoft\MicrosoftAjax\AjaxMinTask.dll.
Could not load file or assembly 'file:///C:\Program Files
(x86)\Microsoft Visual
Studio\2017\Enterprise\MSBuild\Microsoft\MicrosoftAjax\AjaxMinTask.dll'
or one of its dependencies. The system cannot find the file specified.
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.
I've used the MSBuild Message Task to output the path and verified that it is correct by navigating to it from the command prompt. I also tried using the UsingTask with no luck there.
Why is Visual Studio not looking for the AjaxMin DLL in the location I specified?
Update:
I moved the import tag for AjaxMin to the top (right under the project tag) and it works now. I don't understand why.

I resolved this issue by installing the .Net 3.5 framework

The issue turned out being another import for another third party build task. It appears that build task alters the build process such that the AjaxMin build task won't work after it. Having the AjaxMin build task after the Microsoft.CSharp.Targets import but before the other third party build task did the trick.

I moved the import tag for AjaxMin to the top (right under the project tag) and it works now. I don't understand why.
If I understand your question correctly, that is because you have two reference sources for the AjaxMinTask.dll, one is the default assembly source:C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\MicrosoftAjax, another is the import reference, you will notice that the AjaxMinTask.dll is used in the AjaxMin.targets:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask AssemblyFile="AjaxMinTask.dll" TaskName="AjaxMin" />
<UsingTask AssemblyFile="AjaxMinTask.dll" TaskName="AjaxMinBundleTask" />
<UsingTask AssemblyFile="AjaxMinTask.dll" TaskName="AjaxMinManifestTask" />
<UsingTask AssemblyFile="AjaxMinTask.dll" TaskName="AjaxMinManifestCleanTask" />
...
</Project>
So when set the import reference behind your task, MSBuild will use the default assembly source (under the VS2017 installation directory), when you set the import reference before you task, the AjaxMin.targets will rewrite the path of reference source.

Related

How should I include Package References in a VSIX project

My solution creates a Visual Studio Package from multiple projects, using multiple NuGet packages.
All of the Nuget packages are specified in the project files using PackageReference (rather than the older packages.config file). I am using Visual Studio 2019.
I have had a problem, that the DLLs referenced by NuGet Packages are not included in the VSIX installation.
There is a solution to this problem, described in this article by Daniel Cazzulino, by adding the following code to the project file:
<PropertyGroup>
<GetVsixSourceItemsDependsOn>$(GetVsixSourceItemsDependsOn);IncludeNuGetResolvedAssets</GetVsixSourceItemsDependsOn>
</PropertyGroup>
<Target Name="IncludeNuGetResolvedAssets" DependsOnTargets="ResolveNuGetPackageAssets">
<ItemGroup>
<VSIXCopyLocalReferenceSourceItem Include="#(ReferenceCopyLocalPaths)" />
</ItemGroup>
</Target>
This does work, but it blows up the size of the installation from about 20MB to about 40MB.
The installation now includes a lot of PDB files, which I don't really need.
More significantly, it brings in about 46MB of Visual Studio DLLs which are not necessary, because they are part of Visual Studio.
Is there a better way to ensure that the referenced NuGet packages are included in the VSIX, without inflating the installation with these other files?
You can use a simple script like this:
<Target Name="IncludeNuGetPackageReferences" AfterTargets="GetVsixSourceItems">
<ItemGroup>
<VSIXSourceItem Include="#(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' == 'Newtonsoft.Json'" />
<VSIXSourceItem Include="#(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' == 'xxx'" />
... </ItemGroup>
</Target>
You can specify what assemblies should be included into .vsix . And it won't copy the unnecessary VS assemblies after tests in my machine. Hint from smourier, thanks to him.
Hope it helps:)

Get the correct $(VisualStudioVersion) for VS 2017 inside a MSBuild file

I have a MSBuild file to publish a solution (created in VS 2013 and ported to VS 2017) to a remote server. The offending line is this one:
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
When I run the command:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild" WebSite1_Web_configs.build /p:Configuration=Integracion;Platform="AnyCPU" /p:VisualStudioVersion=15.0
After some compilation, it ends up with this error:
Error MSB4062 The "TransformXml" task could not be loaded from the assembly C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll
Of course it can't be loaded, because the version should be 15.0, not 12.0.
Things I have tried:
Adding the /p:VisualStudioVersion=15.0 to the command where I call MSBuild. It doesn't work.
Changing, inside the *.csproj file, the element:
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
For:
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
It doesn't work.
So, how can I get the correct VS version with $(VisualStudioVersion) inside the MSBuild file without having to hardcode it?
Ok, the problem was that I had <Import> elements at the end of the *.build file. One of those imports had part of the path hardcoded:
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0\WebApplications\Microsoft.WebApplication.targets" />
I changed it to:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />
I executed MSBuild with the /p:VisualStudioVersion=15.0 parameter and it worked.
Please, if you have the same problem, check if you have imports with hardcoded paths.
On Visual Studio 2017, instead of edits the .csproj file, you can simple go to Visual Studio Package Manager Console (Tools -> NuGet Package Manager -> Package Manager Console) and install Web.Targets:
Install-Package MSBuild.Microsoft.VisualStudio.Web.targets

TransformXml task could not be loaded from Microsoft.Web.Publishing.Tasks.dll

Has anyone seen this error and know how to fix it?
The "TransformXml" task could not be loaded from the assembly C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll.
Could not load file or assembly 'file:///C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll' or one of its dependencies. The system cannot find the file specified.
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.
I read elsewhere that the problem is when you don't have SQL Server installed. But I do have SQL Express 2012 x64 installed with SP1. I am also running VS 2013 Professional.
I have ran this exact same solution in VS 2012 express with no problems.
The answers provided by Dai Bok and emalamisura work fine as long as you use Visual Studio 2012.
For VS 2013 this fails as well. In order to make this work with all versions of Visual Studio you should:
Open the project file (.csproj) of the project failing to load
Search for <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />
Change it to <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.targets" />
Reload the project
That will set the correct version of Visual Studio dynamically and properly.
To get mine to work, I just copied my v10.0 folder and renamed it to v11.0, and things seems to work well from then on. That's the quick fix for now.
As this is probably not the best solution, and although it works, I was going to try installing the Microsoft Windows SDK for Windows 7 and .NET Framework 4 Windows SDK for Windows 7 and .NET Framework 4, but it is taking to long to download.
To fix the issue,
Find the Visual studio Installer in your computer
Click or tap to start the installer, and then select Modify.
From the Individual Components screen, select Asp.net and web development tools and then select Modify/Install.
This solved the issue as it creates the dll's in the mentioned path.
I've been combating this problem on our build server for several days, so I figured I'd document the resolution I came to. First, my build server has the web publishing extensions installed. I can use the TransformXml task to my heart's content inside of a web application project.
To use it outside of a web application project, I tried to add the UsingTask element to my project and point it to the right place using ms build properties (as Benjamin demonstrated). However, they weren't there on my build server (those with easy access to the file system of their build server can probably skip this and just install the relevant package to Visual Studio). I even went so far as to hard code visual studio versions, but it always dropped that error on me.
I finally gave up, pulled the DLLs from my local PC:
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.XmlTransform.dll
I uploaded them to source control and added that folder to my build's workspace (Edit Build Definition -> Source Settings -> Source Control Folder). From there, I don't even need to reference the folder -- here's what my UsingTask looks like:
<UsingTask TaskName="TransformXml" AssemblyFile="Microsoft.Web.Publishing.Tasks.dll" />
Now I can use the TransformXml task to my heart's content from any project.
For VS2019
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(MSBuildToolsVersion
I replaced MSBuildToolsVersion with VisualStudioVersion.
Because there are only v12.0, v14.0 and v15.0 in my VisualStudio folder, I edit my project file and change the reference path from v10.0 to v14.0. Then the project builds successfully.
Before:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
After:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
Solutions provided seem to work for using VS as an IDE, but if you use DotnetCore via CLI or on a unix based system this does not work.
I found that the following seem to work
<PropertyGroup>
<XmlTransformDllPath Condition="'$(XmlTransformDllPath)' == '' AND '$(MSBuildRuntimeType)' == 'core'">$(MSBuildSDKsPath)/Microsoft.NET.Sdk.Publish/tools/net5.0/Microsoft.NET.Sdk.Publish.Tasks.dll</XmlTransformDllPath>
<XmlTransformDllPath Condition="'$(XmlTransformDllPath)' == '' AND '$(MSBuildRuntimeType)' != 'core'">$(MSBuildSDKsPath)/Microsoft.NET.Sdk.Publish/tools/net472/Microsoft.NET.Sdk.Publish.Tasks.dll</XmlTransformDllPath>
<XmlTransformDllPath Condition="!Exists($(XmlTransformDllPath))">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll</XmlTransformDllPath>
</PropertyGroup>
<UsingTask TaskName="TransformXml" AssemblyFile="$(XmlTransformDllPath)" />
This solution takes into account netcore, full .net
For some reason MSBuildSDKsPath and MSBuildExtensionsPath32 are different on windows when using CLI vs VS2019
CLI:
MSBuildSDKsPath = C:\Program Files\dotnet\sdk\5.0.103\Sdks
MSBuildExtensionsPath32 = C:\Program Files\dotnet\sdk\5.0.103
Vs2019
MSBuildSDKsPath = C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Sdks
MSBuildExtensionsPath32 = C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild
Which on my Mac returns /usr/local/share/dotnet/sdk/5.0.201
Only problem I see is with the tools/net5.0 part of the name which changes ever release
Also created https://github.com/dotnet/sdk/issues/16469 and answers this on The "TransformXml" task was not found (error MSB4036) on TeamCity build
The correct answer to this is to unload the project in question and then edit the csproj file, look for an entry where they are referencing the 10.0 path and change it to point to 11.0 instead.
You need two things to make it work:
1) Install Visual Studio Build Tools (You don't need the whole Visual Studio, only the VS Build Tools) with selected "Web development build tools" option on your build server
https://www.visualstudio.com/pl/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15
2) Ensure that path to Microsoft.Web.Publishing.Tasks.dll is correct
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(MSBuildToolsVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
For me it started working just by adding reference to the NuGet package MSBuild.Microsoft.VisualStudio.Web.targets v14.0.0.3
Even no need to add UsingTask element to the project file as it mentioned by the package author
https://github.com/pdonald/nuget-webtargets
Just install the NuGet package. The package automatically sets the
$(VSToolsPath) property to use the targets file in the tools folder.
And then I was able to use TransformXml and other tasks, defined in the package, for instance to transform app.config
<Target Name="app_config_AfterCompile" AfterTargets="AfterCompile" Condition="Exists('app.$(Configuration).config')">
<!--Generate transformed app config in the intermediate directory-->
<TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
<!--Force build process to use the transformed configuration file from now on.-->
<ItemGroup>
<AppConfigWithTargetPath Remove="App.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
</Target>
Just in case someone is using an SDK-style csproj, you can achieve this without having to install Visual Studio on the build server.
First you should install the SlowCheetah nuget package to your project. Once you install it, you'll see the following in your SDK-style project.
<PackageReference Include="Microsoft.VisualStudio.SlowCheetah" Version="3.2.20">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
Then make sure you add the GeneratePathProperty="true" attribute (see below). This is very important for the next part because it'll help you grab the path of where the nuget package is restored on your machine. George Dangl explains it in his article here.
<PackageReference Include="Microsoft.VisualStudio.SlowCheetah" Version="3.2.20" GeneratePathProperty="true">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
Import the SlowCheetah targets into your project:
<Import Project="$(PkgMicrosoft_VisualStudio_SlowCheetah)\build\Microsoft.VisualStudio.SlowCheetah.targets" />
You can now use an target command (in this case after publish) to apply some custom transformations. If you need to, you can always hard-code the file names below instead of using the variables in the below example.
<Target Name="AfterPublishs" AfterTargets="Publish">
<TransformTask Source="Web.config" Transform="Web.$(Configuration).MyCustomTransformFile.config" Destination="$(PublishDir)\Web.config" />
</Target>
If you haven't used SlowCheetah before, I recommend checking it out. They have a Visual Studio extension that will make it easier for you to preview transform files.

Error MSB4062 when trying to use ServiceController

I use Visual Studio 2010 with TFS 2010 on a x64 machine.
I am trying to use the MSBuild Community Tasks target in my build. This target exists in source control. So in my csproj file i am import that particular target but i now get the following error:
error MSB4062: The "MSBuild.Community.Tasks.Attrib" task could not be loaded from the assembly C:\Program Files (x86)\MSBuild\MSBuildCommunityTasks\MSB
uild.Community.Tasks.dll. Could not load file or assembly 'file:///C:\Program F
iles (x86)\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll' or one of
its dependencies. The system cannot find the file specified. 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 Micros
oft.Build.Framework.ITask. [C:\SampleTest\SampleTest.csproj]
Here is my code:
<Import Project="..\..\Builds\Common\MSBuildTasks\MSBuild.Community.Tasks\MSBuild.Community.Tasks.Targets" />
<Target Name="BeforeBuild">
<PropertyGroup>
<MyService>ServiceName</MyService>
</PropertyGroup>
<ServiceController ServiceName="$(MyService)" Action="Stop" />-->
</Target>
Any thoughts on the above?
Why is MSBuild trying to look for the dll elsewhere when i have specified it in the project file?
Thanks in advance,
I think the problem comes from within the MSBuild.Community.Tasks.Targets file - it is this file that actually references the MSBuild.Community.Tasks.dll assembly.
If you open the file you can see a bunch of UsingTask elements, such as:
<UsingTask AssemblyFile="$(MSBuildCommunityTasksLib)" TaskName="MSBuild.Community.Tasks.Attrib" />
The $(MSBuildCommunityTasksLib) property is defined at the top of the file as:
<PropertyGroup>
<MSBuildCommunityTasksPath Condition="'$(MSBuildCommunityTasksPath)' == ''">$(MSBuildExtensionsPath)\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
<MSBuildCommunityTasksLib>$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.dll</MSBuildCommunityTasksLib>
</PropertyGroup>
So it looks like you need to set the $(MSBuildCommunityTasksPath) property before calling <Import>.

Build doesn't work from VisualStudio, but is ok from msbuild

From a brand new console application template in visual studio, I edited the .csproj to build another project like this:
...
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="BeforeBuild">
<MSBuild Projects=".\other.mproj"/>
</Target>
...
Where other.mproj is:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Target Name="Build">
<Message Text="kikou" />
</Target>
</Project>
After a while I discovered that modifying the content of other.mproj (for instance, by introducing errors or changing text kikou to something else) would not be taken into account unless unloading/reloading the project in visual studio.
Building from the command line with 'msbuild myproj.csproj' immediatly detect changes in 'other.mproj'. So it all looks like visual studio is working from a cached version of other.mproj file.
Why is visual studio caching this other script (which is even not included to the project), and how can I solve this issue ?
Update: I also tried this UseHostCompilerIfAvailable, it doesn't work.
NB1: I didn't add other.mproj as a project reference in the .csproj because it is not a .NET project at all (it just creates resources files for the .csproj from other inputs before the build)
NB2: I'm using VS2010 (10.0.10219.1SP1Rel + MSBuild 4.0.30319.1)
Visual Studio caches all MSBuild files, this is done for performance reasons. You will not be able to have an MSBuild only way around this. It may be possible to achieve this via a VS add-in but I'm not 100% sure of that.

Resources