[Windows翻译]分析.NET Core项目的依赖性。寻找包引用

294 阅读3分钟

原文地址:www.jerriepelser.com/blog/analyz…

原文作者:www.jerriepelser.com/

发布时间:2018年6月20日

PS:如果你在任何ASP.NET Core项目上需要帮助,我可以受聘做自由职业者

在开发dotnet-outdated时,我必须找到一种方法来确定一个项目所引用的包。起初,我使用BuildAlyzer,但在一个用户的建议下,我决定使用.NET Core CLI本身来生成一个依赖关系图。

依赖关系图将指出需要恢复的项目的所有依赖关系,还包含有用的附加信息,如项目的目标框架和NuGet包源,这些包应该用于恢复NuGet包,在dotnet-outdated的情况下,应该用于扫描上述包的较新版本。

依赖关系图的另一个有用的特性是,当针对解决方案文件使用时,它将包含解决方案中所有项目的输出。

要生成依赖关系图,可以使用dotnet msbuild命令,传递/t:GenerateRestoreGraphFile/p:RestoreGraphOutputPath参数。

例如,在包含.NET Core/.NET Standard项目或解决方案的目录下运行以下命令,将输出一个名为graph.dg的依赖关系图文件。

dotnet msbuild /t:GenerateRestoreGraphFile /p:RestoreGraphOutputPath=graph.dg

上面的示例命令将尝试在运行它的目录中定位一个解决方案或项目,但你也可以将解决方案或项目的路径传递给它。

dotnet msbuild MySolution.sln /t:GenerateRestoreGraphFile /p:RestoreGraphOutputPath=graph.dg

依赖关系图的结构

以下是本博文所附的项目生成的依赖关系图输出示例。

{
  "format": 1,
  "restore": {
    "C:\\Development\\jerriepelser-blog\\AnalyzeDotNetProject\\AnalyzeDotNetProject.csproj": {}
  },
  "projects": {
    "C:\\Development\\jerriepelser-blog\\AnalyzeDotNetProject\\AnalyzeDotNetProject.csproj": {
      "version": "1.0.0",
      "restore": {
        "projectUniqueName": "C:\\Development\\jerriepelser-blog\\AnalyzeDotNetProject\\AnalyzeDotNetProject.csproj",
        "projectName": "AnalyzeDotNetProject",
        "projectPath": "C:\\Development\\jerriepelser-blog\\AnalyzeDotNetProject\\AnalyzeDotNetProject.csproj",
        "packagesPath": "C:\\Users\\jerri\\.nuget\\packages\\",
        "outputPath": "C:\\Development\\jerriepelser-blog\\AnalyzeDotNetProject\\obj\\",
        "projectStyle": "PackageReference",
        "fallbackFolders": [
          "C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
        ],
        "configFilePaths": [
          "C:\\Users\\jerri\\AppData\\Roaming\\NuGet\\NuGet.Config",
          "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
        ],
        "originalTargetFrameworks": [
          "netcoreapp2.1"
        ],
        "sources": {
          "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
          "https://api.nuget.org/v3/index.json": {}
        },
        "frameworks": {
          "netcoreapp2.1": {
            "projectReferences": {}
          }
        },
        "warningProperties": {
          "warnAsError": [
            "NU1605"
          ]
        }
      },
      "frameworks": {
        "netcoreapp2.1": {
          "dependencies": {
            "Microsoft.NETCore.App": {
              "target": "Package",
              "version": "[2.1.0, )",
              "autoReferenced": true
            },
            "NuGet.ProjectModel": {
              "target": "Package",
              "version": "[4.7.0, )"
            },
            "newtonsoft.json": {
              "target": "Package",
              "version": "[11.0.2, )"
            }
          },
          "imports": [
            "net461"
          ],
          "assetTargetFallback": true,
          "warn": true
        }
      }
    }
  }
}

project节点下,你会注意到一个实际项目的条目。在有多个项目的情况下(例如当针对解决方案文件生成它时),projects节点将包含每个项目的单独子节点。

sources节点表示恢复NuGet包时应该使用的NuGet源列表。这些也可以用来扫描所述NuGet包的更新。

frameworks 节点将包含项目中每个目标框架的条目,在下面的 dependencies 节点下,你会发现每个包引用的条目以及包的版本。

处理依赖关系图

现在我们已经有了一个依赖关系图,我们需要做的就是处理这个JSON文件,以了解一个解决方案的实际结构和它的项目,以及每个项目的目标框架以及该目标框架的依赖关系。

你可以自己使用JSON.NET等库进行处理,但事实证明,NuGet客户端库已经包含了.NET类来帮助你处理依赖图。

NuGet.ProjectModel包添加到你的项目中。同时添加Newtonsoft.Json包。

dotnet add package NuGet.ProjectModel
dotnet add package Newtonsoft.Json

现在你可以从生成的文件中加载依赖关系图的内容,将JSON反序列化为一个JObject,然后将其传递给DependencyGraphSpec类的构造函数。

string dependencyGraphText = File.ReadAllText(dgOutput);
var dependencyGraph = new DependencyGraphSpec(JsonConvert.DeserializeObject<JObject>(dependencyGraphText));

DependencyGraphSpec实例允许你遍历项目,为每个项目提供目标框架,为每个目标框架提供引用。

foreach(var project in dependencyGraph.Projects.Where(p => p.RestoreMetadata.ProjectStyle == ProjectStyle.PackageReference))
{
    Console.WriteLine(project.Name);
    
    foreach(var targetFramework in project.TargetFrameworks)
    {
        Console.WriteLine($"  [{targetFramework.FrameworkName}]");

        foreach(var dependency in targetFramework.Dependencies)
        {
            Console.WriteLine($"  {dependency.Name}, v{dependency.LibraryRange.VersionRange.ToShortString()}");
        }
    }
}

当处理dotnet-outdated的源码时,会产生以下输出。

下一篇博文中,我将更深入地探讨如何确定一个项目的过渡性依赖关系。

我整理了一个演示这些技术的示例应用程序,你可以在 github.com/jerriepelse… 找到它。


www.deepl.com 翻译