Azure pipeline: msbuild does not copy one DLL in _PublishedWebsites - visual-studio

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

Related

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.

Why does Visual Studio publish packages.config too?

When I use the option Publish... selecting as target the file system in Visual Studio 2015 it compiles the code, do the XML transformation in the Web.config files and copy the files to the folder I specified.
It does not copy any *.cs file as expected since it is compiled.
Something that I don't understand is why it publishes the Nuget Config file (packages.config), after all, the files needed are already in the bin folder.
I found this question that says how to avoid but not the reason they decided this file would be usable on the server.
Can I stop VS from publishing packages.config?
Anyone know why packages.config end up in the publish folder?

devenv copies files from other project during incremental build

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.

ClickOnce : deploy files to different location

Using ClickOnce, is it possible to include a file (resource, dll, image, whatever) to be copied to a different location and NOT the app folder?
What I am trying to achieve exactly is to install Microsoft.Web.Publishing.Tasks.dll + Microsoft.Web.XmlTransform.dll and their .targets to C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web so those msbuild tasks can be used on workstations that do not have Visual Studio installed.
It was so easy using a Setup Project before VS 2013!!
I repeat: I do NOT want those files to be installed in the app folder (so please don't tell me to set the option Copy to Output = Always" on project files).
Thanks.
No. You can't do it with ClickOnce.
Either deploy the files and write code to copy files when your app starts. Or use some other deployment option, like msi.

Resources