Skip to content

Conversation

@nkolev92
Copy link
Member

@nkolev92 nkolev92 commented Oct 3, 2022

Design for #5154

Rendered

cc @dsplaisted

Copy link

@Nirmal4G Nirmal4G left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some ideas and suggestions. Feel free to ignore it. 😅🙃

@nkolev92
Copy link
Member Author

nkolev92 commented Oct 4, 2022

Thanks for taking a look @Nirmal4G

For context, this is design I'm still working on, I'd say it's at about 50%.

Hoping to add more details about the scenarios and just in general provide more concrete proposals soon.

@Nirmal4G
Copy link

Nirmal4G commented Oct 4, 2022

@nkolev92 These are some of my observations and preliminary suggestions, ideas and takeaways from this draft. I'm not taking this as a concrete proposal. I'm just viewing this from a 10-foot view (or design perspective) of the proposal to see how it could impact normal as well as advanced users. In that mindset, read through my comments again. You would then see what I was talking about.

@Nirmal4G
Copy link

Nirmal4G commented Oct 4, 2022

Hoping to add more details about the scenarios and just in general provide more concrete proposals soon.

Sure, Will look though once you mark this ready for review. Sorry for the uninvited comments. I'll stop now.

@nkolev92
Copy link
Member Author

nkolev92 commented Oct 4, 2022

Hoping to add more details about the scenarios and just in general provide more concrete proposals soon.

Sure, Will look though once you mark this ready for review. Sorry for the uninvited comments. I'll stop now.

Oh no worries. I appreciate the feedback as this is a large doc so getting feedback early on is always great.

My comment was more about that fact that I'll be adding even more info to the doc, setting expectations about when something like this would even be close to happening :)

@JonDouglas
Copy link
Contributor

@ViktorHofer & @ericstj

@zivkan zivkan self-assigned this Nov 13, 2023
@zivkan zivkan marked this pull request as ready for review November 15, 2023 13:27
@zivkan zivkan requested a review from a team as a code owner November 15, 2023 13:27
@zivkan zivkan force-pushed the dev-nkolev92-tfmaliases branch from 55c6bba to 1c19625 Compare November 23, 2023 08:55
@ghost
Copy link

ghost commented Jan 11, 2024

This PR has been automatically marked as stale because it has no activity for 30 days. It will be closed if no further activity occurs within another 15 days of this comment, unless it has a "Status:Do not auto close" label. If it is closed, you may reopen it anytime when you're ready again, as long as you don't delete the branch.

@zivkan
Copy link
Member

zivkan commented Jan 26, 2024

oops, vacation and other priorities has kept this feature on the backburner, but it's still planned.

@Nigusu-Allehu Nigusu-Allehu added the Status:Do not auto close Do not auto close for PRs needs long review process label Jun 4, 2024
@zivkan zivkan marked this pull request as draft July 23, 2024 22:34
Should we consider more significant schema changes in the assets file?

Under `$/libraries`, each package lists every file in the package.
However, the performance penalty of needing to parse that list every time the assets file is read may be worse than any benefit it provides from avoiding enumerating the filesystem when it is needed.
Copy link

@jviau jviau Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a functions extensibility scenario, I am considering having extension packages include a well-known marker file in their nupkg. I was going to leverage the fact that the assets file already has all nupkg file contents listed in it to speed up that process.

With this change, is the suggestion I would need to manually scan the file system of every nuget package? Or do you have an idea of a more general way I can add metadata to a nuget package and read it during a build?

Today we have an assembly attribute and we use Mono.Cecil to scan runtime assemblies from nuget looking for that attribute. This is understandably not performant. Which is why I am considering the marker file approach. I wouldn't block on this change just for our use case, but some metadata system for nupkgs that can be read at build time would be helpful (but obviously that would be an entirely different proposal).

