NuGet without cache in VS 2017 - msbuild

Is there a way to tell a Visual Studio solution not to use the NuGet caches when restoring packages on VS 2017? I know you can pass the -NoCache parameter to nuget from the command line, but VS doesnt give me the options to set those command line parameters.
I've tried clearing the local cache as a pre-build event in a project, but that takes place AFTER the nuget restore, so I have to rebuild twice for that solution to work.
I've also tried going back to the old way of nuget Package restore with NuGet.Targets, but then I lose use of the credential manager, so packages completely fail to load.

I've tried clearing the local cache as a pre-build event in a project,
but that takes place AFTER the nuget restore, so I have to rebuild
twice for that solution to work.
Maybe you can try using a "after-build" target to clean the cache?
I mean in a scenario where you have projects from A to G, project A consumes a package called NugetOne. We built the project A and the NugetOne will be added to cache.(C:\Users\xxx\.nuget\packages).
Now we're working in project B which also will consume NugetOne, we want to delete the cache before the restore when building the project in VS. But according to the comments above, this approach failed.
So maybe we can add a target which runs after build to clean the cache. And we can add the target to project A or project B to get similar result:
If we add it to A: After building A successfully, the cache has been cleaned, then when building B, we have no need to worry about the impact of the cache.
If we add it to B: It works like the pre-build-event you use,have to rebuild twice to make it work.
Not sure if it's what you want, but if you want a development environment in which development won't be affected by cache from other projects.You can consider using a Directory.Build.props.
My content of Directory.Build.props(Add it to /repos folder, it will impact all your solutions under it, Add it to solution and it will impact all projects in this solution):
<Project>
<Target Name="CleanCache" AfterTargets="build">
<Message Importance="High" Text="Clean the cache..."/>
<xxx //Do your clean cache action here! />
</Target>
</Project>
Hope it helps in some aspects.

Related

How to kill VBCSCompiler.exe on Ubuntu agent?

I created an Azure Devops Build pipeline and i am trying to build my ASP.NET MVC and Angular hybrid site project on bitbucket (git).
The project first gets checked out, and nuget restores the necessary packages, and then the .NET builds. I used windows 2019 as azure pipeline agent for the build to succeed. however, Its taking about 7 minutes to complete, whilst running the tasks (besides .Net) on a ubuntu agent is much faster! takes around 2 mins instead!
Therefore, I'd like to use ubuntu, but im running into an issue with the MSBuild task...
"/home/vsts/work/1/s/Bobby.ProjectA/Bobby.ProjectA.csproj" (default target) (1) ->
(KillVBCSCompilerAndRetryCopy target) ->
/home/vsts/work/1/s/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8/build/net45/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props(23,5):
error MSB4044: The "KillProcess" task was not given a value for the required parameter "ImagePath". [/home/vsts/work/1/s/Bobby.ProjectA/Bobby.ProjectA.csproj]
According to this post, VBCSCompiler.exe continues running from the Compiler Nuget package (nuget restore task?) so it locks the src folders and prevented future builds from running, e.g. causing error like this:
/home/vsts/work/1/s/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8/build/net45/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props(17,5):
warning MSB3021: Unable to copy file "/home/vsts/work/1/s/packages/Microsoft.Net.Compilers.2.4.0/build/../tools/csc.exe" to "/bin/roslyn/csc.exe". Access to the path '/bin/roslyn' is denied. [/home/vsts/work/1/s/Bobby.ProjectA/Bobby.ProjectA.csproj]
So the solution would be to kill the VBCSCompiler.exe but since i cant actually access the hosted machine during the build, im not sure how to do that.
screenshot of my pipeline so far:
Am i facing a dead-end path here with this approach? The build runs fine on windows 2019 but it just takes too long, so thats why if i can make it run on ubuntu successfully that would be great!
You can have a try with below workarounds:
1,Set MSBUILD arguements /p:UseSharedCompilation=false.
You can add above arguement to the msbuild arguements field of the msbuild task. See here.
2,Upgrade Microsoft.CodeDom.Providers.DotNetCompilerPlatform nupkg to the latest and remove Microsoft.Net.Compilers nupkg from your project. See here for more information.
3, Try Specifing the TTL of Roslyn compiler server.
You can define a pipeline variable VBCSCOMPILER_TTL on the Variable tab to specify a shorter idle time for VBCSCompiler.exe
Or you can add <providerOption name="CompilerServerTimeToLive" value="[num of seconds]" /> under system.codedom/compilers/compiler in the config file. See here for more information.
4, Use CheckIfShouldKillVBCSCompiler target:
You can try add below to your csproj file:
<Target Name="CheckIfShouldKillVBCSCompiler">
<PropertyGroup>
<ShouldKillVBCSCompiler>true</ShouldKillVBCSCompiler>
</PropertyGroup>
</Target>
See here.
The build on Ubuntu 20 finally worked! I don't know why removing these lines resolved the VBCSCompiler issue, but by doing so, the msbuild completed successfully on Ubunutu 20 agent!!
Remove the following lines from the .csproj file:
<Import Project="..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props')" />
<Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))" />
To give some context to the answer, this post here indicated that converting from MSBuild-Integrated Package Restore to Automatic Package Restore (nuget restore task) implied that the Microsoft.Net.Compilers <Import> and <Error Condition> snippets are no longer relevant/needed in the .csproj file.

