1

INTRODUCTION

I am building a class library which could be used by some legacy applications targetting .Net Framework 4.0 and new applications targetting .Net Framework 4.6.1

I am adding some database/Hibernate new code in the class library that requires .Net Framework 4.6.1. This new code is incompatible with .Net Framework 4.0 because the nuGet package FluentNHibernate 3.1.0 requires .Net Framework 4.6.1 and up. And legacy application does not require this functionnality.

WHAT I AM TRYING TO ACHIEVE

I am attempting to conditionnaly build the class library so one code base and the master git branch can be used to build a version compatible for either one or the other application.

So far, I have been able to:

  • Define a constant indicating the target framework (FWK40)
    • for use within .cs code to adjust code to target framework
  • Conditionally define the targetted framework (TargetFrameworkVersion)
  • Exclude files from build when not under the right TargetFrameworkVersion

Here is what the .CSPROJ looks so far (emphasis for the relevant adjustments):

 <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug.Net40|AnyCPU'">

    <!-- Set target framework here -->

    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Debug.Net40\</OutputPath>

    <!-- Define Build-time constant here -->

    <DefineConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0'" >FWK40</DefineConstants>

 </PropertyGroup>

 <ItemGroup>

    <-- Conditionally include .cs files here -->

    <Compile Include="Database\GeneralSQL.cs" Condition="'$(TargetFrameworkVersion)' != 'v4.0'" />
    <Compile Include="Database\NamingStrategy.cs" Condition="'$(TargetFrameworkVersion)' != 'v4.0'" />
 <ItemGroup>

 <ItemGroup>

    <-- In THEORY conditionally include PackageReference here -->

    <PackageReference Include="FluentNHibernate" Condition="'$(TargetFramework)' != 'net40'" >
        <Version>3.1.0</Version>
    </PackageReference>
 </ItemGroup>

THE RESULT SO FAR

What is happenning, is I am getting a nuGet error saying:

NU1202: Package FluentNHibernate 3.1.0 is not compatible with net40 (.NETFramework,Version=v4.0). Package FluentNHibernate 3.1.0 supports:
Failed to restore C:\_projets\repos\TestSolution\TestLibrary\TestLibrary.csproj (in 19 ms).
NuGet package restore failed. Please see Error List window for detailed warnings and errors.

Not withstanding this error, the assemblies all are generated properly, the DLL Class Library itself, as well as an EXE Console application using that class library AND so far they run properly.

THE PROBLEM

I haven't been able to conditionnaly include nuGet a PackageReference.

AND The nuGet error still causes MSBuild.exe to fail, which prevents the CI/CD pipeline to work properly..

WHAT I HAVE TRIED

I have tried many many ways to get rid of nuget NU1202 error message.

#1 I have tried initially with other conditions based on $(TargetFrameworkVersion) which works througout the .csproj but to no avail.

#2 According to official documentation, nuGet ReferencePackage only supports conditions based on $(TargetFramework) adding-a-packagereference-condition as shown in the sample .csproj above. YET THIS STILL DOES NOT WORK.

  • I haven't been able to figure out so far what exactly the Property TargetFramework looks like. I ran MSBUILD.EXE in Verbosity level diagnostics, which dumps all the Properties, but TargetFramework wasn't listed (while others were)

  • I have tried to "reverse" the condition == 'net461' so that if the expected value is incorrect, it won't be included and the error would disappear => no effect, errors still there

#3 I have tried to define myself the TargetFramework property

    <!-- Set target framework here -->
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <TargetFramework>net40</TargetFramework>
  • The outcome would be much worse!
  • Visual Studio did not like it, the "Configuration Manager" broke down
    • it would not allow to set a specific Configuration for a project.
    • changing from Debug.Net40 to any other configuration (or loading the project) would show a nasty error message
Current solution contains incorrect configuration mappings. It may cause projects to not work properly

And the csproj was definitely not loaded properly either and project would be skip the build step.

WHERE I AM AT NOW

I am really stuck! Can't seem to find a way to make this work.

  • I would hate to have to have a branch master40 and a branch master just to handle this.
  • I would hate to have to have two csproj different files, unless I can somehow manage to share/include one into the other AND Visual Studio would not complain

The really really right thing would be to make the conditions on the ReferencePackage to actually work as intended.

Philibert Perusse
  • 4,026
  • 5
  • 24
  • 26

1 Answers1

0

What you want is multi-targeting. The documentation you link seems to be only applicable for SDK-style projects. AFAIK, multi-targeting is not available with the legacy-style project format.

I suggest migrating to the SDK-style project format. A lot of things are much simpler there, not to mention better documented. You can use a tool to do this, like hvanbakel/CsprojToVs2017 or dotnet/try-convert. Don't be fooled by its name and wrong usage of terminology. (since this is also mixed up on SO all the time: yes, you can use the SDK-style format with .NET Framework TFMs; SDK-style has nothing to do with either TFM or Visual Studio version, but only with minimum required MSBuild version).

Once you have done that for your particular project, the documentation for multi-targeting applies and you can use Condition on $(TargetFramework) just like you have already done, in both your PackageReference and the Compile item group and pretty much anywhere you want.

svenhuebner
  • 342
  • 1
  • 2
  • 10