Identifying Nuget package references which are using relative paths across whole solution
Keeping up with a recent binge upgrading projects, including upgrading all my projects in a solution to 4.8, I have been upgrading nuget packages. Whilst this is a relatively simple task, what irks me is that when you add or upgrade a nuget package in Visual Studio, it will often change the package path to be relative to the project file.
What does the issue look like?
When we do something like Install-Package EntityFramework -Version 6.3.0
we end up with something like this in the CSPROJ
As we can see, the <HintPath>
is using a relative path based on the project file location to the solution file (As packages are kept under /Packages at the same level of the .sln)
Why is this a problem? Although it could “just work” for some scenarios, if there are shared libraries which are used across different solutions we can end up with a build failure due to missing packages! Ideally, the hint path should start with $(SolutionDir)packages\
so the correct package will be located regardless of the solution being built.
There are workarounds to stop this occurring (I had varied results), but this doesn’t really solve the issue of retrospectively locating all the places this has happened!
Identifying all references which use relative paths
My solution has close to a hundred projects nested within it, so a manual check could be problematic and prone to human error.
Below is a snippet that will take a Solution file, and for each project check for any hint path which does not contain $($SolutionDir)
providing the directory and solution name are changed.
Once the script runs it will output any projects and hint paths that may be an issue. For me it was simply going over these one by one and changing everything before \Packages (i..e …\..\..\somefolder\Packages\) to use the solution directory variable – i.e. $(SolutionDir)\Packages
Creating a helper in Visual Studio
Although the snippet above will quickly identify any potential issues, it’s not very reusable as you have to change the paths for each solution.
One thing we can do is add a custom tool into Visual Studio to execute the Powershell on demand for the given solution.
To do this, first save the script in the snippet below to your own system. Note this is slightly different to the script above as it takes in a parameter.
Once this is done, go to Visual Studio -> Tools -> External Tools -> Add
In here we can make a new external tool called something like “Find Bad References”.
Command: Path to the system Powershell executable. C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Arguments: -file "C:\Path\To\File.ps1" $(SolutionFileName)
Initial Directory: $(SolutionDir)
Use Output Window: Checked
Now, once saved we should have a new option under tools with the same name as the provided title.
Once clicked, it will execute the script and provide results (if any) in the output tab.
Final thoughts
This isn’t great, and there are plugins that do similar things already, hell, some may even automatically fix these issues! This was designed to scan and generate the potential issues for a manual verification. Feel free to improve it and let me know!