Search code examples
c#dllshared-libraries.net-standard-2.0

can't reference netstandard2.0 library if a reference to CodeAnalysis.CSharp is present


Background

Originally I wrote multiple code generators (need netstandard2.0), and wanted to extract common functionalities into a library (also netstandard2.0). However, when trying to reference the library I always get an error that the .dll file was not found, even though it is there. I spent 3 hours browsing the web and debugging and below you find a MRE. I'm not yet exactly sure that it is the exact same problem I'm facing, since it's complaining about Microsoft's dll and not my own, but I still hope this fix to this will also be a fix to my problem. I'm aware that a newer version of the package is available, but I couldn't get the code generator to run with a newer version, so I'm sticking to this one.

Question

How can I get this running?

Steps to reproduce:

In VS 17.9.3, create a new Console Application, TargetFramework net8.0.

In the same solution, add a new Library project, TargetFramework netstandard2.0.

MyLib.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" PrivateAssets="all" />
    </ItemGroup>
</Project>

Class1.cs

using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace MyLib
{
    public class Class1
    {
        public int GetNumber()
        {
            AttributeSyntax node = null;
            return 1337;
        }
    }
}

In the same solution, add a second new library project, TargetFramework netstandard2.0:

MySecondLib.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\MyLib\MyLib.csproj" />
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" PrivateAssets="all" />
  </ItemGroup>

</Project>

Class2.cs

using Microsoft.CodeAnalysis.CSharp.Syntax;
using MyLib;
using System;

namespace MySecondLib
{
    public class Class2 : Class1
    {
        public void PrintNumber()
        {
            AttributeSyntax node = null;
            Console.WriteLine(GetNumber());
        }
    }
}

For the original console Application, use the following file: NetStandardReproduction.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\MySecondLib\MySecondLib.csproj" />
  </ItemGroup>

</Project>

Program.cs

using MySecondLib;

namespace NetStandardReproduction
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var obj = new Class2();
            obj.PrintNumber();
        }
    }
}

It will build fine, but when you run it it fails with an unhandle Exception:

System.IO.FileNotFoundException: 'Could not load file or assembly 'Microsoft.CodeAnalysis.CSharp, Version=4.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified.'

If you remove the reference from both packages and comment the lines with AttributeSyntax it works just fine.


Solution

  • Check out the Controlling dependency assets (and Use functionality from NuGet packages section of the Source Generators Cookbook):

    You might be using a dependency purely as a development harness and might not want to expose that to projects that will consume your package. In this scenario, you can use the PrivateAssets metadata to control this behavior.

    Basically PrivateAssets=all means that the consumers of this library will not reference dependency marked with it, hence the final console app will not have Microsoft.CodeAnalysis.CSharp referenced, hence error.

    Either remove/modify PrivateAssets property in the libraries or add the Microsoft.CodeAnalysis.CSharp as an explicit dependency to the final app:

    <ItemGroup>
        <ProjectReference Include="..\MySecondLib\MySecondLib.csproj"/>
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
    </ItemGroup>