isxaker
isxaker

Reputation: 9506

How to control output of a nuget package dependencies during build

I would like to support backward compatibility in my application. Simply saying - one app needs to work using different versions of a dll depending on a flag which the app get's during runtime.

I've simplified everything and created a test solution with 2 projects in it. Each project has it's own version of the same nuget package.

test solution

I picked System.Drawing.Common cause it has no dependencies.

ClassLibrary1 contains System.Drawing.Common of version 4.5.0.

ClassLibrary2 contains System.Drawing.Common of version 6.0.0.

Both projects have same output path:

<OutputPath>..\DEBUG\</OutputPath>

When I build my solution I get just one System.Drawing.Common.dll in my output folder: current output

Cause both dlls have one name and only version is different.

The desired behavior on the pictures below:

  1. Distribute the nuget package dependencies into different folders according to versions. desired output

  2. Add suffix to the nuget package dependencies according to versions. desired output

The idea is in controlling output of the nuget package dependencies. Do you have any idea how I can achieve that ?

P.S. all other logic - resolving dependencies according versions etc is out of scope of this question.

Upvotes: 1

Views: 525

Answers (2)

isxaker
isxaker

Reputation: 9506

It's possible. First you need to add GeneratePathProperty to PackageReference element in csproj file

<ItemGroup>
    <PackageReference Include="System.Drawing.Common">
        <Version>4.5.0</Version>
        <GeneratePathProperty>true</GeneratePathProperty>
    </PackageReference>
</ItemGroup>

It allows us using $(PkgSystem_Drawing_Common) variable which contains a path to the nuget package.

Then we need to create a msbuild targets file

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="CopyNugetDll" BeforeTargets="BeforeCompile" Outputs="System.Drawing.Common.dll">
        <XmlPeek XmlInputPath="$(ProjectPath)" Query="Project/ItemGroup/PackageReference[@Include='System.Drawing.Common']/Version/text()">
            <Output TaskParameter="Result" PropertyName="NugetPackageVersion" />
        </XmlPeek>
        <ItemGroup>
            <NugetrDll Include="$(PkgSystem_Drawing_Common)\lib\net461\System.Drawing.Common.dll" />
        </ItemGroup>
        <Message Text="Copying @(NugetrDll) to $(OutDir)" Importance="high" />
        
        <Exec Command="copy $(PkgSystem_Drawing_Common)\lib\net461\System.Drawing.Common.dll $(OutDir)\System.Drawing.Common.$(NugetPackageVersion).dll" />
    </Target>
</Project>

Here using xpath we select version from project.assets.json file and save it in NugetPackageVersion variable. Exec copy is used to copy the dll to a specific location with a specific prefix which contains a value from NugetPackageVersion variable.

Lastly you need to include msbuild targets file to a project

<Import Project="CopyDll.targets" />

Upvotes: 1

rbennett485
rbennett485

Reputation: 2163

This just isn't how package resolution works in .NET, you get one version of each package which is decided at restore time.

There may be some funky options if you have a very niche problem, but it sounds like maybe you're trying to solve a common problem in an uncommon way which is generally a bad idea.

Typically for the problem of backwards compatibility the onus is on the publisher of the library rather than the consumer of the library to make sure it all works by not making breaking API changes.

Upvotes: 0

Related Questions