Thursday, 24 October 2013

Build and Package/Publish Behaviour Changes for SharePoint 2013 Projects from Visual Studio 2012 to Visual Studio 2013

I recently moved to a fresh SharePoint Development Farm with Visual Studio 2013 (from an install with VS 2012 and VS 2013 RC) - and noticed that my projects would build but not publish or deploy correctly. When attempting to Publish or deploy certain projects (i.e. to build SharePoint Solution or .wsp files) in Visual Studio 2013, I found that they would fail on the publish step after rebuilding other projects with your usual build failure exceptions:

The type or namespace name "Interfaces" does not exist in the namespace "ProjectName.Repository" (are you missing an assembly reference?)

I tried to see if there were differences in the Project (csproj) structure in Team Foundation Server (TFS)  - as my colleague still had Visual Studio 2012 and could build the project without issue. There were no differences.

To troubleshoot the issue, I turned build logging way up to the Diagnostics Level from the default of Minimum (in Tools > Options > Projects and Solutions > Build and Run > MSBuild project build output verbosity) as seen below:


Once you do this, you will have tens of thousands of lines of errors and information to sift through. A lot of the errors are spurious and are actually part of the normal functioning of MSBuild. One of the first errors that came up related to the ToolSet Version Installed. It was apparently looking for the Visual Studio 2010 Tools (not even the 2012 Toolset from the Project File (csproj) Definition):

1>------ Build started: Project: MyProject.Model, Configuration: Debug Any CPU ------
1>Build started 23/10/2013 6:32:46 PM.
1>Building with tools version "12.0".
1>Project file contains ToolsVersion="4.0". This toolset may be unknown or missing, in which case you may be able to resolve this by installing the appropriate version of MSBuild, or the build may have been forced to a particular ToolsVersion for policy reasons. Treating the project as if it had ToolsVersion="12.0". For more information, please see http://go.microsoft.com/fwlink/?LinkId=293424.
1>Target "_CheckForInvalidConfigurationAndPlatform" in file "C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets" from project "C:\src\DDK\BIT\MyProject\trunk\MyProject.Models\MyProject.Model.csproj" (entry point):
1>Task "Error" skipped, due to false condition; ( '$(_InvalidConfigurationError)' == 'true' ) was evaluated as ( '' == 'true' ).
1>Task "Warning" skipped, due to false condition; ( '$(_InvalidConfigurationWarning)' == 'true' ) was evaluated as ( '' == 'true' ).
1>Using "Message" task from assembly "Microsoft.Build.Tasks.v12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
1>Task "Message"
1>  Configuration=Debug
1>Done executing task "Message".
1>Task "Message"
1>  Platform=AnyCPU
1>Done executing task "Message".
1>Task "Error" skipped, due to false condition; ('$(OutDir)' != '' and !HasTrailingSlash('$(OutDir)')) was evaluated as ('bin\Debug\' != '' and !HasTrailingSlash('bin\Debug\')).
1>Task "Error" skipped, due to false condition; ('$(BaseIntermediateOutputPath)' != '' and !HasTrailingSlash('$(BaseIntermediateOutputPath)')) was evaluated as ('obj\' != '' and !HasTrailingSlash('obj\')).
1>Task "Error" skipped, due to false condition; ('$(IntermediateOutputPath)' != '' and !HasTrailingSlash('$(IntermediateOutputPath)')) was evaluated as ('obj\Debug\' != '' and !HasTrailingSlash('obj\Debug\')).

I tried to replace all the ToolsVersions to the Visual Studio 2013 version (which is ToolsVersion="12.0" - but to no avail.

I also had exceptions pointing to files that didn't exist - like so:
8>Output file "__NonExistentSubDir__\__NonExistentFile__" does not exist.

I checked with the Fusion Log Viewer (fuslogvw from a Visual Studio Command Prompt) - but there were no errors loading assemblies found. I also checked the GAC with gacutil /l and the files definitely got installed there - so that wasn't the issue. I also considered that it may be one of the perennial problems involving permissions - but Visual Studio was running as an Administrator and the Diagnostics Build log showed no permissions errors like this.

Thinking about how the error only occurred during a Publish or Deploy in Visual Studio, I considered that it may be a problem with the SharePoint Package (Package.package) file. Turns out this was right on the money.

Looking at the very end of the Diagnostic Build log:

8>Done executing task "Exec".
8>Done building target "PostBuildEvent" in project "MyProject.Common.UI.csproj".
8>Target "CoreBuild" in file "C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets" from project "C:\src\DDK\BIT\MyProject\trunk\MyProject.Common.UI\MyProject.Common.UI.csproj" (target "Build" depends on it):
8>Done building target "CoreBuild" in project "MyProject.Common.UI.csproj".
8>Target "CreateTfsBuildInfoResource" skipped, due to false condition; ( $(AddBuildInfoToAssembly)==true ) was evaluated as ( false==true ).
8>Target "AfterBuild" in file "C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets" from project "C:\src\DDK\BIT\MyProject\trunk\MyProject.Common.UI\MyProject.Common.UI.csproj" (target "Build" depends on it):
8>Done building target "AfterBuild" in project "MyProject.Common.UI.csproj".
8>Target "Build" in file "C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets" from project "C:\src\DDK\BIT\MyProject\trunk\MyProject.Common.UI\MyProject.Common.UI.csproj" (entry point):
8>Done building target "Build" in project "MyProject.Common.UI.csproj".
8>Done executing task "MSBuild" -- FAILED.
8>Done building target "BuildSharePointProjectReferences" in project "MyProject.ApplicationPages.csproj" -- FAILED.
8>Done executing task "CallTarget" -- FAILED.
8>Done building target "ConditionalPackage" in project "MyProject.ApplicationPages.csproj" -- FAILED.
8>
8>Build FAILED.
8>

When I removed all project assemblies from the Package.Package File (under "Additional Assemblies") that were in my project output (i.e. any non-3rd Party Components), the package would work correctly. Turns out the main difference between Visual Studio 2012 and 2013 is that the order of "Additional Assemblies" defined in a SharePoint package actually makes a difference - and they must be in order of your project dependencies. If they are out of order, MSBuild process (during creation of the wsp only) will not find them in its working directory and spit the dummy.

The fix to resolve the issue then is to make sure all your "Additional Assemblies" are created in correct dependency order - this didn't make a difference during the build process in Visual Studio 2012 but it makes a big difference in Visual Studio 2013.




I suspect this difference in behavior is related to the changes in architecture to MSBuild and its migration from .NET into Visual Studio itself as discussed here -




DDK

3 comments:

Ryan Shripat said...

Very good investigative work, you saved me, thanks!!

Ryan Shripat said...

Added to SharePoint.StackExchange: http://sharepoint.stackexchange.com/a/84342/69

Unknown said...

Thanks! what a stupid feature of VS - you saved me tonnes of time.