sdk: 'Private' metadata is not propagated to transitive dependencies

This was discovered moving Roslyn’s VSIX projects to the new SDK.

Roslyn builds a number of VSIX projects and is very particular about which projects end up embedded in which VSIX. There are a number of patterns employed to accomplish this including

<ProjectReference Include="..\..\VisualStudio\Core\Impl\ServicesVisualStudioImpl.csproj">
  <Project>{c0e80510-4fbe-4b0c-af2c-4f473787722c}</Project>
  <Name>ServicesVisualStudioImpl</Name>
  <Private>false</Private>
</ProjectReference>

The intent here is to reference the project but not include its contents in the resulting VSIX by means of <Private>false</Private>. This continues to work in the new SDK.

However implicit transitive references ends up pulling in all of the projects that ServicesVisualStudioImpl.csproj. None of those projects are marked as <Private>false</Private> and as a result end up included in the VSIX. This both bloats (in some cases 100 fold) and functionally breaks our VSIX (some cases 100 fold).

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 1
  • Comments: 16 (14 by maintainers)

Commits related to this issue

Most upvoted comments

Changing title to match more general issue as #1467 stated it (marked as dupe now). The repro steps in #1467 are also very clear and should be used to construct a test case when fixing this. cc @sharwell

This is also an issue for VS for Mac.

Here are my notes, in case it’s helpful:

Right now, if project B has a private (i.e. the default) project reference to project A and project C has a non-private ref to project B, project C will transitively get a private ref to project A.

This seems very wrong, and is very much NOT what we want.

Extensions reference each other with non-private refs so we only get one copy of each dll in the app. This breaks that.

Setting PrivateAssets=“runtime,contentFiles” on the private reference does NOT fix it.

And here’s my workaround:

<Target Name="_MakeTransitiveProjectRefsNonPrivate" AfterTargets="IncludeTransitiveProjectReferences">
	<ItemGroup>
		<!-- remove the transitive project references and re-add them as non-private project references -->
		<ProjectReference Remove="@(_TransitiveProjectReferences)" />
		<ProjectReference Include="@(_TransitiveProjectReferences)" Private="False" />
	</ItemGroup>
</Target>