Wix Nuget Packages

So here's the scenario: I have several wix projects that the exact same extra msbuild targets and tasks to automate some very tedious tasks: things like building a help file and authenticode signing the msi and output files using signtool.exe.
Having gotten tired of copying changes to these scripts into 5 different repositories every time I made a fix. So I got clever and I turned them into nuget packages with a .targets file in the build folder. A simple nuget restore turns a laundry list of packages into targets files.
The problem
Wix v3 doesn't like packages. It doesn't support package references so packages.config looks like the thing. Except that visual studio doesn't like packages.config. It will happily restore the packages (into the folder I specified with a nuget.config) but none of the .targets files are automatically imported.
Easy enough to fix: I just added an import statement into my wixproj file. Except that visual studio doesn't automatically re-evaluate the wixproj after running the restore operation. We can work with this, but it is really annoying to have to build, unload the project, reload the project, and rebuild any time the packages change.
So I tried to fix it
I crawled through the log output of a standard C# project build and discovered the Nuget.Targets file, which can be imported into a project to provide pack and restore targets. It also let me convert to packagereferences, which are somewhat more convenient and less messy than packages.config, but I still had to manually add the import statement for the nuget.g.targets and nuget.g.props files that were produced by the restore target.
And, since I had to manually import those files, I'm right back to the build, unload, reload, rebuild workflow.
Attempt number 2
I discovered through intense internet searching that msbuild recently added a /restore flag to their command line utility specifically to force a project re-evaluation after restoring packages. This works on the command line, but visual studio seems to be clueless. (Maybe because of something that wix v3 does behind the scenes in the Visual Studio template?) In any case, they mentioned in the issue notes that they are essentially using an msbuild task with new global properties to force a re-evaluation. So I attempted to add such a step to the pre-build event of my wixproj, but no sauce.
The question
How do I tell visual studio to re-evaluate this wixproj after running restore? Is there some sort of property or item group I need to add to the wixproj? Is there some kind of target I can insert into the build process?
Update 1:
Found a project property that looked promising: UseHostCompilerIfAvailable, but it didn't work. Still got the same problem.

TeamCity - Microsoft.Bcl.Build Dependency

I've just committed some code changes to my repository and all of a sudden (after weeks of being fine). The TC build starts failing as it fails to download the NuGet package for Microsoft.Bcl.Build.1.0.6.
I ended up having to manually copy the contents of the packages directory to the TC build location which utterly defeats the point of NuGet.
What can I check to get to the root cause of this?
Everything about NuGet is enabled in the solution for getting packages.
I've blogged about this issue at http://sedodream.com/2012/12/24/SlowCheetahBuildServerSupportUpdated.aspx. To summarize NuGet package restore (prior to 2.7) is implemented as a part of the MSBuild build process. When MSBuild starts a build it will evaluate the project file and any Import declarations importing other files. This happens before any target gets executed.
Since NuGet pkg restore is a part of the build process the .targets files get restored at a point in time that it is too late for the Import statement to have any impact.
You can work around this by either checking in the .targets file as you stated, or by invoking pkg restore before the build process. I've created a NuGet package, PackageRestore, which can help with the latter approach.
To use PackageRestore just add the NuGet package to your project which will automatically create a file named packageRestore.proj in your projects directory. When configuring your build, you will need to build that item before your .sln/.csproj file.
OK This is a bit of a nasty issue.
If you are having this problem you need to do something rather ugly to your repository.
Make sure you are checking in the packages\repositories.config file.
Then if your build is failing with unresolved references to Microsoft.Bcl.Build you will need to also checkin the .targets file for this package. eg:
package\Microsoft.Bcl.Build.x.x.x\tools\Microsoft.Bcl.Build.targets
Hideous ...
This blog post is the most thorough one I've seen for explaining the workaround options:
http://blogs.msdn.com/b/dotnet/archive/2013/06/12/nuget-package-restore-issues.aspx
None are great IMO - this problem still needs a better solution.
But for the time being, the best recommended option is to check the Bcl.Build .targets file into source control - which means when the version of Bcl.Build is updated, you'll need to add the new .targets file, and remove the old one.
I think (but am not sure, so I created this SO question: What does the Microsoft.Bcl.Build NuGet package do?) that Microsoft.Bcl.Build is only needed for development, and is not needed on a build server. So, I have a Builder.targets file that only exists in the build environment, that is indirectly <import> ed into all of our projects, which includes this bit of MSBuild xml:
<!-- Skip Microsoft.Bcl.Build functionality when building only from Source. Presumably Microsoft.BclBuild is only needed for development. -->
<PropertyGroup>
<BclBuildImported>Ignore</BclBuildImported>
</PropertyGroup>
Since the block of MSBuild logic inserted into your project by the Bcl.Build nuget package is dependent on the BclBuildImported property being empty, this effectively sidesteps the problem in my build environment - the Microsoft.Bcl.Build steps are skipped, and it no longer breaks my CI builds.
Note that since it appears that this package manages binding redirects in your app.config, and ensures that transitive dependencies are included in your projects, it's important to leave in for development. But I'm not currently aware of a need for it in a build server environment.

