Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support hardcoding a different TFM for a packagereference's resolution #7279

Closed
moh-hassan opened this issue Sep 6, 2018 · 9 comments
Closed
Labels
Resolution:Duplicate This issue appears to be a Duplicate of another issue Style:PackageReference Type:Feature

Comments

@moh-hassan
Copy link

Introduction:

I have faced a problem of installing many packages (not needed) in a project net461 as described in this issue #7263 ,Why nuget install many dll dependenices in FFW 4.6.1

I was adviced by @PatoBeltran

Ideally suave (in your case CommandLineParser) should contain a group without the netstandard dependencies that specifically targets .NETFramework to avoid unneeded dependencies.

I followed his advice by adding an empty group for net45,as the following line:

	<group targetFramework="net45"/>

The details of the solution: #7263 (comment)

and this line resolved the problem.
This requires that the owners of most of the packages should modify .nuspec file and add the previous line.

The Feature Request:

It's nice if you can add to the PowerShell command Install-package command

a parameter named Framework, something like:

	Install-package  ......   	-Framework net45

And user can define his Nearest Framework ,e.g, net45

The advantage:

The Framework option imply that the nuget install-command when reading the dependency from nuspec file included in the package, add the empty dependency group line:

<group targetFramework="myframework-in-Framework-parameter"/>

to dependencies and consequently install net45 lib not netstandard package (which is currently auto selected by nuget for frameork net46x)
For example: the following dependency in nuspec file:

   <dependencies>	   
  <group targetFramework=".NETStandard1.5">
	<dependency id="System.Collections" version="4.0.11-rc2-24027" />
	<dependency id="System.Console" version="4.0.0-rc2-24027" />
	..... 
  </group>           
</dependencies>

by running the command:
install-package mypacke -Framework net45

The dependencies will become in memory:

    <dependencies>
   <group targetFramework="net45"/>    <!-- this line added by the new feature -->
  <group targetFramework=".NETStandard1.5">
	<dependency id="System.Collections" version="4.0.11-rc2-24027" />
	<dependency id="System.Console" version="4.0.0-rc2-24027" />
	......
  </group>           
</dependencies>

This avoid the modification of nuspec file of many packages need to be modified by the owner of the package to add this empty group and avoid installs superfluous dependencies of netstandard as the the Nearest Framework.

The great benefit is enabling the developer immediately to select his nearest package and avoid the installation of netstandard dependncies for framework net461,462,471,..

The same is applied for update-package (may be other commands for consistency)

@moh-hassan moh-hassan changed the title Enable adding the nearest framework in the parameters of the PowerShell command install-package or Update-package Feature Request: Enable adding the nearest framework in the parameters of the PowerShell command install-package or Update-package Sep 6, 2018
@PatoBeltran
Copy link

@moh-hassan I'm sorry but this doesn't look like something we would want to have as part of nuget. The packages are shipped as-is, we do not do any modification (even if it is in memory) of them before installing them.

There is no way for nuget to implement reliably a feature like this, and there is no reason why someone should have that granular control over what to pick and what not to pick in a package. Implementing something like this would be a hack that might work in some scenarios (like yours), but it might not work in others.

If you really need to have that level of control over what a package is installing on your project, you can always take a package, do your custom modifications and repack them. Then consume them from a local source or have your private copies of the packages.

@PatoBeltran PatoBeltran added ClosedAs:WontFix Type:Feature Functionality:Update The update package feature/command/experience Functionality:Install The install command in VS/nuget.exe labels Sep 6, 2018
@moh-hassan
Copy link
Author

moh-hassan commented Sep 6, 2018

this would be a hack that might work in some scenarios (like yours)

@PatoBeltran, This feature (without the details of implementation) is currently available in the third party Paket tool
which is a dependency manager for .NET with support for NuGet packages.
It helped me to solve like this issues by providing framework=net45
What i did by adding empty group isn't a hack but an official solution done by many owners of the package like log4net and visualsharp(Microsoft) and suggested by you.
Any way, owners of packages should do this hack (not ME)
Thanks for help and support.

Update
Can we consider this feature a hack that might work in some scenarios?
No, because :

  • It's applied for multi target package only.
  • The framework has a corresponding folder inside the .nuspec lib folder.
  • The dependencies section in .nuspec file haven't a dependency group for that framework, which means that it's sure the framework have no dependencies at all and it's safe to add a group and don't violate the dependencies rules of .nuspec file.
  • The package include both full framework and netstandard lib.
  • It will not violate the internal logic/rules in nuget client or PowerShell commands
  • It solves real annoying problem of installing extra unneeded packages of netstandard in full framework projects 4.6.x .
  • It's option that can(not) used by developer as needed.

@nkolev92
Copy link
Member

nkolev92 commented Sep 7, 2018

@moh-hassan
I'm curious to understand which paket feature you are referring to?

You can tell restore to only run with a specific framework, but that framework has to be in your project.

If you are allowed to specify custom frameworks to restore certain packages against, build would be likely to fail.

@moh-hassan
Copy link
Author

moh-hassan commented Sep 8, 2018

Thanks @nkolev92 for reply.

I'm curious to understand which paket feature you are referring to?

  1. In Paket, when adding the following framework option 'framework:461' in 'paket.dependencies' file:

     nuget CommandLineParser 2.3.0  framework:461
    

