-
Notifications
You must be signed in to change notification settings - Fork 258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NullReferenceException during list package in NuGet.CommandLine.XPlat #13397
Comments
@carstencodes Thanks for reaching out. I was able to reproduce the problem with the example scenario. The SolutionDir is a macro variable that, according to the documentation, is only defined when building a solution in the IDE. Therefore, it won't be set when running the dotnet list package command. I understand what you're wanting to accomplish, and we handle a similar scenario in our NuGet codebase. Rather than using SolutionDir to define the path to the solution, we define a variable called RepositoryRootDirectory and reference that in the BaseIntermediateOutputPath. I applied the same technique to the sample you provided and got this to work by making the BaseDir.props as follows:
With that in place, the |
Hi @jebriede thanks for coming back to me. I replaced all occurrences of SolutionDir with a matching RepositoryRootDir Variable, that we were using before. In my example, it works. If I apply it to my real solution, the issue remains. In my binary log, I see, that the variable has the correct value. If I run
Is there any switch or anything else that I could try to increase verbosity? Or to find the place that actually bugs our config? |
If it is more helpful: I was able to narrow it down to this, where the exception is not passed to the logger and hence get lost / swallowed. I am currently not able to build a version of XPlat with this fix locally, as I cannot get a version of MsBuild (which seems to be loaded dynamically) to be loaded. |
Looks like you got a new error message there, did you run a rebuild or restore before trying dotnet command? |
@jgonz120 Yes, I run the restore first. Then I run the list package command. |
I was actually able to get more output from XPLat:
I think, the faulting lines might be these ProjectItemElement packageInCPM = directoryBuildPropsRootElement.Items.Where(i => (i.ItemType == PACKAGE_VERSION_TYPE_TAG || i.ItemType.Equals("GlobalPackageReference")) && i.Include.Equals(topLevelPackage.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
installedPackage = new InstalledPackageReference(topLevelPackage.Name)
{
OriginalRequestedVersion = packageInCPM.Metadata.FirstOrDefault(i => i.Name.Equals("Version", StringComparison.OrdinalIgnoreCase)).Value,
}; From my side it should be:
|
Or - TBH ProjectItemElement packageInCPM = directoryBuildPropsRootElement.Items.Where(i => (i.ItemType == PACKAGE_VERSION_TYPE_TAG || i.ItemType.Equals("GlobalPackageReference")) && i.Include.Equals(topLevelPackage.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
installedPackage = new InstalledPackageReference(topLevelPackage.Name)
{
OriginalRequestedVersion = packageInCPM.Metadata?.FirstOrDefault(i => i.Name.Equals("Version", StringComparison.OrdinalIgnoreCase))?.Value,
}; (I don´t know what will happen after this excpetion has been avoided, but I think that using the projectPackage instead of an ´OriginalRequestedVersion´ with a ´null´ value is preferable) /cc @martinrrm |
Is there a way you can modify the example project so we can reproduce this error? |
I am already trying, but it's tricky. Would you accept a Stripped Version of the project.assets.json alongside with the props and Targets File? With Stripped I mean, that the parts of the File would be redacted that Show Login named etc. In this case I would ASK my Management to publish These Files in a new gist. |
Ok, by comparing some folders after deleting Directory.Build.props and .targets I was able to create a version, where this issue does not occur. The reason is pretty simple and yet silly: Some of our projects still require to run in .NET Fx based applications. Hence they become strong name signed. The strong name is brought to us as a nuget-package, but without a props file, hence the path to the key is constructed within the build folder. In this case, the one who wrote the build recipe simply added the Moving this to GlobalPackageReferences now worked, but it was hell of work to make it work, so I ask you to
Here's how this might work: bool packagesInSync = true; // added by carstencodes
foreach (var library in target.Libraries)
{
var matchingPackages = frameworkDependencies.Where(d =>
d.Name.Equals(library.Name, StringComparison.OrdinalIgnoreCase)).ToList();
var resolvedVersion = library.Version.ToString();
//In case we found a matching package in requestedVersions, the package will be
//top level.
if (matchingPackages.Any())
{
var topLevelPackage = matchingPackages.Single();
InstalledPackageReference installedPackage = default;
//If the package is not auto-referenced, get the version from the project file. Otherwise fall back on the assets file
if (!topLevelPackage.AutoReferenced)
{
try
{ // In case proj and assets file are not in sync and some refs were deleted
var projectPackage = projectPackages.Where(p => p.Name.Equals(topLevelPackage.Name, StringComparison.Ordinal)).First();
// If the project is using CPM and it's not using VersionOverride, get the version from Directory.Package.props file
if (assetsFile.PackageSpec.RestoreMetadata.CentralPackageVersionsEnabled && !projectPackage.IsVersionOverride)
{
ProjectRootElement directoryBuildPropsRootElement = GetDirectoryBuildPropsRootElement(project);
ProjectItemElement packageInCPM = directoryBuildPropsRootElement.Items.Where(i => (i.ItemType == PACKAGE_VERSION_TYPE_TAG || i.ItemType.Equals("GlobalPackageReference")) && i.Include.Equals(topLevelPackage.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
installedPackage = new InstalledPackageReference(topLevelPackage.Name)
{
OriginalRequestedVersion = packageInCPM.Metadata.FirstOrDefault(i => i.Name.Equals("Version", StringComparison.OrdinalIgnoreCase)).Value,
};
}
else
{
installedPackage = projectPackage;
}
}
catch (Exception)
{
/* changed by carstencodes */
packagesInSync = false;
logger.Log(new LogMessage(LogLevel.Warning, string.Format(CultureInfo.CurrentCulture, Strings.ListPkg_PackageNotFound, topLevelPackage.Name)));
continue;
/* end change */
}
}
else
{
var projectFileVersion = topLevelPackage.LibraryRange.VersionRange.ToString();
installedPackage = new InstalledPackageReference(library.Name)
{
OriginalRequestedVersion = projectFileVersion
};
}
installedPackage.ResolvedPackageMetadata = PackageSearchMetadataBuilder
.FromIdentity(new PackageIdentity(library.Name, library.Version))
.Build();
installedPackage.AutoReference = topLevelPackage.AutoReferenced;
if (library.Type != "project")
{
topLevelPackages.Add(installedPackage);
}
}
// If no matching packages were found, then the package is transitive,
// and include-transitive must be used to add the package
else if (transitive) // be sure to exclude "project" references here as these are irrelevant
{
var installedPackage = new InstalledPackageReference(library.Name)
{
ResolvedPackageMetadata = PackageSearchMetadataBuilder
.FromIdentity(new PackageIdentity(library.Name, library.Version))
.Build()
};
if (library.Type != "project")
{
transitivePackages.Add(installedPackage);
}
}
}
var frameworkPackages = new FrameworkPackages(
target.TargetFramework.GetShortFolderName(),
topLevelPackages,
transitivePackages);
resultPackages.Add(frameworkPackages);
}
// added by carstencodes
if (!packagesInSync) {
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ListPkg_ErrorReadingReferenceFromProject, projectPath));
}
return resultPackages; This would be very helpful. I you like to, I would submit a PullRequest. |
Team Triage: We'd be happy to consider a PR. Note that we haven't looked at your exact change in detail, but we think it'd be great to fix the NRE. |
I just had a quick read of the last few comments, and it sounds like there might be a bug in the overall approach that list package uses. The assets file already defines all the direct package references the project has, so list package should not be reading PackageReferences from the project. In my opinion, list package should only read the project to find the assets file location, and then do everything else using only the assets file. If list package is reading PackageReferences from the project, another potential error scenario is restore the project, then add a new PackageReference without restoring, then run list package. We need a better error message than a null reference exception, but I really don't think that list package should be getting package information from anywhere other than the assets file. |
I haven't dug in, but I'm guessing the reason why the declared package versions are being read from the project file is because the assets file only contains the normalized versions. |
TBH, I'm not quite sure, if it is a good idea to modify the way the files are read. I'm not really familiar with the way HOW the information is gained or the information is consumed. The solution I suggested is a local optimum, not a global one, as I haven't dug into the rest of the code that deep and don't know what I could possibly destroy with this ... |
NuGet Product Used
dotnet.exe
Product Version
8.0.204
Worked before?
No response
Impact
It's more difficult to complete my work
Repro Steps & Context
This issue has already been created in .NET SDK, but was closed There with the hint that It's more likely to be a NuGet issue.
Describe the bug
When I run
dotnet list package
for a solution wherea) Non-project MsBuild-Properties are used, e.g.
SolutionDir
b) Directories are not defaulted, e.g.
BaseIntermediateOutputPath
the command exits with an error, saying that
$(MSBuildProjectDirectory)obj\
In our solution we have > 200 projects. These projects use a common base intermediate output path set to
$(SolutionDir)obj\$(MSBuildProjectName)\
as it makes it easier to reset the files.To Reproduce
An example can be found at this gist
Expected output
Actual output
Diagnostic output is not helpful:
Workarounds
None applicable. From my point of view, it would be applicable to pass MsBuildVarialbles to
dotnet list package
, e.g.Exceptions (if any)
No exception to be found.
Further technical details
Verbose Logs
The text was updated successfully, but these errors were encountered: