How to deal with the NuGet hell of transitive dependencies in your .NET projects
Navigating through the complexity of NuGet package dependencies aka “NuGet hell” in .NET applications can be a daunting task. The project.assets.json
file, found in the obj
folder of your .NET projects, is a crucial resource in managing these dependencies. This file provides detailed information about the packages used, including direct and transitive dependencies. In this article, we’ll explore what the project.assets.json
file is, how to use it to understand your dependencies, and how it can help you keep your packages up to date.
The bad alternatives to project.assets.json file
To make the problem obvious to the reader, let us show some other ways for identifying the structure of the NuGet dependency tree.
The first way would be by opening Manage NuGet packages
dialog in Visual Studio. However, in that case you see only a list of the transitive dependencies without knowing which direct dependency uses them:
You could now open the Dependencies\Packages
drop-down of your project and try to manually spot the transitive dependency by checking inside all the direct dependencies of your project:
This is not a good idea… Let us see the proper way to search in the dependency tree of your application.
The project.assets.json file
This file is a JSON document which is generated by the .NET SDK during the build process. It contains a comprehensive list of all NuGet packages that your application depends on, including both direct dependencies (packages explicitly added to your project) and transitive dependencies (packages that are dependencies of your direct dependencies).
The JSON contains the following sections:
-
version
: Indicates the version of the file format. -
targets
: Lists all the target frameworks for the project and the dependencies for each target. ** This is the section of our focus in this article**. -
libraries
: Contains information about each NuGet package, including version, SHA hash, and files included in the package. -
packageFolders
: Shows the paths to the package sources. -
projectFileDependencyGroups
: Lists the direct dependencies as specified in the project file.
Identifying Transitive Dependencies
Transitive dependencies are packages that are required by your direct dependencies. Understanding these can help you troubleshoot issues and ensure compatibility. In the project.assets.json
file, you can find transitive dependencies listed under the targets section for each target framework. For example in the following section, the version 18.0.4 of PuppeteerSharp
contains three dependencies:
"PuppeteerSharp/18.0.4": {
"type": "package",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "1.1.0",
"Microsoft.Extensions.Logging": "2.0.2",
"Newtonsoft.Json": "13.0.1"
},
"compile": {
"lib/netstandard2.0/PuppeteerSharp.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/netstandard2.0/PuppeteerSharp.dll": {
"related": ".xml"
}
}
}
Updating NuGet Packages
Based on the information gathered in the dependencies
sections of the direct dependencies you can identify the current versions of the NuGet packages that used from your direct dependencies and update them to the same version.
Conclusion
The project.assets.json
provides a detailed map of all dependencies, including transitive ones and allows you to navigate and manage your project’s package ecosystem effectively. So next time you find yourself in “NuGet hell,” remember that the project.assets.json
file is your guide to navigating through it.