project-system
project-system copied to clipboard
There is no way to query PackageReferences in a project
There are API's to Add or Remove a PackageReference, but there is currently no way to ask if a package reference exists in a project, and if so, what version is it. There's also no way to just enumerate all existing package references.
So you can't positively know if a package is referenced in a project until you have successfully restored packages in a project, at which time existing NuGet related package services will have installed version information and let you enumerate installed packages.
Are you looking for a general API that works with any form of nuget packaging style? As in the same API will work for packages.config, project.json, and .csproj PackageReference? Or are you okay with a special case check for the new PackageReference? And also does this have to work outside of VS?
If you are okay with a special case for this and only running inside VS then there is multiple ways to see what PackageReferences exist. Since it is just an MSBuild item you can get a hold of the msbuild project and ask it for all PackageReference items. Or you can get the Dependency tree and find all nuget packages in it.
I don't think falling back to MSBuild is the right solution here - design-time builds could supplement (or even remove) these things, so just using evaluation will give misleading results.
@jviau What do we do for references here? I think asking consumers of the project system to fall back to MSBuild or listen to the project subscription is too hard and easy to get wrong.
We should have friendly facades over these concepts, a la DTE's Project.References.
it would be nice to have one common thing that tells what the references are whether they are installed or not, without knowing about msbuild or walking build trees/etc, what kind of project it is, etc. It's strange that some kinds of csproj projects give you one answer when calling nuget packages whether installed/restored or not, and another kind of csproj gives you different answers depending on if the user has ever built/restored or not.
because our tooling is specifically built to install some nuget packages and configure a project if they aren't there, we're in this limbo state where until a user builds, we don't know for sure without doing all these kinds of workarounds.
Given that we're a VS Extension, the code only needs to work inside VS. If it has to be a new thing and we have to ask the existing nuget apis AND new ones for package references, fine. but it's really strange right now that there's not even api to ask what package references are supposed to be in this project.
aside: @jviau can you give me details about your "get a hold of the msbuild project and ask it for package reference items" workaround? we need do to something until there's a better way.
@davkean CPS does have support for VSLangProj.References and other types through our OAVS* classes. I did some investigation and found that the new Dependencies tree is not working with our implementation. I will keep looking into it and see where the fix should go.
@gardnerjr the MSBuild way will only tell you what packages should be there, but not what is restored or not, so it may not be sufficient. Considering that I just found some issues with our references DTE layer we may be able to fix that instead of needing a workaround.
@jviau knowing what packages should be there is all we actually need to know. if it should be there, then our tool would show "configure" options, if it isn't found as "should | installed" then we'd show our "add" menu items/etc. given the time left in RC3 is very short, even that kind of workaround is good enough for us for now.
@gardnerjr this document subscribe_to_project_data is probably the best option for you. You will want to subscribe to "PackageReference". And here is how you obtain the UnconfiguredProject the example uses: finding_CPS_in_a_VS_Project
@jviau I pinged Andrew/Lifeng on this offline but I think asking consumers to listen to the project subscription data is the wrong approach, it requires him to understand:
- The msbuild representation of what makes up a package reference both at evaluation and design-time and make sure I agree with all the other services (language service, dependency node, VSLangProj.Referenes, etc). For example, we currently only use evaluation to figure out package references - but we're going to be moving to a design-time build based calculation.
- How metadata values from the evalation/design-time results are interpreted, and make sure that he interprets them the same way that everyone else does
- Snapshots and snapshot versions, and figuring out how to coordinate between evaluation and design-time versions
- Making sure the tree is up-to-date (so that any answers I give match the answers it gives) and dealing the fallout when the active config changes under the covers while I’m waiting on this
@davkean yes I agree, but @gardnerjr wanted a workaround for the time being. @abpiskunov and I are working on getting VSLangProj.References working again with the dependency tree. We are also considering including support for PackageReference in this work as well, but it will need some design.
Yes, i just need a workaround. Is there any way to do this without all the subscriptions? i need a "what are the packagereferences right now" type check for some BeforeQueryStatus VSCT calls. I don't need (or really want) to watch ongoing changes while the user is doing things.
FYI: we were discussing supporting VSLangProj.References with @jviau and are making corresponding changes in Managed project system and CPS. It should work soon hopefully ..
What will packages show up as? Or are we adding new API to support this?
in the UI nothing changes for users. After my change in managed project system, without CPS changes VSLangProj.References would only show usual references (assemblies, projects etc). If CPS changes would be done , then we could also include packages to references and have a new reference type "package" ...
yeah, I'm talking about VSLangProj APIs.
The way it implemented in CPS now, to support VSLangProj.References they look in the tree nodes and check nodes with Reference flag. Then the match them to rules from DT build . I did not support Refernce flag for Dependency nodes, and adding this support right now (review will be soon). This will bring support for regular references. However CPS currently has hardcoded list of rules that thay try to map to VSLangProj.Refernces and it does not include PackageDependency rules, thus until it is supported package would not appear in VSLangProj.References... Thats what Jacob is looking at .
Do we know if this is going to make RTM at this point?
For official support we need to consider how a PackageReference falls into the VSLangProj.Reference interface, or is there a new interface we need to implement for them?
@gardnerjr for now there is a messy way to find all PackageReferences. They are on the DTE tree in the following way: Dependencies -> NuGet -> {PackageReferences}.
You can walk the DTE tree to the NuGet node and then all children are package references. The best way to find the Dependencies tree is to find the node where DTE.ProjectItem.Object is VSLangProj.References is true. From there you can walks its children (on the DTE.ProjectItem layer!, not the VSLangProj layer) to find the node with a caption of "NuGet" and then all children are package references.
This is a very implementation specific work around, and I hope we can come up with a better solution in the future.
Related: this appears to have been "fixed" in nuget recently, though:
https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/PackageManagement.VisualStudio/ProjectSystems/CpsPackageReferenceProject.cs#L174
that means the IPackageInstallerServices.IsPackageInstalled calls there will return true if there are PackageReferences for a package. this "fixes" this issue for me, personally, as that method was returning false in prior versions (like for .xproj in dev14), so i needed some other check if that returned false to see if it was "supposed" to be installed.
Given those fixes were made, it is possible that nothing needs to be done here?
How is everything going on?
@gardnerjr That file you linked to has been moved or deleted, is that fix still in place?
I have recently updated to using PackageReference with the legacy project system and IsPackageInstalled will return true even if that package is a indirect dependency of the project. Then when I attempt to update the project, it will fail because the project doesn't actually have the XML for a PackageReference to the package it claimed to have.