@nkolev92 nkolev92 force-pushed the dev-nkolev92-tfmaliases branch from 1c19625 to ddc7fae Compare September 16, 2025 18:27
@nkolev92 nkolev92 force-pushed the dev-nkolev92-tfmaliases branch from ddc7fae to 413d370 Compare November 26, 2025 17:58
@nkolev92 nkolev92 assigned nkolev92 and unassigned zivkan Dec 1, 2025
@nkolev92 nkolev92 changed the title Design for allowing restore of multiple equivalent frameworks Design for allowing restore of multiple equivalent frameworks (Target Frameworks as Aliases) Dec 12, 2025
@nkolev92 nkolev92 force-pushed the dev-nkolev92-tfmaliases branch from 650ca9a to b6c47f6 Compare December 12, 2025 18:39
@nkolev92 nkolev92 marked this pull request as ready for review December 12, 2025 18:42
@nkolev92 nkolev92 requested a review from baronfel December 12, 2025 18:43
@nkolev92
Copy link
Member Author

@ericstj @ViktorHofer @dsplaisted @baronfel @zivkan @jeffkl

This is ready for review.

It's a complicated, but I'd love to get through it async as much as possible because of the length itself :D

dsplaisted
dsplaisted previously approved these changes Dec 12, 2025

Currently `GetReferenceNearestTargetFrameworkTask` is implemented by running NuGet's "nearest match" algorithm.
This feature would extend it to first try nearest match, and if there is more than one matching `TargetFramework`, then look for a `TargetFramework` that has an exact name match in both projects.
If there are more than one "nearest" framework, but no exact name match, then for the first version of this feature, NuGet will report an error.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How hard would it be to have some sort of extensibility point so that you can add your own logic to choose the "nearest" framework if the NuGet logic results in more than one match?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To add to that question, in the "No match found" case, would it make sense to return that information without raising an error / warning so that we could allow for customization in the msbuild target instead of in the task (which would give us much more flexibility)?

We still want to raise an error if there's no customization (I'm trying to avoid the word "fallback" here as it has a different meaning for NuGet). That would probably need to be moved outside of the task, into the target.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How hard would it be to have some sort of extensibility point so that you can add your own logic to choose the "nearest" framework if the NuGet logic results in more than one match?

It's not impossible. I'd love to see any usage of this multiple framework project reference scenario before we want that direction though.

To add to that question, in the "No match found" case, would it make sense to return that information without raising an error / warning so that we could allow for customization in the msbuild target instead of in the task (which would give us much more flexibility)?

Can you help me understand how this could help?
If there's no nearest match/restore/build should be failing.
I see this as equivalent to a nearest framework not matching at all.

We still want to raise an error if there's no customization (I'm trying to avoid the word "fallback" here as it has a different meaning for NuGet). That would probably need to be moved outside of the task, into the target.

The target that calls the task does not run during restore.
In the core restore algorithm, NuGet picks the nearest project ref and that's based on the data provided to NuGet and collected at the beginning of restore.
Effectively, NuGet does the same thing internally when choosing to flow the package references coming through projects.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, fair point. I was basically wondering if we can add an extension point / a callback to provide additional information that would allow us to extend the selection algorithm for the multiple or non found cases.

Runtime today overwrites the entire selection algorithm target (msbuild) and task (nuget) due to not an extension point being available. This isn't great and needs an update every time the P2P protocol is touched and the msbuild target gets updated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you're not focusing on that right now, but what are some practical examples where the runtime needs to overwrite the selection.
I was hoping alias matching would address a bunch of those needs.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RID based selection. I.e. net10.0-linux should be able to reference net10.0-unix (as unix is a parent of linux in the graph). The current algorithm as you describe in the doc wouldn't be able to handle that but it would support direct matches, i.e. net10.0-unix referencing net10.0-unix.

We can probably workaround that limitation if necessary or even change the RIDs that we target in TFMs but yeah...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. That's the next step then yeah.
Rids are a cross product, but maybe it'll be possible to add first class support for nearest that accounts for the RID as well.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I probably wouldn't try to include RID matching in NuGet or the SDK for the first version of this, ideally just an extensibility point so that people could add it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in V1, we can just add alias matching support, but I'll create a follow-up for the extensibility point.
Right now, the current technical implementation does not allow a computational extensibility.


