devenv copies files from other project during incremental build - visual-studio

I have 3 projects; Project1.Web, Project1.Service and Project1.Common.
Both Project1.Web and Project1.Service have dependencies on Project1.Common.
If I rebuild the solution which contains all 3 projects; all works correctly.
If I change a file in Project1.Web; files are built to Project1.Web\bin - all works correctly.
If if change a file in Project1.Service files are built to Project1.Service\bin\Debug AND some are copied to Project1.Web\bin. The copied file is Project1.Common.dll, but Project1.Web.dll is not built (or copied).
The file modified in Project1.Service is not shared, its just modified to trigger an incremental build of Project1.Service.
Does anyone know why Visual Studio would be copying a build artifact to a a directory that is not part of the incremental build?
Currently this sequence of events leaves Project1.Web is a non-working state as Project1.Service and Project1.Web have dependencies on different versions of the same assembly via a third party assembly. If we decide to make a change to Project1.Service then it has the side-effect of breaking Project1.Web.
I've tried/checked the following:
There are no dependencies between Project1.Web and Project1.Service (either direction).
The file modified in Project1.Service is not shared; and there are no pre/post build events defined.
Executing msbuild on the Project1.Service.csproj project file does not have the same effect.
Denying write/create permission on the bin directory under Project1.Web does not cause the incremental build to fail.
No output is emitted in the detailed or diagnostic msbuild output that references Project1.Web (from within Visual Studio)
Using procmon, I can see that devenv is using mswebprj.dll (C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Packages\mswebprj.dll) - which invokes the copy of the file.

Related

Azure pipeline: msbuild does not copy one DLL in _PublishedWebsites

I have a strange behavior with msbuild on my Azure Pipeline.
I'm using Azure Pipeline with Self-hosted Windows agents.
Configuration:
My Visual Studio .sln contains two C# projects:
WebService (Rest API)
Business layer
In addition, the Business layer has dependencies on 2 others projects.
Kernel.DataModel
Kernel.DataAccess
The Kernel.DataAcess layer is using the NuGet package "Microsoft.SqlServer.Types" (14.0.314.76)
The Reference "Microsoft.SqlServer.Types" in the project Kernel.DataAccess has "Copy Local = True". Therefore the DLL file should be copied in the output (release) directory.
The problem:
When I run the Azure Build pipeline, the file "Microsoft.SqlServer.Types.dll" is not copied in the "_PublishedWebsites" directory.
To convince myself, I decided to run the same Pipeline on another build machine by changing the Agent Pool. At my surprise the DLL was present in the "_PublishedWebsites" on the second build machine.
Furthermore, I decided to manually run the msbuild command on my local computer and the the DLL was also present in the "_PublishedWebsites...\bin" on my local machine.
Log files:
I also looked at log files on the Build machines and on my local computer.
First build machine -> The DLL file is simply not copied !
Second build machine -> The DLL file is copied from this location.
Copying file from "C:\Program Files (x86)\Microsoft SQL Server\140\SDK\Assemblies\Microsoft.SqlServer.Types.dll" to "F:\AgentLatestBuild\A1\_work\28\b\_PublishedWebsites\ApiProject\bin\Microsoft.SqlServer.Types.dll".
Local machine ->
_CopyFilesMarkedCopyLocal:
Copying file from "C:\TFS\Repos\Src\Project\**packages**\Microsoft.SqlServer.Types.14.0.314.76\lib\net40\Microsoft.SqlServer.Types.dll" to "E:\tfs\build\Microsoft.SqlServer.Types.dll".
Copying file from "E:\tfs\build\Microsoft.SqlServer.Types.dll" to "E:\tfs\build\_PublishedWebsites\ApiProject\bin\Microsoft.SqlServer.Types.dll".
As you can see:
On the second build machine, msbuild is not using the NuGet packages folder but it's using "C:\Program Files (x86)\Microsoft SQL Server\140\SDK\Assemblies\Microsoft.SqlServer.Types.dll"
On my local machine, the DLL is copied from the NuGet packages folder.
Here are my questions:
How msbuild.exe is selecting the source/location of the DLL ?
Is there a way to force msbuild to first use the NuGet packages instead of any others folders ?
I think msbuild should first look in the NuGet packages folder and if the DLL is not found, then it should try to find it from somewhere else. (C:\Program Files (x86), GAC, etc..)
Finally, do you have any idea why the "Microsoft.SqlServer.Types.dll" is not copied at all on the first build machine. The DLL is present in at least three locations. (ie: NuGet packages folder, C:\Program files\ and it is also in the GAC).
It looks like msbuild is lost in the dependency tracking and can't find the file or it won't copy it for some other reasons.
Thanks for your help.
Is it possible that your *.csproj is targetting the wrong HintPath?
Could you check if you have something like this:
<Reference Include="Microsoft.SqlServer.Types">
<HintPath>..\packages\Microsoft.SqlServer.Types.YOURVERSION\lib\net40\Microsoft.SqlServer.Types.dll</HintPath>
</Reference>
thanks

