PackageReference condition is ignored - visual-studio

In my VS 2017 project I reference docfx.console package and I want it to be used only when certain condition is met. But the package gets used for all builds.
Here is a part of my project. I want docfx.console to be used when configuration is Installer/AnyCPU and VS is building net40 flavor.
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net40;netstandard1.3;netstandard2.0</TargetFrameworks>
<!-- ... -->
<Configurations>Debug;Release;Installer</Configurations>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)'=='net40' ">
<!-- ... -->
<PackageReference Include="docfx.console" Version="2.30.0" Condition="'$(Configuration)|$(Platform)'=='Installer|AnyCPU'" />
</ItemGroup>
<!-- ... -->
</Project>
Is there a way to use docfx.console in Installer build for net40 only?

To summarize, even with the condition "false", the package will be imported.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp3.0;netcoreapp2.2;net472</TargetFrameworks>
<Platforms>x64;x86</Platforms>
</PropertyGroup>
<ItemGroup Condition="false">
<PackageReference Include="MyPackage" Version="1.0.0" />
</ItemGroup>
</Project>
We found that we can work around this issue by putting the packagereference in a different file, and making the import of the file conditional.
Separate file: packagerefs.targets
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="MyPackage" Version="1.0.0" />
</ItemGroup>
</Project>
Project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp3.0;netcoreapp2.2;net472</TargetFrameworks>
<Platforms>x64;x86</Platforms>
</PropertyGroup>
<Import Project="packagerefs.targets" Condition="false" />
</Project>

Even i was looking for referencing nuget packages on condition based (load only when expected constant is set in DefineConstants). Though #Luke Schoen Solution worked for me, I could make it work without the external targets file.
Solution is to include your PackageReference using Choose > When
Make sure to have this block after your PropertyGroup which has DefineConstants.
<Choose>
<When Condition="$(DefineConstants.Contains('My_CONST'))">
<ItemGroup>
<PackageReference Include="MyPackage">
<Version>1.0.6</Version>
</PackageReference>
</ItemGroup>
</When> </Choose>

PackageReference condition is ignored
This is an known issue about the new style csproj PackageReference to work with content/Tools files in a nuget package.
In the package docfx.console, it looks like docfx.console has "content", "build" and "tools" without .NET code in it, just random files:
In this case, when we install this nuget package, nuget does not do anything. So it seems gets used for all builds. That because:
NuGet packages that work with Packages.config, don't always work in
transitive NuGet environments (projects using Project.json or
PackageReferences). Packages that work in transitive NuGet
environments must use "contentFiles" instead of "content" -- you can
have both, if a package would like to work in both environments. Also,
install.ps1/uninstall.ps1 doesn't execute in transitive NuGet
environments -- however, init.ps1 will work in both Packages.config
and transitive environments.
At this moment, there is not a perfect solution, so the issue 4837 is still open.
To resolve this issue, the NuGet docfx.console package needs to be changed to use contentFiles and define targets and would typically reference a tool by using $(MSBuildThisFileDirectory)..\tools\MyTool.exe. If you put this PackageName.targets file into the a build directory, it will be automatically included into the project referencing the NuGet package.
Hope this helps.

In my case I had also same kind of problem - but root cause was that some of msbuild properties were not defined when nuget package building was performed - in particular $(SolutionName) was not defined. Condition still gets evaluated, only it's returning true for some reason. (You can test this by putting Condition="false" - it will be omitted).
Solution for me was to check if property is defined, for example like this:
<ItemGroup Condition="'$(SolutionName)' != '' and $(SolutionName.Contains('SolutionCustomTag'))">
<Reference Include="...">
Te first statement '$(SolutionName)' != '' and - tests that property is defined.

Related

Why am I getting warning NU1507 with Central Package Management even with Package Source Mapping set?