PackageReference is also supported by non-SDK style projects, which use [dotnet/NuGet.BuildTools](https://github.com/NuGet.BuildTools) which, despite the name, is owned by the non-SDK project system team, not NuGet.
The changes to the assets file that affect legacy projects will be done in a non-breaking way and as such, changes should not be required there.
NuGet will utilize the SDKAnalysisLevel property when it writes out an assets file with breaking changes, ensuring that the .NET SDK will be able to read the assets file for the build.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Customers are expected to change SDKAnalysisLevel if they have build errors when upgrading to a newer SDK. I can't remember the name of the property, but there's an SDK version that feels more appropriate for what this is aiming to achieve.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, there's an SDK version property for sure, we raise telemetry on that, but I see SDKAnalysisLevel to mean, behave like the previous SDK version, and to me that'd imply the older restore behavior in general.

I don't feel too strongly though, and can easily be convinced otherwise.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my mind, SdkAnalysisLevel is about warnings and errors (diagnostics), not features, and looking at the original spec, I feel my opinion is reinforced: https://github.com/dotnet/designs/blob/main/proposed/sdk-analysis-level.md

The spec doesn't say it, but I always thought SdkAnalysisLevel was inspired by Roslyn's AnalysisLevel, and Roslyn also has LangVersion which I consider to be the feature toggle. The SDK/NuGet doesn't have a "global feature toggle" like Roslyn does with LangVersion. Using SdkAnalysisLevel is a choice that can be made, but then customers lose the ability to enable new features while disabling new diagnostics. I guess we need to decide whether that's an important distinction to allow customers to have.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Chet has a good compass when it comes to SDKAnalysisLevel.

Curious what you think @baronfel

tldr;
NuGet will introduce a V4 of the assets file.
It requires a new .NET SDK reader, ie a specific .NET SDK version.

Should that "switch" be based off of the SDKAnalysisLevel or NETCoreSdkVersion property.
More context on the pros and cons in the above comments.


As previously shown in [the assets file pivots changes](#target-framework-pivots), NuGet uses `tfm/rid` as the property name in the `$/targets` object.
Therefore, a `TargetFramework` that includes a `/` will cause parsing challenges.
NuGet's libraries could attempt to do the split on the last `/` character.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the assets file has an entry for the ridless target, in addition to the per-rid targets, I think it would be challening to tell the difference between the two.

If the parser keeps raw strings in memory and then parses the alias/rid only once all targets are parsed from json, then you can find what the max number of / are, and assume the ridless has n-1.

But I think it's easier if we fail restore if the alias has a /. It's easier to block first and later allow, than the other way around.

Since we're already incrementing the version number, I think it'd be ideal if we could make another breaking change to the format, so instead of

"targets": {
   "alias" : {  },
   "alias/rid": {  }
}

we could instead have

"targets": {
   "alias": {
     "": { },
     "rid": {  }
  }
}

But I suspect this might be a lot harder to implement.

However, as is pointed out just below, the target alias is used as the directory name for the obj and bin directories, and / is a directory separator, so I think that's another reason we could just block / from the alias

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'd be fine with blocking that yeah.
Honestly, I can't image this to be a super critical scenario that would need to be addressed.
The more changes we make, the higher the risk of the change anyways.

JanProvaznik pushed a commit to dotnet/msbuild that referenced this pull request Dec 19, 2025
Fixes #

### Context

Design: NuGet/Home#12124

To allow duplicate frameworks in aliasing, the project reference
protocol nearest framework selection needs to be updated to support
matching by alias as well.

Relevant part: 

https://github.com/NuGet/Home/blob/dev-nkolev92-tfmaliases/accepted/2025/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md#project-to-project-references

NuGet/NuGet.Client#7011 NuGet.Client side
adding the parameter.
NuGet/NuGet.Client#6972 will add the full
implementation at a later point.

### Changes Made

- Pass CurrentProjectTargetFrameworkProperty if
GetReferenceNearestTargetFrameworkTaskSupportsTargetFrameworKPropertyParameter
is set.
- If
GetReferenceNearestTargetFrameworkTaskSupportsTargetFrameworKPropertyParameter
is not set, but
GetReferenceNearestTargetFrameworkTaskSupportsTargetPlatformParameter is
set, call the old variation.
- Otherwise calls the last variation.

### Testing

- Manual testing.
- I'd be happy to add tests if someone can point me in the right
direction.
### Notes

The idea here is to get ahead of things. Currently aliasing work can't
be end to end tested because it requires an msbuild change. It makes it
really hard to validate the NuGet changes are enough and good, but this
is the only change needed on the msbuild side.

---------

Co-authored-by: Copilot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Status:Do not auto close Do not auto close for PRs needs long review process

Projects

None yet

Development

Successfully merging this pull request may close these issues.