How to set SGEN toolpath in Msbuild to target 3.5 framework - visual-studio-2010

I've just upgraded a project from VS2008 to VS2010 but I'm still targeting the 3.5 framework.
In my project file I have a custom task to run SGEN to generate my XmlSerializers.dll. However the version of sgen being run targets the 4.0 framework. As a result, when I run my application I get the error message:
"Could not load file or assembly 'XXXX.XXXX.XmlSerializers' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded."
The Sgen task looks like this:
<Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);#(IntermediateAssembly)" Outputs="$(OutputPath)$(_SGenDllName)">
<!-- Delete the file because I can't figure out how to force the SGen task. -->
<Delete Files="$(TargetDir)$(TargetName).XmlSerializers.dll" ContinueOnError="true" />
<SGen BuildAssemblyName="$(TargetFileName)" BuildAssemblyPath="$(OutputPath)" References="#(ReferencePath)" ShouldGenerateSerializer="true" UseProxyTypes="false" KeyContainer="$(KeyContainerName)" KeyFile="$(KeyOriginatorFile)" DelaySign="$(DelaySign)" ToolPath="$(SGenToolPath)">
<Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly" />
</SGen>
</Target>
There's the ToolPath="$(SGenToolPath)". How do I make it run the version that targets 3.5?
There's a similar question here but it doesn't help me much.

I have solved this by manually configuring the ToolPath to point to the old (version 2.0.50727.3038) version of sgen.exe
On my machine, this is in: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin
I changed the ToolPath attribute to be:
ToolPath="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin"
and this solved the problem.
It seems, by default, it's running the new 4.0 framework version in: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools
Hope this helps somebody else.

MSBuild uses the registry to get the path to the v3.5 tools. The MSBuild tasks that require v3.5 SDK tools will fall back to the v4.0 path if the path to the 3.5 tools can't be identified - look at the logic used to set the TargetFrameworkSDKToolsDirectory property in C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.NETFramework.props if you're really interested.
You can diagnose and fix this problem as follows:
Install Process Monitor and set up a filter to monitor registry access by msbuild (Event class: Registry, Process Name: msbuild.exe, all types of result).
Run your build.
Search Process Monitor for a RegQueryValue access matching "MSBuild\ToolsVersions\4.0\SDK35ToolsPath". Note that this could be be under either "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft" or "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft".
If you have a look at this key in the registry, you'll see that it aliases another registry value, e.g. "$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1\WinSDK-NetFx35Tools-x86#InstallationFolder)"
Shortly after this, you'll probably see a "NAME NOT FOUND" result. If you look at where the expected key should be, you'll see that they don't match the key being requested (missing hyphens and possibly no key ending with "-86").
It should be clear what you need to correct. I chose to export the incorrect keys, edit the .reg file and run it to create the correct keys.
One cause of invalid registry entries could be a bug with the Microsoft SDK v7.1 installation:
http://connect.microsoft.com/VisualStudio/feedback/details/594338/tfs-2010-build-agent-and-windows-7-1-sdk-targeting-net-3-5-generates-wrong-embedded-resources

I found this to be the easiest way and it works with: <GenerateSerializationAssemblies>On</ GenerateSerializationAssemblies>
<SGenToolPath>C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin</SGenToolPath>

The problem is $(SGenToolPath) isn't set by MSBuild. If you use $(TargetFrameworkSDKToolsDirectory) then it will attempt to resolve the path based on $(TargetFrameworkVersion).
Its helpful to make use of tags for printf() style debugging. Add the following temporally.
<Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);#(IntermediateAssembly)" Outputs="$(OutputPath)$(_SGenDllName)">
<Message Text="SGenPath: $(SGenPath)" Importance="high"/>
<Message Text="TargetFrameworkVersion: $(TargetFrameworkVersion)" Importance="high"/>
<Message Text="TargetFrameworkSDKToolsDirectory : $(TargetFrameworkSDKToolsDirectory )" Importance="high"/>

#Craig - Did you manually install the 7.0A framework on your build machine. If so, your problem may be your registry settings and not msbuild. Take a look at LocalMachine -> Software -> Microsoft -> MSBuild -> ToolsVersions -> 4.0 -> SDK35ToolsPath and make sure the reg key that is referenced there is valid. (Hint: Make sure the -x86 is there only if the -x86 key exists.)

Related

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.

Building InstallShield LE project with MSBuild - Error MSB4062

I work with Visual Studio 2012, and I just switched my deployment tools from NSIS to InstallShield. I've added new projects to my solution for InstallShield installers. When I build in Visual Studio (the IDE) I've no errors, no warnings and I'm happy.
Now, I want to have a script that build the full solution without launching the IDE. But when I run MSBuild in the command line, like that
MSBuild MySolution.sln /t:Build /p:Configuration=Release
I get following error MSB4062
C:\Program Files (x86)\MSBuild\InstallShield\2012SpringLimited\InstallShield.targets(21,3): error MSB4062: The "Microsoft.Build.Tasks.AssignProjectConfiguration" task could not be loaded from the assembly Microsoft.Build.Tasks.v3.5. Could not load file or assembly 'Microsoft.Build.Tasks.v3.5' or one of its dependencies. 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.
My searches lead me to the conclusion that I must buy the Premier Edition of InstallShield to take profit of ISCmdBuild. But I can't afford it, and I think there might be another solution.
Any idea?
Using Fusion logging the MSBuild checks for the DLL here: file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/Microsoft.Build.Tasks.v3.5.DLL.
I copied
c:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Build.Tasks.v3.5.dll
to
c:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.Tasks.v3.5.dll
And the error is gone.
Alternatively open your *.isproj file and change from "3.5" to "4.0" on top on the tag:
<Project ToolsVersion="3.5"...> --> <Project ToolsVersion="4.0" ...>
Another solution is to force MSBuild to use the x86 platform. See https://stackoverflow.com/a/1074699/870604
If you're building from a TFS build, this can be configured from the build options:
I found the solution. Use the command devenv.exe instead of MSBuild.exe. It will be similar to launching Visual Studio and clicking the Build button. That's all!
devenv.exe MySolution.sln /build Release

