Search code examples
c#.netnugetmultitargeting

How do I make NuGet aware of a specific version of a package while referencing a multi-targeted class library?


We have three projects:

WebApp.csproj, ASP.NET WebForms app compiled against .NET Framework 2.0

Api.csproj, ASP.NET WebApi 2 compiled against .NET Framework 4.5

Lib.csproj, compiled against .NET Framework 2.0 and referenced by both of the projects above.

Lib.csproj has been recreated in the new .NET project format (the one used by .NET Core) and made to target both .NET Fw 2.0 and 4.5 with the <TargetFrameworks>net20;net45</TargetFrameworks> technique.

So far so good, I can reference different NuGet packages by writing the appropriate sections in Lib.csproj like so:

<ItemGroup Condition="'$(TargetFramework)' == 'net20'">    
    <PackageReference Include="NLog" Version="2.1.0.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
    <PackageReference Include="NLog" Version="4.7.8.0" />
</ItemGroup>

and I can point Api.csproj to the version of Lib.csproj targeting net45, like so:

<ProjectReference Include="..\..\Lib\Lib.csproj" AdditionalProperties="TargetFramework=net45">
    <Project>{32e77bcf-152c-4b64-be37-a13f49cdcab6}</Project>
    <Name>Lib</Name>
</ProjectReference>

The net20 version references NLog 2.1.0, the net45 one NLog 4.7.8.

The problem: now I want to use NLog 4.7.8 in my Api.csproj, but when I click on Manage Packages for Solution on the solution that includes Api.csproj and Lib.csproj, the referenced version appears to be 2.1.0.

I tried selecting both projects and installing it, however I rightly get an error because NLog 4.7.8 is not compatible with net20.

So really, the problem is that NuGet does not seem to be aware that the project I'm referencing is a multi-target one, and only sees the version of NLog installed in the net20 version even though Api.csproj is targeting the right "flavor" of Lib.csproj (and if I go and check the binaries, the version of NLog.dll that gets copied to the output folders is the right one for each of my targets).

I tried looking on the interwebs, but to no avail.

To be fair: the version of NLog that gets copied to Api.csproj's bin folder is the right one, so it's not a showstopper. But it is mildly annoying, because NuGet shows the wrong version of my dependency, and then it's hard to tell what version we're actually using.

For a bit of context: this app is obviously ancient, at least WebApp.csproj. Due to performance reasons, we are making Api.csproj use async/await, and since that project references code that could be made async in Lib.csproj but obviously wouldn't compile under .NET 2, we chose to make Lib.csproj multi-targeted.


Solution

  • The AdditionalProperties here shouldn't be necessary:

    <ProjectReference Include="..\..\Lib\Lib.csproj" AdditionalProperties="TargetFramework=net45">
        <Project>{32e77bcf-152c-4b64-be37-a13f49cdcab6}</Project>
        <Name>Lib</Name>
    </ProjectReference>
    

    I strongly recommend updating all your projects to use SDK-style csproj format if possible. This isn't possible for legacy (pre-Core) web projects, which is the case for WebApp.csproj and Api.csproj. However, even those projects can use some parts of the newer csproj format.

    Specifically, they can use PackageReference. I assume your existing web projects are using nuget.config, but they can be changed to use PackageReference without actually making them SDK-style csprojs. NuGet has some issues with transitive dependencies when nuget.config is used, so I just recommend using PackageReference everywhere.