NuGet for Website Projects
The Problem
Unlike proper Web Application
projects, Website
projects in Visual Studio just take everything under a folder and assume that is the project. And 9 times out of 10 (based on the handful of times I have dealt with them) these projects, when in source control, have all binaries checked in as well.
References can be sorta made using NuGet
on the Bin
folder, but in my experience this only sort-of works: .refresh
files are added to the folder as a kind of redirect to the original file located elsewhere (like the ../packages
directory. These refreshes are triggered at certain times like when the project is opened or switching between projects. It also does not care about any folders nested underneath like the Bin/roslyn
folder.
That kinda stinks.
The Solution
A single Powershell file to help facilitate the restore and frankly, copying of dlls locally so we can work without having to shove binary files in source.
In addition to the script, I also included a custom nuget.config
to allow for other NuGet
feeds (like Telerik
).
Folder Structure:
- Project/ (root)
- .nuget/nuget.config
- lib/
- packages/
- src/
- restore.ps1
.nuget/nuget.config
Make sure we have all the dependencies we need, in our case we needed Telerik
as well, which happens to be authenticated.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="Telerik" value="https://nuget.telerik.com/nuget" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<activePackageSource>
<add key="All" value="(Aggregate source)" />
</activePackageSource>
<packageSourceCredentials>
<Telerik>
<add key="Username" value="bob@pizza.co" />
<add key="ClearTextPassword" value="NoToppings!" />
</Telerik>
</packageSourceCredentials>
</configuration>
restore.ps1
Handle what the package manager in a website project can’t:
set-location $PSScriptRoot
Write-Host "Executing NuGet self update and restore" -ForegroundColor Green
nuget update -self
nuget restore .\src\packages.config -PackagesDirectory packages
set-location $PSScriptRoot\src
Write-Host "Copying files for .refresh" -ForegroundColor Green
Get-ChildItem -Path ./ -Filter *.refresh -Recurse -File -Name | ForEach-Object {
$referenceFile = Get-Content $_
$destinationFile = $_.Replace(".refresh", "")
Write-Host $referenceFile " -> " $destinationFile
Copy-Item $referenceFile -Destination $destinationFile
}
Executing this script does the following:
NuGet
self updateNuGet
restore using thepackages.config
maintained by the project and puts them one layer up in the../packages
directory- Iterates thru all of the
.refresh
files in the project and copies over the original*.dll
file to the location of the.refresh
file.
This helped a lot for local development, particularly for the initial environment setups. Queue the next step…
CI/CD
Along with this effort, we also helped set up CI/CD
within Azure Devops
. We used a very similar principle in resolving the dependencies during the Build pipeline:
- Use NuGet 5.5.0 task
- NuGet restore task
- Path to NuGet.config
$/Project/.nuget/nuget.config
- Destination Directory
$(UserProfile)/.nuget/packages
- Path to NuGet.config
- PowerShell Script task (inline)
-
Write-Host $PSScriptRoot Write-Host "Copying files for .refresh" -ForegroundColor Green Get-ChildItem -Path ./ -Filter *.refresh -Recurse -File -Name | ForEach-Object { $referenceFile = (Get-Content $_).Replace("..\packages","$(UserProfile)\.nuget\packages") $destinationFile = $_.Replace(".refresh", "") Write-Host $referenceFile " -> " $destinationFile Copy-Item $referenceFile -Destination $destinationFile }
-
- Build Solution task
- Solution:
$/Project/src/website.publishproj
- MSBuild Arguments
/p:deployOnBuild=true
/p:publishProfile=Project
/p:publishUrl="$(build.artifactstagingdirectory)\\"
- Publish Artifacts task
The result of the above pipeline and really the entire effort is a solution that doesn’t involve checking in binaries, uses NuGet and overall feels just slightly closer to normal Web Application development.
Hope this helps!