I'm trying out the new Central Package Management feature in NuGet.
As stated in the documentation, if you use multiple NuGet sources (which I use), it is now required to configure the Package Source Mapping in a nuget.config file, otherwise you should get a NU1507 warning.
My simplified file tree is this:
MySolution.sln
Proj1.csproj
MyLibrary\ (this is an external repository with all my shared projects)
Directory.Packages.props
nuget.config
Proj2\ (an example library project)
Proj2.csproj
Here is the Proj1.csproj content:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);MyLibrary\**\*</DefaultItemExcludes>
</PropertyGroup>
</Project>
Here is Directory.Packages.props:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="JetBrains.Annotations" Version="2022.1.0" />
</ItemGroup>
</Project>
Here is nuget.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear/>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json"/>
<add key="Custom NuGet" value="https://nuget.mydomain.net/"/>
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*"/>
</packageSource>
<packageSource key="Custom NuGet">
<package pattern="MyNamespace.*"/>
</packageSource>
</packageSourceMapping>
</configuration>
and Proj2.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
In the official documentation the MyLibrary\nuget.config should be used when restoring the packages because it is in the parent directory of Proj2.csproj, and actually it works when I build the solution via dotnet build, but when I build it in Visual Studio I still get the NU1507 warning.
I know that I could work around the issue by copying the nuget.config file in the same directory as the solution file (the warning goes away), but I have hundreds of projects that include the MyLibrary directory and I'd like to keep all the configuration centralized.
Moreover it works as expected when it's built from the command line, so what am I doing wrong?
Everything seems like correct from your configure file.But MS doc has mentioned this note:Central package management is in active development. You can provide any feedback you may have at Nuget/Home
Here’re suggestions you can have a try to check :
1 check your visual studio version and this feature is available for Visual Studio 2022.17.2 and later.Because older tooling will ignore central package management configurations and features.See more information please refer to doc:CPM
2 If you are unable to onboard to Package Source Mapping but want to use central package management, can suppress the warning. Please refer to doc:
<PropertyGroup>
<NoWarn>$(NoWarn);NU1507</NoWarn>
</PropertyGroup>
3 use dotnet nuget list source to get package source list and check whether they are enabled.

How do you specify common package versions in a common.props file?

We've got a simple common.props file that is basically doing what Directory.Build.props appears to do. It specifies various settings and is then imported to the csproj files that need it.
Here's the basics of the MyProject.common.props file:
<Project>
<PropertyGroup>
// some settings
</PropertyGroup>
<PropertyGroup>
<LangVersion>8.0</LangVersion>
//some more settings...
<MyNewVariable>3.1.22</MyNewVariable>
</PropertyGroup>
</Project>
Here's the basics of the csproj:
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\folderA\MyProject.common.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="$(MyNewVariable)" />
</ItemGroup>
</Project>
When I use this approach I get the error:
Project dependency Microsoft.Extensions.Hosting.WindowsServices does
not contain an inclusive lower bound. Include a lower bound in the
dependency version to ensure consistent restore results.
However, if I just input 3.1.22 where the variable is it works fine. This suggests to me that the variable is coming through empty or not being picked up. If I remove the variable altogether and leave the Version blank I get the same error. I also double checked the path to the file by misspelling the import and I get a different error, so I know it can at least find the common.props file.

build project without runtimes folder but included nuget packages in nopcommerce 4.40(.net 5 and VS 2019)

I'm developing plugin for nopcommerce,
I'm using VS 2019 and nopcommerce 4.40.4(.net 5)
I should use a nuget package in my plugin,
If I set CopyLocalLockFileAssemblies to true, when I build my project, it created runtimes folder, which is about 65 MB,
If I set CopyLocalLockFileAssemblies to false, it does not create runtimes folder, but, the dll of nuget package which I should use, not included in the build folder,
would you please help me about this?
Note: set copy local to no, make no difference when I change for Nop.Services which I use in the project
this is my csproj and my the package is > SmsIrRestful.NetCore :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputPath>..\..\Presentation\Nop.Web\Plugins\AttributeStockSMS</OutputPath>
<OutDir>$(OutputPath)</OutDir>
<!--Set this parameter to true to get the dlls copied from the NuGet cache to the output of your project.
You need to set this parameter to true if your plugin has a nuget package
to ensure that the dlls copied from the NuGet cache to the output of your project-->
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<ClearPluginAssemblies Include="$(MSBuildProjectDirectory)\..\..\Build\ClearPluginAssemblies.proj" />
</ItemGroup>
<ItemGroup>
<None Remove="plugin.json" />
</ItemGroup>
<ItemGroup>
<Content Include="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="SmsIrRestful.NetCore" Version="1.1.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\Nop.Services\Nop.Services.csproj">
<Private>false</Private>
</ProjectReference>
</ItemGroup>
<Target Name="NopTarget" AfterTargets="Build">
<!-- Delete unnecessary libraries from plugins path -->
<MSBuild Projects="#(ClearPluginAssemblies)" Properties="PluginPath=$(MSBuildProjectDirectory)\$(OutDir)" Targets="NopClear" />
</Target>
</Project>
Instead of using NuGet reference, include the dll file of that NuGet package. For example, You are going to use TaxJar library then follow these steps.
Added NuGet reference.
Right click on NuGet package and go to properties.
Copy path value from property values as below.
Go to that path in file explorer.
Find dll file(s) from there, copy-paste into your plugin folder and add refence.
Repeat same procedures for dependent packages also (if any).
Mark as Copy Local to Yes from properties.

