原文地址:www.jerriepelser.com/blog/analyz…
发布时间: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… 找到它。