TFS 2015 Visual Studio Build - Package .zip not being created

I'm trying to build my solution and package up the web app into a web deploy (.zip) package to be deployed.
I've added the Visual Studio Build step with the following MSBuild Arguments:
/p:DeployOnBuild=True /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:PackageLocation="$(build.artifactstagingdirectory)\"
And I've set up the Copy and Publish Build Artifacts step to copy all .zip files to the drop folder.
The build completes successfully but nothing is copied to the drop folder because there are no .zip packages that get created.
So when I look on the TFS server, the only thing in the 'a' folder is an empty 'drop' folder. And in the 's' folder is the solution directory with a PrecompiledWeb folder in it. Not sure what that is but it doesn't look like the deployment package (and it's not a .zip).
Any ideas?
I have tried the same on VS2015 MVC web application using VSTS and TFS 2015.2.1 both. I had to do a slight change to the Build arguments in Visual Studio build. That is removing the trailing "\" in /p:PackageLocation="$(build.artifactstagingdirectory)\".
Here is the argument I passed to Visual studio build step
/p:DeployOnBuild=True /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:PackageLocation="$(build.artifactstagingdirectory)"
Then I used Copy and Published Build Artifacts (Deprecated in VSTS you should use Copy task and Publish task instead of this task) as shown below
This gives me output as below.
First suggest you manually remote in the build agent and build the project through MSBuild command line with arguments to see if the project builds properly.
This will narrow down the issue is related to the environment on your build agent or your build definition.
You should directly use /p:PackageLocation=$(build.stagingDirectory
Besides since you have multiple assemblies that are referenced in the web app. Please also double check dependencies that are building in the correct order or referenced correctly.
Make sure the ASP.NET development workload of Visual Studio is installed.
If DeployOnBuild is having no effect, you may need to install the ASP.NET Development "workload" with the VS setup tool.
There are specific .targets files that, if they don't exist, cause these parameters to be silently ignored. Installing this adds those .targets and the parameters become active, allowing the .zip to be created.
For me (VS 2017) the relevant target file (or one of them, anyway) that was missing but is needed is:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.targets
If it is missing, you'll need to install as above, and if it is there, then you have a different problem. ;)

Different results with MsBuild and Visual Studio

I have a solution, which consists out of 2 projects: regular class library for .NET 4.5 + website (not web application) project.
When I build this solution with Visual Studio - all referenced assemblies from Nuget packages and local references are copied to bin folder of website project.
If I try to build solution with MsBuild - bin folder of website project does not receive any assemblies.
Website project is not selected to be built in VS configuration (which is reported by message in both cases)
Edit - here is additional explanation.
When I clone a project from git - bin folder of website contains only 4 assemblies already checked in:
If I will run msbuild command with /t:Build or /t:Rebuild and /p:Configuration=Release;Platform="Any CPU" - I'll receive just an output of postbuild event in my other project, included in solution:
However, if I execute build from VS (Ctrl + Shift + b) in Release/Debug config - bin have all required assemblies for running web application.
Edit 2: Link to example solution - https://github.com/akuryan/csharp-website-test
When one builds it with msbuild TestApp.sln /t:Rebuild /p:Configuration=Release;Platform="Any CPU" - this results in only Test.Core.* and LetsEncrypt.Umbraco.dll (initially checked in) found at ~\Test.Web\bin\ (where Test.Web is website project). If one builds TestApp.sln with VisualStudion 2015 (I suppose, 2013 and 2017 will be the same) - ~\Test.Web\bin\ gets whole amount of assemblies.
Different results with MsBuild and Visual Studio
That because the all dll.refresh file in bin folder alongside the binary file are ignored by .gitignore.
Since Web Site projects do not have any project file (.csproj) to put the assembly references, the *.dll.refresh files are used by MSBuild to understand the assembly references. The contents of the file is the relative path to the .dll via the packages folder for the solution. When you ignore all those .dll.refresh by .gitignore, MSBuild could not understand how to handle the dll files.
To test this, I created a website project, add a nuget package to it, then delete the dll files but keep the .dll.refresh files in the bin folder. Build the website project by MSBuild command line:
msbuild.exe TestWebsite.sln /t:Rebuild
After this command complete, the dll files are copy to the bin folder.
So build and package restore to work it looks like you need to keep the .dll.refresh files in the bin folder. You can remove the other binaries from your version control system.
Note: If you want to get those .dll.refresh back, you can use the command line in the Package Manager Console:
update-package -reinstall
Hope this helps.

Executable not rebuilt but object files recompiled

Building a basic C++ project with Visual Studio 2012. When I make changes to source files:
the corresponding object files are compiled
the .tlog files for the compiler are updated
the PDB file is updated
the .tlog files for the linker however are not changed
the linker claims All outputs are up-to-date. and does not build a new executable.
The only way to get the executable to be built is deleting it. It seems something with the tracking system is wrong and I was wondering if anyone can shed some light on this issue.
Here is the msbuild output after I change two files, full paths and some other stuff omitted (this output is for the VS2010 toolset, but 2012 behaves the same):
1>Target "ClCompile" in file "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\Microsoft.Cpp.Win32.targets"...
Using "CL" task from assembly "Microsoft.Build.CppTasks.Win32, Version=4.0.0.0...
Task "CL"
Read Tracking Logs:
cl.read.1.tlog
CL.2520.read.1.tlog
...
Outputs for ....
XXX.OBJ
YYY.OBJ
...
xxx.cpp will be compiled as xxx.cpp was modified...
yyy.cpp will be compiled as yyy.cpp was modified...
Write Tracking Logs:
cl.write.1.tlog
CL.2520.write.1.tlog
...
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\CL.exe ....
Tracking command:
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\Tracker.exe ....
xxx.cpp
yyy.cpp
Done executing task "CL".
1>Done building target "ClCompile" in project "xxx.vcxproj".
so far, so good. Now the linker kicks in (well, it doesn't):
1>Target "Link" in file "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\Microsoft.Cpp.Win32.targets"....
Using "Link" task from assembly "Microsoft.Build.CppTasks.Win32, Version=4.0.0.0...
Task "Link"
Using cached output dependency table built from:
link.write.1.tlog
Using cached input dependency table built from:
ink.read.1.tlog
Outputs for ....
MY.EXE
MY.PDB
All outputs are up-to-date.
Done executing task "Link".
Task "Message"
xxx.vcxproj -> my.exe
Done executing task "Message".
1>Done building target "Link" in project "xxx.vcxproj".
After checking all options we have in the property sheets one-by-one, it seems the sole source of this problem is that we have the intermediate directory set to a directory on another drive. We always do out of source builds in %TEMP%, and most of the time the projects reside on another drive.
Filed a bug report here including simple steps that reproduce the problem. Hopefully this gets fixed soon. Current soltuion is to set IntDir to a direcyory on the same drive as the project.
UPDATE
The bug report filed for this issue was closed as 'by design': it seems the Intermediate Directory should not be %TEMP% or %TMP% or any subdirectory of those. Disturbing, but at least I know what was wrong now.

What is incremental clean in msbuild and when is it triggered?

I am debugging a bug in my build process that happens occasionally but I can't directly reproduce it. I'm using msbuild with teamcity.
I have a dependency hierarchy like this:
Some.Interop.dll
Dependency-> SharedDllABC.dll
SomeService.exe
Depenendcy-> Some.Interop
Usually the final service exectuable gets in its release directory:
Some.Interop
SharedDllABC.Dll
ServiceExectuable.exe
However I can see in our msbuild logs that sometimes the tertiary dependency gets deleted during an Incremental Clean after everything is built resulting in:
Some.Interop
ServiceExectuable.exe
You can see it here in the msbuild log:
[src\SomeService\SomeService.csproj] _TimeStampAfterCompile
[12:32:43]: [src\SomeService\SomeService.csproj] Compile
// some other targets
[12:32:43]: [src\SomeService\SomeService.csproj] _CopyFilesMarkedCopyLocal
[12:32:43]: [_CopyFilesMarkedCopyLocal] Copy
[12:32:43]: [Copy] Copying file from "C:Projects\trunk\src\Some.Interop\bin\Release\Some.Interop.dll" to "bin\Release\Some.Interop.dll".
// some other targets
[src\Project\SomeService\SomeService.csproj] IncrementalClean
[18:54:42]: [IncrementalClean] Delete
[18:54:42]: [Delete] Deleting file "C:\Projects\trunk\src\Project\SomeService\bin\Release\SharedDllABC.dll".
[18:54:42]: [Delete] Deleting file "C:\Projects\trunk\src\Project\SomeServiceService\bin\Release\SharedDllABC.pdb".
[18:54:42]: [src\Project\SomeService\SomeService.csproj] CoreBuild
[18:54:42]: [src\Project\SomeService\SomeService.csproj] AfterBuild
[18:54:42]: [src\Project\SomeService\SomeService.csproj] Build
This is my direct msbuild output, I just changed the project names/dll names to match my example. By the time this Incremental Clean has occurred the SomeService.csproj has already been built. You can see that its not getting copied. However in other msbuild logs it does properly get copied and then the incremental clean doesn't delete it.
I think incrementeal clean from this post is supposed to clean dll's that were created from previous builds, but that doesn't explain how this dll didn't get built when most of the time it does. In visual studio this always works as well.
I guess I just want to know what exactly is Incremental clean, what causes it to kick in, and maybe what things I should look for when debugging a situation like this (assembly versions, timestamps, etc?)
Try the following:
Add:
<Target Name="IncrementalClean" />
to a .targets file that's included in all projects.
From --> https://github.com/Microsoft/msbuild/issues/1054
#Kebabbi recommends a good fix by editing a csproj file. As of MSBuild 15, there is a simple way to make this apply to all CSPROJ files, instead of editing each csproj file.
https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2017
Directory.Build.props and Directory.Build.targets
Prior to MSBuild version 15, if you wanted to provide a new, custom property to projects in your solution, you had to manually add a reference to that property to every project file in the solution. Or, you had to define the property in a .props file and then explicitly import the .props file in every project in the solution, among other things.
However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). If it finds one, it imports the property. Directory.Build.props is a user-defined file that provides customizations to projects under a directory.
Create a file Directory.Build.props, and place it adjacent to the SLN file.
<Project>
<Target
Name="ForceAssignProjectConfigurationBeforeSplitProjectReferencesByFileExistence_KLUDGE"
BeforeTargets="_SplitProjectReferencesByFileExistence"
DependsOnTargets="AssignProjectConfiguration" />
</Project>
This could be caused by a bug in MsBuild: https://github.com/Microsoft/msbuild/issues/1054.
A fix is proposed in the comments: https://github.com/Microsoft/msbuild/issues/1054#issuecomment-406438561
When MsBuild determines which items to copy from referenced projects, it should do this recursively but does not properly do this.
As a workaround the following can be added to each csproj.
<Target
Name="ForceAssignProjectConfigurationBeforeSplitProjectReferencesByFileExistence_KLUDGE"
BeforeTargets="_SplitProjectReferencesByFileExistence"
DependsOnTargets="AssignProjectConfiguration"
/>
I just spent a few days trying to figure this out with a similar pattern. In our case it was nuget files that were being removed from the output folder.
NugetPackage (that drops files in x86/x64 subfolders in output folder)
LibraryA.dll
Dependency-> NugetPackage
LibraryB.dll
Dependency-> LibraryA.dll
In our case, we have a number of solution files that are built as part of an msbuild script in a certain order.
The problem was that LibraryB.csproj was included in two solution files.
Solution1 builds and output files are all present.
Solution2 builds and sees that LibraryB.dll is present and up to date, so for some reason triggers the IncrementalClean that removes the NugetPackage files from the output folder.
Once I removed the LibraryB.csproj from solution 2, the problem is solved and the files are present in the output folder.

Resources