MSBuild task to Build other solution projects fails in VS but works with MSBuild.exe command line

I have a custom MSBuild task which among other things adds embedded resources to other projects in the solution. After adding the resources I'd like to then build those projects, but found I can't get this working within Visual Studio.
To test, I stripped out the custom task entirely and redefined a simple AfterBuild target in the web project of a Silverlight solution. The target uses the MSBuild task to build the Silverlight application project in the solution, and looks like this:
<Target Name="AfterBuild">
<PropertyGroup>
<LinkedProject>..\SilverlightApplication1\SilverlightApplication1.csproj</LinkedProject>
</PropertyGroup>
<MSBuild Condition="'$(LinkedProject)' != '' "
Projects="$(LinkedProject)"
Targets="Build"
Properties="CustomFlag=true" >
</MSBuild>
</Target>
The odd thing is that this works perfectly when using MSBuild from the command line, yet does not work in Visual Studio when building the web project. I thought this might be some sort of Silverlight problem, and had the task build a .NET class library project instead, but the result was the same - it worked from the command line but not within VS. In VS there's no actual error - it's just that the Csc task does not compile the assembly and generates no output.
What do I need to do to get this working within Visual Studio?
Pass the 'UseHostCompilerIfAvailable=false' property to the MSBuild task.
It looks like Visual Studio breaks badly if csc is invoked from a MSBuild task as it reuses the initial project build settings for its in-process host compiler. In my case, I was building the same project twice - default build was using target framework v3.5, with a AfterBuild MSBuild task specifying v4.0. I ended up with the same issue - csc appeared to run but produced no output. I think what was happening was that with the UseHostCompilerIfAvailable property set to true, csc was calling the hosted compiler which reused my initial project settings, so even though the command line showed csc "building" my v4.0 assembly, the host compiler was simply overwriting the v3.5 one I had just built!
Change Visual Studio verbosity to detailed and check build log. I think that CoreBuild is not executed if your files have not changed, so you could try to use AfterCompile instead of AfterBuild.

Sharing visual studio C# project with native dependencies on the file system

I have a shared C# project that uses assemblies which rely on native dlls in the current directory. This project is used by developers and a build server which uses msbuild to build and deploy the project with clickonce. There are environmental variables on these machines that specify these native library paths. I tried to find a way to add the dll to the project and set copy local to true, but there doesn't seem to be a way to add a file link using an environment variable.
Is it even possible to use environment variables in the visual studio IDE? If not, what is the correct/normal way to handle this? The dlls need to be found and copied to the output when developers are building and debugging the project from source control, and they need to be added to the click once Application Files when the build server does an msbuild publish.
The msbuild project can use environment variables, so you could add a "post build"
task that uses the environment to and start devenv with "devenv /useenv".
For example:
<Target Name="AfterBuild">
<Copy SourceFiles="$(DatabaseSourcePath)\NORTHWND.MDF"
DestinationFolder="$(TargetAppDataPath)" />
</Target>

MSBuild target PipelinePreDeployCopyAllFilesToOneFolder cannot be found when deploying

Deploying a Web Application Project from VS2010 RTM causes an error in MSBuild. It complains that the PipelinePreDeployCopyAllFilesToOneFolder target cannot be found.
Is there any way to further diagnose this?
Thank you.
I had the same problem and when I looked in the .csproj file for my web application I had the following lines...
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="'$(Solutions.VSVersion)' == '8.0'" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" Condition="'$(Solutions.VSVersion)' == '9.0'" />
I guess this happened since I had recently upgraded from VS2008 to VS2010. So it looks like the during the conversion process it got all screwed up. To fix it I just replaced those lines with ...
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
After that everything worked as it should.
I've seen the answer given by brodie in several places online, which is strange to me because this task (PipelinePreDeployCopyAllFilesToOneFolder) is not even contained in this target (Microsoft.WebApplication.targets):
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
If you actually go and find this file (on an x64 machine it's in C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets, or the version 12.0 equivalent if you're using VS2013) and open it in a text viewer, you'll see it's not there..
It's actually contained in the file that Sayed Ibrahim Hashimi mentions, which is the Microsoft.Web.Publishing.targets file (C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets).
So to get this into your MSBuild/.csproj file, include the following:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />
Do you have Visual Studio 2010 installed on the machine where you are trying to build? If so then look for a file located at %Program Files(x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets it should have that target. If it doesn't then those files may have been corrupted and probably reparing your VS 2010 install should fix it.
I think the Web Deployment targets/tasks are shipped with VS itself and not the .NET framework, so you need VS installed (or you can manually configure the machine)/
Even though this is an old post It still provided some great help!
My setup is using a remote host for Automation of a project built in VS2013.
The remote host doesn't contain all the VS2013 targets when you solely install MSBuild 12.0 and this resulted in the 'Microsoft.Web.Publishing.targets' file not existing.
To get around this target error I had to copy the files from my local VS2013 path and copy this to the remote host in the equivalent location.

Resources