Msbuild pack ignores nuget packages with targets and task

I have ProjectA and ProjectB
ProjectA
Is a dotnet standard project with output and exe file to be used as as tool.
This generates a nuget package on build, using property and property to mark the package as a tool.
It also is marked as to auto exclude from projects which installs the nuget package, when they them also generate a nuget package.
<Project Sdk="Microsoft.Net.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<AssemblyName>ProjectA</AssemblyName>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IsTool>true</IsTool>
<DevelopmentDependency>true</DevelopmentDependency>
</PropertyGroup>
<ItemGroup>
<None Include="build\ProjectA.props" Pack="True" PackagePath="build" />
<None Include="build\net461\ProjectA.targets" Pack="True" PackagePath="build" />
</ItemGroup>
<PropertyGroup>
</Project>
ProjectA.targets
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<GetPackageVersionDependsOn>MyCustomTask;$(GetPackageVersionDependsOn)</GetPackageVersionDependsOn>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<Target Name="MyCustomTask">
<!-- Idealy i would use a custom task to set PackageVersion to something different. Like 5.0.99-alpha1+102435 -->
<PropertyGroup>
<PackageVersion>5.0.99-alpha1+102435</PackageVersion>
</PropertyGroup>
</Target>
</Project>
ProjectB
Installs a reference to the nuget package created by ProjectA.
<PropertyGroup>
<TargetFrameworks>net461</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ProjectA" Version="1.0.0" PrivateAssets="all" />
</ItemGroup>
When building ProjectB, the following files are genearted in obj/ folder:
.csproj.nuget.g.props
.csproj.nuget.g.targets
These files include import to ProjectA targets and props from the nuget package cache at:
%userprofile%.nuget\projecta\1.0.0\build\ProjectA.targets etc
Msbuild -t:pack ignores these imports when running, and hence the build ProjectB never sets the PackageVersion to 5.0.99-alpha1+102435 as i would expect.
Adding the above content of ProjectA.targets directly into ProjectB.csproj works.
Anyone have any suggestions what I'm missing or if the might be an issue?
If you use *.targets to pack the nuget project into a nuget package based on that file, you should make this file recognized along with csproj file.
Based on the description, it seems that you used that targets file to pack your nuget project into a version 5.0.99.
So you should make your csproj to work along with that file like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<!--the path of the *.targets file-->
<Import Project="xxx\xxx.targets"/>
</Project>
Update 1
clean nuget caches or delete all files under C:\Users\xxx\.nuget\packages) and msbuild -t:pack ProjectB.csproj to check it.
Update 1
Instead, modify Project B.csproj file:
use <TargetFramework>net461</TargetFramework> instead of <TargetFrameworks>net461</TargetFrameworks>.
The multi-platform framework seems to break the performance of the targets file, I'm also curious why this is happening. But this is the tip. You should use that.

Adding file to nuget package [duplicate]

I have installed AsyncUsageAnalyzers for my common project (which is a NuGet package), and I want the rules to be enforced in all of my packages/applications that depends on it.
I have changed the severity of the UseConfigureAwait rule, and a .ruleset has been created.
I have read on https://stackoverflow.com/a/20271758/2663813 that I needed to have a NuGet package with a given structure. That assertion has been confirmed here https://stackoverflow.com/a/46115423/2663813
What I have now:
build/Common.ruleset
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="My common analyzer rules" Description="The rules that are enforced on all of my projects" ToolsVersion="10.0">
<Rules AnalyzerId="AsyncUsageAnalyzers" RuleNamespace="AsyncUsageAnalyzers">
<Rule Id="UseConfigureAwait" Action="Error" />
</Rules>
</RuleSet>
build/My.Package.Id.targets
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)Common.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>
In my .csproj
<Import Project="build\My.Package.Id.targets" />
My question is : Now that I've done that and that the rules are correctly applied on my project, how do I add the files under build/ inside the NuGet package, inside the build/ folder? I know that I could do that with a .nuspec file as mentionned in the links, but I'd like to do that with the new .csproj syntax.
Sorry for posting too quickly, I just found the solution right under my eyes:
In the page https://learn.microsoft.com/en-us/dotnet/core/tools/csproj#nuget-metadata-properties , in the comments, MarkPflug gives the translation, and quotes
https://learn.microsoft.com/en-us/nuget/schema/msbuild-targets#pack-scenarios for reference.
In my case, I need to use PackagePath as follows (Content would also work, but as Martin Ullrich pointed out, None is a better choice here):
<ItemGroup>
<None Include="build\**" Pack="True" PackagePath="build\" />
</ItemGroup>

Resources