MSBuild: How can you find out where a specific file is added to _CopyFilesMarkedCopyLocal? - msbuild

When I build a specific project there is an undesired file being copied into the output from a nuget package during the _CopyFilesMarkedCopyLocal task. I can't determine from the logs or a search of project references why the file is marked CopyLocal. Is there anything logged that could help? Or is there a property or item group that I can start printing out debug messages to track it down?
More details:
The file is part of a Nuget package, but it isn't directly referenced in the project where the copy happens.
The project where the copy happens is part of a large complex .NET Framework application. The project has 5 PackageReference , and 1 ProjectReferences. The ProjectReference project has an additional 17 PackageReferences and 7 ProjectReferences and the tree keeps going.

NuGet will generate obj\...nuget.g.props/.targets file that contains the reference.
This can be controlled via Dependency asset attributes - e.g. setting ExcludeAssets="contentfiles" on the PackageReference.
Using a binary log (adding -bl to msbuild/dotnet build invocations) and opening it in the structured log viewer gives you good search options in the logical build tree and the files / log output which can help find these files.

Related

NETSDK1152 Error for _ViewImports.cshtml files

After upgrading my WebApp from NET5 to NET6, when trying to push my WebApp to the Azure AppService, I get the NETSDK1152 error:
Found multiple publish output files with the same relative path:
C:...\src\ProjA_ViewImports.cshtml,
C:...\src\ProjB_ViewImports.cshtml,
C:...\src\ProjC_ViewImports.cshtml
The projects in Question are Razor Class Libraries (Project Sdk="Microsoft.NET.Sdk.Razor"), which all get referenced by a regular Web App (). The files in question are _ViewImport.cshtml files to contain common usings/imports for my Views. They only have their standard properties which never got changed by me (Action -> Content, Copy to Output Directory -> Do not Copy).
Before updating to NET6, everything worked flawlessly, both on my local machine as well as on Azure (both publishing and running the application). After my upgrade to .NET6, I started receiving the error mentioned above.
However, this ONLY occurs when I use the publish functionality (or when the CI/CD is triggered by pushing to the remote git repo). If I use dotnet publish locally, everything seems to be published just fine.
Trying the usual recommendation, of turning off the error (as proposed, for instance, here), did not solve anything for me.
Apart from either getting rid of the _ViewImport.cshtml files altogether, or restructuring the project, I am lost with regards how to potentially solve this issue while keeping the structure as is.
The .NET SDK (6.0.100 Preview 1) generates a new error (NETSDK1152) in cases where files from different source paths would be copied to the same file path in the publish output. This can happen when a project and its project references include a file with the same name that's included in the publish output.
Old Behavior
Both files were copied to the same destination. The second file to be copied overwrote the first file, and which file "won" was mostly arbitrary.
In some cases, the build failed. For example, when trying to create a single-file app, the bundler failed with an ArgumentException, as shown in the following build output:
C:\Program Files\dotnet\sdk\5.0.100-preview.5.20258.6\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(962,5): error MSB4018: The "GenerateBundle" task failed unexpectedly. [C:\repro\repro.csproj]
C:\Program Files\dotnet\sdk\5.0.100-preview.5.20258.6\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(962,5): error MSB4018: System.ArgumentException: Invalid input specification: Found multiple entries with the same BundleRelativePath [C:\repro\repro.csproj]
C:\Program Files\dotnet\sdk\5.0.100-preview.5.20258.6\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(962,5): error MSB4018: at Microsoft.NET.HostModel.Bundle.Bundler.GenerateBundle(IReadOnlyList`1 fileSpecs) [C:\repro\repro.csproj]
New behavior
Starting in .NET 6, MSBuild removes duplicate files that are copied to the publish folder if both the source and destination are the same. If there are any remaining duplicates, a NETSDK1152 error is generated and lists the files that are duplicated.
Reason for change
Duplicate files in the publish output sometimes caused build breaks or unpredictable behavior.
Recommended action
Ideally, you should update your project to avoid situations where multiple files with the same name are copied to the publish output. The error message includes the name of the duplicate file. Some causes for duplicate files include:
An ASP.NET Core project that references an ASP.NET Core web service, and each has its own appsettings.json file.
A project item where CopyToOutputDirectory is unnecessarily set to Always.
Binary log files can be useful for finding the cause of the duplicated files.
Alternatively, you can set the ErrorOnDuplicatePublishOutputFiles property to false.

TFS Build dropping extra files including csproj in target folder

I have an automated build process set up to run from a build definition in TFS, which publishes a web application and generates/executes a database project script successfully via publish profiles that are passed as msbuild arguments in the build process definition. Everything is now running as expected except that several unnecessary files are being deployed to the target folder, including the .csproj file, all of the config transforms, and the properties folder which contains all of my publish profiles.
This is strange because 1. It's definitely not including ALL files/folders and mostly appears to be including ones used by the publish profile like transforms, while applying the transform correctly and excluding any explicitly excluded file (as defined in the pubxml), and 2. The process works perfectly if I do it by publishing from the project in Visual Studio 2013. I have the profile configured to only include files needed by the application, and I've confirmed in the csproj file that this property is there.
I tried excluding the properties folder from deployment in the pubxml file, but this causes the build to crash because it can't find the assembly file. What I've gathered is that the process is keeping all files it needs to complete the build, and dropping all of those files in my destination folder. FWIW, I'm using the "file system" method and I'm not sure yet if web deploy will make a difference. I haven't been able yet to connect to the target server with web deploy, but that's a separate problem to solve. Is there something in the build that I can configure so that my destination folder has only the files it needs to run the application, and not the files needed to BUILD the application?
FYI I also have not been using a drop folder, I'm not sure if that makes a difference or not but that might be the only thing I haven't tested as it doesn't seem necessary since I'm using a publishprofile and don't want to use the default tfs build configuration.
I found a solution that works well enough, after reading this: http://www.asp.net/web-forms/tutorials/deployment/advanced-enterprise-web-deployment/excluding-files-and-folders-from-deployment
This was a little uglier solution than I wanted, since it requires hard-coding the names of excluded files, but it does the trick and only requires identifying the files and folders in one location instead of altering a publish profile for each target environment. I created a wpp.targets file and used the ExcludeFromPackageFolders and ExcludeFromPackageFiles elements to identify the extra files. Ironically, if I don't also name the wpp.targets file in the exclude element, THAT file is included in my package. It's possible MSDeploy doesn't have the same issues with TFS as filesystem, but after spending half a day trying to work through a different set of issues and permissions workarounds, we decided that file system is a cleaner publishing method.

Wix - building files to subdirectories

I am new to WiX and am trying to get my install project to build certain files to a subdirectory of the build output path. For example, if my build output path is: bin\Debug, I would like certain files to be added to a subfolder here: bin\Debug\Images.
Is this possible please?
It looks like you are using a WiX project template with Visual Studio, MSBuild and/or SharpDevelop. If so, you have several options:
Use XCOPY in the Post Build Event.
flexible
somewhat easy to find in your project (on one of the project designer tabs)
not integrated well with the build system
Add the folder and files to your project folder, include them in your project and set the Copy to Output Directory on each file. Note: you can't set that property on a folder. The copying will preserve the folder structure but you have set the property on each file you want copied.
inflexible
very easy to find in your project (solution explorer and properties window)
Open the project file in a text editor and add MSBuild tasks such as Copy to the AfterBuild or other target. Note: To use VS to edit the project file, right click, select Unload Project, then right click and select Edit.
flexible
hard to find in your project (XML in the project file)
uses the build system
In the last case, I sometimes put a REM comment in the Post Build event to clue people into the fact that the project file has been customized.

SlowCheetah transforms manually but not via TFS (on most of the projects)

I have some environment specific transforms for about 10 class library projects. These projects are all similar in architecture, especially the configuration files I want to transform. Out of the 10 projects, 2 of them transform via TFS Build. The rest do not.
If I open the project source that TFS (2010) downloaded and built it myself the transforms work for any project I build.
What could cause SlowCheetah to NOT transform via tfs but but does transform when I build the very same code manually? The build definitions all look similar as do the .csproj files.
It looks like this was happening because test projects were building and overwriting the config file. When I changed the configuration to not include building the test projects the transforms started working.
UPDATE:
If you need a file to be copied over (like in my case a configuration file) then normally you would mark it as 'Content' and 'Copy always' (or newer or whatever). Once you decide to add transforms to that file then you should revert back to None and 'Do not copy'. Apparently SlowCheetah implicitly treats a file with transforms as signal to copy it to the output. If I had left it as 'Content' and 'Copy Always' any project (like the test project) that relies on it will overwrite (without the transforms being applied).

MSBuild overwriting dependencies

Ok, so I've got a somewhat complicated problem with my build environment that I'm trying to deal with.
I have a solution file that contains multiple C# projects which is built by a NAnt script calling MSBuild - passing MSBuild the name of the solution file and a path to copy the binaries to. This is because I want my automated build environment (CruiseControl.Net) to create a folder named after the revision of each build - this way I can easily go back to previous binaries for any reason.
So idealy I have a folder layout like this
c:\build\nightly\rev1
c:\build\nightly\rev2
c:\build\nightly\rev3
...
c:\build\nightly\rev10
etc.
The problem that's arisen is I recently added the latest version of the Unity IoC container to my project, checking it directly out of MS's online SVN repository. What's happening is I have a Silverlight 3 project that references the Silverlight version of Unity but I also have other projects (namely my Unit testing project) that reference the standard (non-Silverlight) version of Unity.
So what happens is since MSBuild is dumping everything into one single folder the Silverlight version of the Unity assembly is overwriting the non-Silverlight version because they have the exact same assembly file name.
Then when CruistControl runs my unit tests they fail because they don't have the proper dependencies available anymore (they try to load the Silverlight specific Unity assembly which obviously doesn't work).
So what I want to do is:
keep my desired output directory
structure (folder\revision)
I don't want to have to manually edit
every single proj file I have as this
is error prone when adding new
projects to the solution
Idealy I would like MSBuild to put everything into a folder structure similar to this:
nightly\revision1\project1
nightly\revision1\project2
nightly\revision1\project3
...
nightly\revision2\project1
nightly\revision2\project2
nightly\revision2\project3
etc
I can't modify the Unity project to give it a different file name because it comes from another SVN repository I cannot commit changes to. I found a similar question posted here and the suggested solution was to use a "master" MSBuild file that used a custom task to extract all the project file names out of the solution then loop over each one building them. I tried that but it doesn't build them in the order of their dependencies, so it fails for my project.
Help?
Firstly I would always have the build server delete the old working copy and check out a fresh copy to avoid any problems with stale artifacts from the previous build.
Next I would have nant or msbuild build the solutions as before with the artifacts from each build going to their local working output folders.
After that I'd move the artifacts from their working paths to their output paths, this shouldn't require digging through the project files since you can just tell msbuild/nant to copy working\project1\bin\release\**\*.* to artifacts\project1\.
The script that does this should ideally be stored along with the source with the main file, e.g. build.nant or build.proj in top level of the trunk.
For third party libraries I would simple include the DLLs directory in your repository. Nothing worse than writing some code and having a third party dependency break your build because of changes on their end.
Simply document the versions of the libraries you are using, and if you must update them, you'll have a better sense of what breaks the build before you even check it in.
Also, doesn't CC.Net automatically handle the providing of releases based on revision? I'm using TeamCity and it keeps a copy of the artifacts of every build.
I highly recommend reading JP Boodhoo's Automating Builds with NAnt blog series. That's been my starting point and have made lots of changes for my own taste. I also highly recommend checking out the builds of many open sources projects for examples. I've learned a lot from the builds of the Castle/Nhibernate/Rhino-Tools stack.