MSBuild deploy failing after upgrade to .NET 4.5

.net-4.5msbuildmsbuild-4.0

We recently upgraded our VS 2010 and .NET 4 application to VS 2012 and .NET 4.5. We have a build script to deploy the application on the test server. We have two boxes – one is Windows 8 with VS 2012 (fresh install) and other is Windows 7 with VS 2010 and VS 2012 (installed newly).

When running the build script from Windows 8 box build script is working well and deploys the application to test server. But when deploying the application from Windows 7 box I get the following error:

"C:\Achinth\Build\Work\build\qa1sb.proj" (DeployAll target) (1) ->"C:\Achinth\Build\Work\App\App.csproj" (ResolveReferences;MsDeployPublish target) (2) ->(MSDeployPublish target) -> C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets(3847,5): error : Web deployment task failed.((8/19/2012 6:23:41 PM) An error occurred when the request was processed on the remote computer.) [C:\Achinth\Build\Work\App\App.csproj]C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets(3847,5): error : \r [C:\Achinth\Build\Work\App\App.csproj]C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets(3847,5): error : (8/19/2012 6:23:41 PM) An error occurred when the request was processed on the remote computer.\r [C:\Achinth\Build\Work\App\App.csproj]C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets(3847,5): error : The application pool that you are trying to use has the 'managedRuntimeVersion' property set to 'v4.0'. This application requires 'v4.5'. [C:\Achinth\Build\Work\App\App.csproj]

Looking at the error it looks like that MSBuild is using VS 2010 targets instead of VS 2012, which is causing the error. Since Windows 8 box does not have VS 2010 it is using VS 2012 targets correctly.

Can some one please provide pointers on how to make MSBuild to pick the right version?

Best Answer

In this case you will need to specify the MSBuild property VisualStudioVersion=11.0. I just blogged about this at http://sedodream.com/2012/08/19/VisualStudioProjectCompatabilityAndVisualStudioVersion.aspx, I've pasted it below as well for your convenience.

One of the most requested features of Visual Studio 2012 was the ability to open projects in both VS 2012 as well as VS 2010 (requires VS 2010 SP1). In case you haven’t heard we did implement that feature. You may be wondering how we were able to do this and how this may impact you.

If you open the .csproj/.vbproj for a Web Project created in VS2010 you will see the following import statement.

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\
                  v10.0\WebApplications\Microsoft.WebApplication.targets" />

When you open this project in VS 2012 there are a few changes made to your project file to ensure that it can be opened in both VS 2010 SP1 and VS 2012. One of the changes made to the project when it is first loaded in VS 2012 is to add the following to replace that import statement.

<PropertyGroup>
  <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
  <VSToolsPath Condition="'$(VSToolsPath)' == ''">
    $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />

We removed the hard-coded 10.0 and instead used the property VisualStudioVersion. When building in Visual Studio 2012 this value will always be 11.0, but for VS 2010 it doesn’t exist. That is why we defaulted it to 10.0 above. There are some scenarios where building from the command line will require to set this property explicitly. Before we get there let me explain how this property gets set (in this order)

  1. If VisualStudioVersion is defined as an environment variable/global MSBuild property, that is used.
    • This is how VS and the VS developer command prompt set this value
  2. Based on the file format version of the .sln file (toolset used is sln file format –1)
    • To simplify this statement, the .sln file will build with specifying VisualStudioVersion to the value of the version of VS which created the .sln file.
  3. Choose default
    • 10.0 if VS 2010 is installed
    • Highest-versioned sub-toolset version installed

For #2 when you are building a .sln file the value of VisualStudioVersion will be –1 of the Format Version found in the .sln file. The important thing to note here is that if you build a .sln file it will build with the value of VisualStudioVersion corresponding to the version of VS which created the .sln file. So if you create a .sln file in VS2012 and you always build that .sln file the value for VisualStudioVersion will be 11.0. In many cases if you build the .sln file you are good.

If you are building .csproj/.vbproj files w/o going through a .sln file? If you build a web project from the command line (not the developer prompt) then the value for VisualStudioVersion used will be 10.0. That is an artifact of the properties which I showed above. In this case you should pass this in as an MSBuild property. For example

msbuild.exe MyAwesomeWeb.csproj /p:VisualStudioVersion=11.0

In this case I’m passing in the property explicitly. This will always override any other mechanism to determine the value for VisualStudioVersion. If you are using the MSBuild task in a build script, then you can specify the property either in the Properties attribute or the AdditionalProperties attribute. See my previous blog post on the difference between Properties and AdditionalProperties.

If you encounter any funny behavior when building/publishing and you notice that the wrong .targets files are being imported then you may need to specify this property.