and run 'paket install' in the commandline, Paket install only net45 lib(in my issue #7263), only one package without any dependencies.

Also, Paket add the following section to the project file myproject.csproj

	<Choose>
		<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.6.1'">
		  <ItemGroup>
			<Reference Include="CommandLine">
			  <HintPath>..\packages\CommandLineParser\lib\net45\CommandLine.dll</HintPath>
			  <Private>True</Private>
			  <Paket>True</Paket>
			</Reference>
		  </ItemGroup>
		</When>
	  </Choose>

Note the path \lib\net45\CommandLine.dll (not nestandar15 path)

  1. If I didn't add 'framework:461' option, like:

           nuget CommandLineParser 2.3.0 
    

Paket install all netstandard15 lib dependencies, exactly Like nuget command install-package (no more no less)

  1. Even, if I wrote unsupported framework , the Choose statement in the csproj prevent any invalid reference.

  2. In paket, i can set the restriction on the level of solution:

         // Download and install only for .NET 3.5 and .NET 4.0.
           framework: net45, net35 
    

OR:

         // Only the target frameworks that are used in projects.  the best
          framework: auto-detect

For more details , read the paket.dependencies: Framework restrictions

If you are allowed to specify custom frameworks to restore certain packages against, build would be likely to fail.

Sure, I mean the current project in VS IDE or with option -ProjectName MyProject of the command.

I find nuget do this restriction and solve the problem of avoiding of installing many netstandard packages in project net46x in smart way if the empty dependency group exist in the dependencies, and the idea of adding the framework option is raised for me.

Many owners of the package forget to add this empty dependency group in multi target package (if no dependencies exist)

I mean, by the feature request, the restriction for framework in the command install-package (and the corresponding other commands for consistency) without the details of implementation that I provided.

@nkolev92
Copy link
Member

Maybe I'm not following you exactly, but here's what I understand. In number 1 you say:

and run 'paket install' in the commandline, Paket install only net45 lib(in my issue #7263), only one package without any dependencies.

I don't see any difference from before. For net461, NuGet just selects the closest matching framework.

The choose statement is required because paket writes to csproj.
In PackageReference, the build figures the assembly references out of the project.assets.json. And that works the exactly same way as writing it in the csproj does.
Your project has to target a framework to install against it.

Regarding number 2:
In the end, you are targeting a framework, so the selections are happening against that.

Regarding 3.
In PackageReference we fail fast there.

I mean, by the feature request, the restriction for framework in the command install-package (and the corresponding other commands for consistency) without the details of implementation that I provided.

I wouldn't call it a restriction.
If you multi target, you can select to install against only 1 target framework.
But that's the key, your project has to be targeting that framework, for you to install against it.

https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets
https://docs.microsoft.com/en-us/nuget/create-packages/supporting-multiple-target-frameworks

@moh-hassan
Copy link
Author

moh-hassan commented Sep 10, 2018

I don't see any difference from before. For net461, NuGet just selects the closest matching framework.

Really, Paket find net45 is the closest framework for net461, because i provided a restriction , but nuget find netstandard15 is the closest one. That is the point.

But that's the key, your project has to be targeting that framework, for you to install against it.

I use the sdk format of csproj in vs 2017 update 3 that target net461, with the properties:

	<Project Sdk="Microsoft.NET.Sdk">
	     <PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net461</TargetFramework>
	   </PropertyGroup>
	  <ItemGroup>
	  <PackageReference Include="CommandLineParser" Version="2.3.0" Condition="'$(TargetFramework)' == 'net461'"/>
	</ItemGroup>
	</Project>

I try to use the PackageReference format with condition, but in vain. May be, I missed something.
Take into account that there is no empty dependency group for net45 in nuspec file of the package.

see in demo project with the new SDK style :
dependency for net461
dependency for net46
C# project demo
The big question:
Why ,in our case project net461, nuget select netstandard15 as the closest framework, but in case of an empty dependency group for net45 exist in dependencies of nuspec, nuget select net45 as the closest framework.
What's the logic behind?
How to enforce msbuild/nuget to select net45 lib (without dependency) than netstandard15 lib(with lot of dependencies)?

@rrelyea rrelyea added Style:PackageReference and removed Functionality:Update The update package feature/command/experience Functionality:Install The install command in VS/nuget.exe ClosedAs:WontFix labels Mar 29, 2019
@rrelyea rrelyea changed the title Feature Request: Enable adding the nearest framework in the parameters of the PowerShell command install-package or Update-package Support hardcoding a different TFM for a packagereference's resolution Mar 29, 2019
@rrelyea
Copy link
Contributor

rrelyea commented Mar 29, 2019

Sounds to me this is a request for a way to do something like this:
<PackageReference include="mypackage" version="2.0" useTfm="net45" />

Renamed this title to:

  • Support hardcoding a different TFM for a packagereference's resolution

In case we don't provide a more elegant way in the future, see this blog post for a hard coded way to do it:
http://duanenewman.net/blog/post/forcing-a-specific-target-platform-with-packagereference/?utm_source=duaneat&utm_medium=twitter&utm_campaign=blog

Related twitter thread: (has some interesting discussion too)
https://twitter.com/duanenewman/status/1108109664410054656

@moh-hassan
Copy link
Author

moh-hassan commented Mar 29, 2019

Thanks @rrelyea for reply.
Good for the title renaming. That is really the feature that I need.
For the HintPath to the dll path, what if the library has a HintPath and become a new nuget package.
In that case I think that the dll is shipped with the new package.

Good news that the feature will be available in vs 2019

Visual Studio 2019 is the first version that works with it, so that's another thing to be aware of.

@zivkan
Copy link
Member

zivkan commented Aug 26, 2019

Closing as duplicate of #7416

@zivkan zivkan closed this as completed Aug 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution:Duplicate This issue appears to be a Duplicate of another issue Style:PackageReference Type:Feature
Projects
None yet
Development

No branches or pull requests

5 participants