如何在解决方案中查找未使用的NuGet软件包?
我有很多解决方案,安装了很多软件包,并且其中有很多被标记为需要更新。
但是,我担心会有破坏性变化,因此首先想要通过删除任何未使用的软件包来清理。
如何在解决方案中查找未使用的NuGet软件包?
我有很多解决方案,安装了很多软件包,并且其中有很多被标记为需要更新。
但是,我担心会有破坏性变化,因此首先想要通过删除任何未使用的软件包来清理。
ReSharper 2016.1有一个功能,可以删除未使用的NuGet包。
它可以在解决方案上运行,也可以在解决方案中每个项目上运行,并执行以下操作:
不幸的是,这对于project.json
项目(RSRP-454515)和ASP.NET core项目(RSRP-459076)无效。
您可以使用 ReSharper 2019.1.1 来完成此操作。
右键单击项目 > 重构 > 删除未使用的引用。
如果您的项目规模较小,可以使用:项目 > 优化已使用的引用 . . .
一个窗口将弹出。选择所有引用并将它们全部删除。然后重新添加那些给您编译错误的引用。
function Get-PackageReferences {
param($FileName, $IncludeReferences, $IncludeChildReferences)
$xml = [xml] (Get-Content $FileName)
$references = @()
if($IncludeReferences) {
$packageReferences = $xml | Select-Xml -XPath "Project/ItemGroup/PackageReference"
foreach($node in $packageReferences)
{
if($node.Node.Include)
{
if($node.Node.Version)
{
$references += [PSCustomObject]@{
File = (Split-Path $FileName -Leaf);
Name = $node.Node.Include;
Version = $node.Node.Version;
}
}
}
}
}
if($IncludeChildReferences)
{
$projectReferences = $xml | Select-Xml -XPath "Project/ItemGroup/ProjectReference"
foreach($node in $projectReferences)
{
if($node.Node.Include)
{
$childPath = Join-Path -Path (Split-Path $FileName -Parent) -ChildPath $node.Node.Include
$childPackageReferences = Get-PackageReferences $childPath $true $true
$references += $childPackageReferences
}
}
}
return $references
}
function Get-ProjectReferences {
param($FileName, $IncludeReferences, $IncludeChildReferences)
$xml = [xml] (Get-Content $FileName)
$references = @()
if($IncludeReferences) {
$projectReferences = $xml | Select-Xml -XPath "Project/ItemGroup/ProjectReference"
foreach($node in $projectReferences)
{
if($node.Node.Include)
{
$references += [PSCustomObject]@{
File = (Split-Path $FileName -Leaf);
Name = $node.Node.Include;
}
}
}
}
if($IncludeChildReferences)
{
$projectReferences = $xml | Select-Xml -XPath "Project/ItemGroup/ProjectReference"
foreach($node in $projectReferences)
{
if($node.Node.Include)
{
$childPath = Join-Path -Path (Split-Path $FileName -Parent) -ChildPath $node.Node.Include
$childProjectReferences = Get-ProjectReferences $childPath $true $true
$references += $childProjectReferences
}
}
}
return $references
}
$files = Get-ChildItem -Path C:\MySolutionDirectory -Filter *.csproj -Recurse
Write-Output "Number of projects: $($files.Length)"
$stopWatch = [System.Diagnostics.Stopwatch]::startNew()
$obseletes = @()
foreach($file in $files) {
Write-Output ""
Write-Output "Testing project: $($file.Name)"
$rawFileContent = [System.IO.File]::ReadAllBytes($file.FullName)
$childPackageReferences = Get-PackageReferences $file.FullName $false $true
$childProjectReferences = Get-ProjectReferences $file.FullName $false $true
$xml = [xml] (Get-Content $file.FullName)
$packageReferences = $xml | Select-Xml -XPath "Project/ItemGroup/PackageReference"
$projectReferences = $xml | Select-Xml -XPath "Project/ItemGroup/ProjectReference"
$nodes = @($packageReferences) + @($projectReferences)
foreach($node in $nodes)
{
$previousNode = $node.Node.PreviousSibling
$parentNode = $node.Node.ParentNode
$parentNode.RemoveChild($node.Node) > $null
if($node.Node.Include)
{
$xml.Save($file.FullName)
if($node.Node.Version)
{
$existingChildInclude = $childPackageReferences | Where-Object { $_.Name -eq $node.Node.Include -and $_.Version -eq $node.Node.Version } | Select-Object -First 1
if($existingChildInclude)
{
Write-Output "$($file.Name) references package $($node.Node.Include) ($($node.Node.Version)) that is also referenced in child project $($existingChildInclude.File)."
continue
}
else
{
Write-Host -NoNewline "Building $($file.Name) without package $($node.Node.Include) ($($node.Node.Version))... "
}
}
else
{
$existingChildInclude = $childProjectReferences | Where-Object { $_.Name -eq $node.Node.Include } | Select-Object -First 1
if($existingChildInclude)
{
Write-Output "$($file.Name) references project $($node.Node.Include) that is also referenced in child project $($existingChildInclude.File)."
continue
}
else
{
Write-Host -NoNewline "Building $($file.Name) without project $($node.Node.Include)... "
}
}
}
else
{
continue
}
dotnet build $file.FullName > $null
if($LastExitCode -eq 0)
{
Write-Output "Building succeeded."
if($node.Node.Version)
{
$obseletes += [PSCustomObject]@{
File = $file;
Type = 'Package';
Name = $node.Node.Include;
Version = $node.Node.Version;
}
}
else
{
$obseletes += [PSCustomObject]@{
File = $file;
Type = 'Project';
Name = $node.Node.Include;
}
}
}
else
{
Write-Output "Building failed."
}
if($null -eq $previousNode)
{
$parentNode.PrependChild($node.Node) > $null
}
else
{
$parentNode.InsertAfter($node.Node, $previousNode.Node) > $null
}
# $xml.OuterXml
$xml.Save($file.FullName)
}
[System.IO.File]::WriteAllBytes($file.FullName, $rawFileContent)
dotnet build $file.FullName > $null
if($LastExitCode -ne 0)
{
Write-Error "Failed to build $($file.FullName) after project file restore. Was project broken before?"
return
}
}
Write-Output ""
Write-Output "-------------------------------------------------------------------------"
Write-Output "Analyse completed in $($stopWatch.Elapsed.TotalSeconds) seconds"
Write-Output "$($obseletes.Length) reference(s) could potentially be removed."
$previousFile = $null
foreach($obselete in $obseletes)
{
if($previousFile -ne $obselete.File)
{
Write-Output ""
Write-Output "Project: $($obselete.File.Name)"
}
if($obselete.Type -eq 'Package')
{
Write-Output "Package reference: $($obselete.Name) ($($obselete.Version))"
}
else
{
Write-Output "Project refence: $($obselete.Name)"
}
$previousFile = $obselete.File
}
在这里可以找到更多信息:https://devblog.pekspro.com/posts/finding-redundant-project-references
我认为没有默认的方法来找到这个。主要原因是这些包可以做的事情非常多,从引用程序集到向项目注入源代码。您可能想检查Nuget.Extensions。以下线程在codeplex上讨论了nuget包的审核报告。
http://nuget.codeplex.com/discussions/429694
使用ReSharper或类似的代码分析工具识别项目中未使用的引用并在相应项目中卸载nuget。
有时已卸载的nugets仍然留在“已安装包”和“更新”列表中。在关闭Visual Studio之后删除“packages”文件夹,然后重新打开解决方案并恢复你的nugets。
在JetBrains Rider IDE中:
https://www.jetbrains.com/help/rider/Refactorings__Remove_Unused_References.html