Running custom MSBuild tasks as part of the git deployment to Azure WebSites

Problem
As part of my csproj I have a custom MSBuild task that executes the YUICompressor and generates a compiled css and js file.
<PropertyGroup>
<CssOutputFile>$(OutDir)..\Styles\compiled.css</CssOutputFile>
<JavaScriptOutputFile>$(OutDir)..\Scripts\compiled.js</JavaScriptOutputFile>
<BuildDependsOn Condition="'$(Configuration)' != 'Debug'">
$(BuildDependsOn);
CompressorTarget;
</BuildDependsOn>
</PropertyGroup>
This runs fine as part of the git deployment and the file is being generated, however the Azure Web Sites deployment engine will then copy all the output files to another folder. In that process it seems it takes whatever you have in your csproj instead of whatever you have in the folder. That menas that the generated compiled.css and compiled.js won't be copied (because they are not in my csproj)
What Azure does to deploy your project should be exactly the same as if you do the following:
Right click on the project and choose Publish
Change the Publish Method to 'File System'
Enter a path and click Publish
So generally, you'll want to make sure that your build process works such that you get the right file when you do this local publish. If it does, then chances are you'll get the same results when git pushing to Azure.
The workaround I used for now is adding an empty compiled.css and .js file to the csproj and I wanted to write this question in case someone goes through the same thing.
It would be great if someone from MS can comment if there are plans on doing something different for this scenario.
Depending on where you place the compiled scripts, you can use star-includes in your project file:
<ItemGroup>
<Content Include="assets\**\*" />
</ItemGroup>
If Azure uses your project file to determine what gets deployed (which seems somewhat strange to start with), then that should work.

MSBuild speedup: how to remove unnecessary project builds?

I have a solution with several projects in it. Let's say
project A depends on projects B and C
project B depends on project C
When I run my solution on the local machine VS builds each project once and it takes 1 minute. However, on our build machine it takes about 4 minutes to build and, as I can understand from the MSBuild logs it goes like this:
build A -> build B for A, build C for A
build B -> build C for B
So it builds some projects several times... How can I speed up the build process?
P.S. It's not a question of 3 extra minutes, I just wonder why is it so different from my local machine build?
I am not sure about your build order. Sometimes TeamBuild can look like it is building projects over and over but it is building for different configurations. Take a look and make sure you have not defined multiple FlavorsToBuild.
Also, if you don't want to do a fresh check out and rebuild every time, you can define this at the bottom of your TFSBuild file.
<PropertyGroup>
<IncrementalBuild>true</IncrementalBuild>
</PropertyGroup>-->
Put that right before the </Project> tag.
This sample seems to work for me. TestLib.Extra depends on TestLib. If I change something in TestLib, both projects will build. If I change only in TestLib.Extra, only that one will build, and if I don't change anything at all, they will just report Skipping target "CoreCompile" because all output files are up-to-date and so on.
<Target Name="Build">
<MSBuild Targets="Build" Projects="TestLib\TestLib.csproj" />
<MSBuild Targets="Build" Projects="TestLib.Extra\TestLib.Extra.csproj" />
</Target>
The trick is to use the "Build" target of the projects, rather than "Rebuild". The difference between these is essentially the same as the difference between the "Build" and "Rebuild" commands in the build menu in Visual Studio.
Edit
This works well also if the projects are included in a solution file, and you specify the solution to build instead:
<Target Name="Build">
<MSBuild Targets="Build" Projects="TestLib.sln" />
</Target>
Maybe like our's, your build server is a virtual machine (10x at least slower).
Also TFS (and maybe others), does a fresh checkout on build, so it will have to build all the projects regardless.
Are you using the /maxcpucount switch? There may be a difference in number of processors between your local machine and the build machine. This setting can also be different between your msbuild file and the visual studio setting which could also explain the difference you're seeing in build times.
I do this as follows. It is somewhat complicated custom build system but the basic idea is.
The dlls which are reused in many solutions are build to a known folder. This is achieved my using a msbuild project file that builds these common dlls.
When building other csproj files in a solution we copy the csproj files then use xslt manipulation to replace the project references with dll refernces for those common dlls.
The build scripts then build these changed csproj files using custom msbuild project files we maintain corresponding to each solutions. We don't build .sln files. These custom project files is a itemgroup of .csproj files in correct dependency order.
Maybe this can help you in achieving what you want.