Msbuild: ProjectReference transitive dependencies

Created on 11 Sep 2019  路  7Comments  路  Source: dotnet/msbuild

Steps to reproduce

Let's consider these 3 project files :

ProjectA

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net471</TargetFramework>
  </PropertyGroup>
</Project>

ProjectB

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net471</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\ProjectA\ProjectA.csproj" />
  </ItemGroup>
</Project>

ProjectC

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net471</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\ProjectB\ProjectB.csproj" />
  </ItemGroup>
</Project>

The 3 projects depends on each other as follows : ProjectC -(depends on)-> ProjectB -> ProjectA

Expected behavior

ProjectC should not be able to use elements from ProjectA (public classes for example) since it doesn't reference this project directly.

Actual behavior

ProjectC has access to ProjectA via transitivity as it can be seen in his assets file :

{
      ...
      "ProjectA/1.0.0": {
        "type": "project",
        "framework": ".NETFramework,Version=v4.7.1",
        "compile": {
          "bin/placeholder/ProjectA.dll": {}
        },
        "runtime": {
          "bin/placeholder/ProjectA.dll": {}
        }
      },
      "ProjectB/1.0.0": {
        "type": "project",
        "framework": ".NETFramework,Version=v4.7.1",
        "dependencies": {
          "ProjectA": "1.0.0"
        },
        "compile": {
          "bin/placeholder/ProjectB.dll": {}
        },
        "runtime": {
          "bin/placeholder/ProjectB.dll": {}
        }
      }
      ...
}

As mentioned in https://github.com/dotnet/project-system/issues/2313, it appears that this behavior can be cancelled by using PrivateAssets, from PackageReference dependency assets, when referencing ProjectA :

  <ItemGroup>
    <ProjectReference Include="..\ProjectA\ProjectA.csproj" PrivateAssets="all" />
  </ItemGroup>

Using ExcludeAssets when referencing ProjectB also works :

  <ItemGroup>
    <ProjectReference Include="..\ProjectB\ProjectB.csproj" ExcludeAssets="all" />
  </ItemGroup>

However, these metadatas are originally applicable only for PackageReference and I can't find any documentation of this behavior for ProjectReference (in the ProjectReference item reference for example).
So, should this (PrivateAssets or ExcludeAsssets) be really used in ProjectReference tag ?

Environment data

msbuild /version output: 15.9.21.664
Visual Studio : Professional 2017, version 15.9.15

Most helpful comment

You could use <DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences> to turn this off for Project to project references.

@thank you @livarcocc It works perfect.
Do you know if there is any documentation for this settings? I cannot find anything. I also don't know when it was introduced (in which version of MSBuild/SDK/VisualStudio?)

Not sure if you are the right person to ask, but just to clarify I have some questions:

So this DisableTransitiveProjectReferences setting changes ProjectReference behavior in new SDK-csproj to be the same as in old csproj where ProjectReference wasn't transitive but the transitive projects' .dlls were copied to bin folder ?

Is the effect the same as setting PrivateAssets="All" on all the dependencies of dependand project? Just that with DisableTransitiveProjectReferences you control this behavior in different place, on project that reference other projects, not on project that might be referenced by other projects.

In other word PrivateAssets="All" is more flexible and fine-grained and you can achieve the same end result like with DisableTransitiveProjectReferences but DisableTransitiveProjectReferences is just more useful if you prefer "old non-SDK csproj" non-transitive behavior of ProjectReferences (or if you are in process of migrating to .NET Core or SDK-style csproj)

All 7 comments

Any update on the topic please ?

You could use <DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences> to turn this off for Project to project references.

Ok, thanks.
I'll try that.

@livarcocc <DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences> works fine as far as compilation is concerned.
However, ProjectA is still present in ProjectC asset file (same as mentioned in the description); which is a false information since this dependency doesn't exist anymore at compile time.

Any update please ?

<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>

and

      <Private>false</Private>
      <ExcludeAssets>all</ExcludeAssets>

seems to work to me

You could use <DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences> to turn this off for Project to project references.

@thank you @livarcocc It works perfect.
Do you know if there is any documentation for this settings? I cannot find anything. I also don't know when it was introduced (in which version of MSBuild/SDK/VisualStudio?)

Not sure if you are the right person to ask, but just to clarify I have some questions:

So this DisableTransitiveProjectReferences setting changes ProjectReference behavior in new SDK-csproj to be the same as in old csproj where ProjectReference wasn't transitive but the transitive projects' .dlls were copied to bin folder ?

Is the effect the same as setting PrivateAssets="All" on all the dependencies of dependand project? Just that with DisableTransitiveProjectReferences you control this behavior in different place, on project that reference other projects, not on project that might be referenced by other projects.

In other word PrivateAssets="All" is more flexible and fine-grained and you can achieve the same end result like with DisableTransitiveProjectReferences but DisableTransitiveProjectReferences is just more useful if you prefer "old non-SDK csproj" non-transitive behavior of ProjectReferences (or if you are in process of migrating to .NET Core or SDK-style csproj)

Was this page helpful?
0 / 5 - 0 ratings