What does PrivateAssets='All' mean? - .net-core

When I build my .NET Core (NETStandard v2.0) project I am getting the following warning:
ViewModels: [FodyPackageReference] Fody: The package reference for PropertyChanged.Fody
does not contain PrivateAssets='All'
The warning is in reference to the PropertyChanged.Fody NuGet package.
While the warning does not stop the build, I would like to resolve the warning. However, I don't understand what it is trying to communicate.

PrivateAssets is a metadata tag used to control dependency assets.
You might be using a dependency purely as a development harness and might not want to expose that to projects that will consume your package. In this scenario, you can use the PrivateAssets metadata to control this behavior.
Package references (PackageReference) in project files
In your case, unless you want to expose PropertyChanged.Fody to a consumer (i.e. you are releasing a library), setting PrivateAssets to All in your .csproj file will remove the warning.
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="PropertyChanged.Fody" Version="3.3.1" PrivateAssets="All" />
</ItemGroup>
</Project>

Related

Referencing assemblies under dotnet installation directory

Wondering if there is any legitimate reason for a .csproj to contain an assembly reference to an assembly w/ a hint path under the dotnet installation directory (default: c:\Program Files\dotnet on Windows).
In particular, the directories
packs
sdk
shared
An example of such a reference:
<ItemGroup>
<Reference Include="Microsoft.Extensions.Configuration.Abstractions">
<HintPath>..\..\..\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\3.1.0\ref\netcoreapp3.1\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
</Reference>
</ItemGroup>
Surely not. This application would not work on other machines.
It looks like someone inserted code that uses Microsoft.Extensions.Configuration.Abstractions package which was not referenced and then probably applied "Quick fix" action from Resharper/Rider. Sometimes it leads not to referencing Nuget package
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.1" />
</ItemGroup>
but to referencing locally placed assembly.

Shipping projects as NuGet packages while depending on each other

I have three projects I'm building
FooBar.Abstractions
FooBar.AspNetCore
FooBar.AspNetCore.IntegrationTesting
The FooBar.AspNetCore and the FooBar.AspNetCore.IntegrationTesting projects both have references to FooBar.Abstractions. I want to package and ship all three of these as individual NuGet packages.
I started with a NuGet.config file that looks like this locally:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="aspnetcore_abstractions" value="./src/FooBar.Abstractions/bin/Debug/" />
</packageSources>
</configuration>
Then I add the package to my projects
<ItemGroup>
<PackageReference Include="FooBar.Abstractions" Version="2.0.0-preview1" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
</ItemGroup>
This really sucks though as each time I make a change in the FooBar.Abstractions project I have to go into my C:\.nuget\packages folder and delete the cache before my FooBar.AspNetCore project can restore the newly compiled version from my solution.
If I just add FooBar.Abstractions as a project reference, and then I ship the two packages to NuGet.org, how does that affect users that install the two packages across different projects in their solutions. Does NuGet and .Net figure it all out, knowing that they're the same referenced assembly? I assume in this case the FooBar.AspNetCore project will ship with the FooBar.Abstractions.dll in it if I add it as a project reference.
I don't know if that causes conflicts knowing that the package ships that .dll, then a customer installs the Abstractions package explicitly that contains the same .dll.
How do you handle this with NuGet packaging with the newest versions of NuGet? How do I constrain FooBar.AspNetCore to use the same FooBar.Abstractions.dll version between the package reference and the NuGet package others will install? I can't force PackageReference Include="FooBar.Abstractions" Version="2.2" if I'm adding it as a project reference instead can I?
When you pack a project with at project reference, NuGet converts the project reference into a NuGet dependency. It figures out the dependency version based on what version that project would be if it were packed. There is no need to use PackageReference when packing. As you discovered/explained, doing so makes local development much more difficult.
Therefore the solution to your problem is to just use ProjectReference when the projects are in the same source code repository.

Dependencies in Nuspec vs. csproj

I have a Dotnet Core 2.1 project which has both a nuspec and a csproj file - one major hassle is that the csproj describes dependencies like this:
<ItemGroup>
<PackageReference Include="Refit" Version="4.6.16" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1" />
<PackageReference Include="Refit.HttpClientFactory" Version="4.6.16" />
</ItemGroup>
While the nuspec does this:
<dependencies>
<dependency id="Refit" version="4.6.16" />
<dependency id="Refit.HttpClientFactory" version="4.6.16" />
<dependency id="Microsoft.AspNetCore.All" version="2.1" />
</dependencies>
Both are easily out of sync and keeping the same information twice is annoying.
Is there a way to avoid that?
There is certain to be a easy way for this, just use dotnet pack instead of nuget pack and .csproj files instead of .nuspec files.
dotnet pack supports 2 ways to specify the nuget package properties.
The legacy way: using .nuspec file, which would disable the 2nd way
The new way: specifying them in .csproj file
dotnet pack supports both ways but you must add a NuspecFile property to reference the .nuspec file and there are a lot of bugs and feature missings for the legacy way, which means you can only use the new one.
dotnet pack executes restore and build on the project and packs it with a automatically generated .nuspec file resolving all nuget metadata properties in .csproj as .nuspec properties and all projects references as nuget package references (This is not available with manually specified .nuspec file), so that versioning, dependency, and package file structure things can be automatically ensured.
My own library could be an example. Version and dependency things are specified for only once at where they are supposed to be and there are no longer any annoying duplicate configurations. Executing dotnet pack on the solution directory would generate all good .nupkgs on the dist directory.

dotnet core nuget package copying content files on restore

So I feel like I have come to the end of the rope here, but hoping someone knows more than I do here. I have some Typescript files, though that is mostly irrelevant as I am having this problem with all content files.
I am able to generate a nuget, or more precisely dotnet pack, nuget package that includes my content files in the package by using this in the .csproj of my parent project:
<ItemGroup>
<Content Include="Scripts\Utility.ts">
<Pack>true</Pack>
<PackagePath>contentFiles\Scripts\;content\Scripts</PackagePath>
</Content>
</ItemGroup>
I can browse the generated .nupkg and see that indeed the file was added to the package in both the content\Scripts and contentFiles\Scripts locations
The problem is that whenver I consume this package in my 'child' progect, that Typescript never gets copied into any folder of the child project, though I can see it extracted in the .nuget\packages\parent\... folders.
At first I thought it was something with my initial settings in the parent project, and it may be, but after trying what seems like everything in the book, that fails to copy the content files to the child project. I then tried going the dark path of trying to use Init.ps1 in the tools folder of my package, and though it was impossible to debug, it also seemed to run sporatically (I completely unistalled and reinstalled the package and it still failed to run most of the time.) This could be the way but I don't know why I can't get it to output to the Package Manager Console... maybe there's still hope with Init.ps1 but I can't seem to figure it out. Finally I see some potential with a nuget .targets file but I can's seem to grasp how to use it for my purpose either! I would love some feedback as to how to get this done.
From: Announcing NuGet 3.1 with Support for Universal Windows Platform
Importing content from a Nuget package was depreciated for projects using a project.json file in Nuget v3.1. Since then the project.json file has been dropped in favour of the new .csproj format. Importing content from a Nuget package should still work though if you're using the packages.config file instead.
Also mentioned is the fact that there are other package managers available for delivering content.
It looks to me like the answer in the new world is to create a node module containing utility.js and let npm deliver it to your project.
Possible Workaround:
I've looked at .targets to copy files and got this working, but it does run on each build - which may or may not be a problem for you. I can't do what I want with it.
In [PackageId].targets:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Either do this for all scripts in the Scripts/js folder -->
<Target Name="CopyScriptsToProject" BeforeTargets="Build">
<Message Text="Copying scripts to project" />
<ItemGroup>
<SourceScripts Include="$(MSBuildThisFileDirectory)..\..\content\Scripts\js\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(SourceScripts)" DestinationFiles="#(SourceScripts -> '$(MSBuildProjectDirectory)\wwwroot\js\%(RecursiveDir)%(Filename)%(Extension)')" Condition="!Exists('$(MSBuildProjectDirectory)\wwwroot\js\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<!-- Or do this for the individual script -->
<Target Name="CopyUtilityScriptToProject" BeforeTargets="Build">
<Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\content\Scripts\js\Utility.js" DestinationFiles="$(MSBuildProjectDirectory)\wwwroot\js\Utility.js" Condition="!Exists('$(MSBuildProjectDirectory)\wwwroot\js\Utility.js')" />
</Target>
</Project>
<!-- Note: condition can be removed from either if you want it to overwrite each build -->
and in the .csproj file (replacing [PackageId] with the name of your package):
<Project Sdk="Microsoft.NET.Sdk">
... any Globals for source control stuff ...
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<Version>7.0.0</Version>
<PackageId>[PackageId]</PackageId>
</PropertyGroup>
... any PackageReference stuff ...
<ItemGroup Label="Packaging">
<Content Include="build\netcoreapp2.0\[PackageId].targets" PackagePath="build\netcoreapp2.0\[PackageId].targets" />
<!-- Either -->
<Content Include="Scripts\js\**\*.*" PackagePath="content\Scripts\js;contentFiles\Scripts\js" />
<!-- or -->
<Content Include="Scripts\js\Utility.js" PackagePath="content\Scripts\js;contentFiles\Scripts\js" />
</ItemGroup>
</Project>
There seemed to be a bug whereby when the <PackageId>[PackageId]</PackageId> wasn't set explicitly in the .csproj, the build targets didn't work. Although that may well be an issue with my development environment.
Apparently you need the any\any in the path (learn more) as well as to include <PackageCopyToOutput>true</PackageCopyToOutput>, like this:
<ItemGroup>
<Content Include="Scripts\js\Utility.js">
<Pack>true</Pack>
<PackagePath>contentFiles\any\any\wwwroot\js\;content\any\any\wwwroot\js\</PackagePath>
<PackageCopyToOutput>true</PackageCopyToOutput>
</Content>
</ItemGroup>
You'll also need to precompile your TypeScript before including the .js files in the package
However, this still doesn't create a file there, just some strange reference to it.
In the end, we got it working with a .targets file, you can find a working repo here: https://github.com/NuGet/Home/issues/6743
Serj Sagan's answer got me on the right track, but it wasn't sufficient to deploy the content file to the bin directory (as he noted). I was able to get the file to be deployed by changing the package reference options in the consuming project's .csproj file, as follows:
<PackageReference Include="MyNuGetPackage" Version="0.0.0.1">
<IncludeAssets>all</IncludeAssets>
<PrivateAssets>analyzers;build</PrivateAssets>
</PackageReference>
It seems like the default for PrivateAssets is contentfiles;analyzers;build (documentation), which is not what we want in this case.
Simplified code and explanation from #PurplePiranha
TL;DR:
Basic .NET6 simplified sample code on Github
Step by Step guide
Selection of the files
First we need to select all the files that needs to get into the nuget package.
Add this to the <LibraryPackageName>.csproj:
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup Label="Packaging">
<Content Include="<Your directory path>\<your file(s)>" />
</ItemGroup>
Multiple content lines are allowed.
Write a target
Make a target file to copy the files before (or after) the build to the bin directory:
The location and name of this file is important:
<root>\build\<LibraryPackageName>.targets
Now, make sure that it will get executed by referencing it in the <LibraryPackageName>.csproj by adding a content line:
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup Label="Packaging">
<Content Include="build\<LibraryPackageName>.targets" PackagePath="build\<LibraryPackageName>.targets" />
<Content Include="filesToAdd\*.txt">
<Pack>true</Pack>
</Content>
</ItemGroup>
Eg: From the code in github:
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup Label="Packaging">
<Content Include="build\PackageToGenerateFile.targets" PackagePath="build\PackageToGenerateFile.targets" />
<Content Include="filesToAdd/*.txt">
<Pack>true</Pack>
</Content>
</ItemGroup>
NOTE: By copying the files to the bin directory, the files are not part of your version control, but your package is!
Build and pack
In Visual Studio, right-click on the package name and select "Pack".
A new nuget package should be created in the bin directory of your library.
Use the nuget package
Install the nuget package now in your destination package.
Notice that the files are in the solution explorer, but not in a directory on your disk. They have a shortcut symbol.
Build the destination package
Check the bin directory.
The files should be copied to the location mentioned in the targets.

How do I specify dependencies in a .NET Standard Class Library?

A .NET Standard Class Library doesn't use a .nuspec file; there is a "Package" tab in the project settings where you enter all the metadata for the NuGet package. These go in the .csproj file.
I want to create a solution with projects A and B, where project B depends on project A. Both need to go on NuGet as separate packages. But if someone installs the NuGet package for B, it should also install the package for A.
How do you specify this simple dependency for a .NET Standard Class Library? I'm not assuming that adding a reference will be enough to do this.
NET Standard .csproj files use PackageReference and ProjectReference MSBuild items to control dependencies on packages loaded from NuGet or your solution, respectively. They both support metadata tags PrivateAssets, IncludeAssets, ExcludeAssets, which control what exactly and how your project depends on in those dependencies. By default, all dependencies are auto-generated by the Visual Studio with PrivateAssets, which means those dependencies are consumed, but they're not marked as dependencies for consumers of your project (which is gonna be a package in NuGet).
So, you just need to replace the PrivateAssets metadata with the IncludeAssets (maybe with proper values).
For example, my SuperPackage.csproj file looks like below:
..................
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2">
<IncludeAssets>compile</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
<IncludeAssets>compile</IncludeAssets>
</ProjectReference>
</ItemGroup>
</Project>
So, I have the PackageReference to the 'Newtonsoft.Json' package from NuGet marked as a dependency, and the ProjectReference to the ClassLibrary1 project within the single solution.
When the SuperPackage project is built with checked 'Generate NuGet package on build', I get the following SuperPackage.nupkg:
Check this doc for more details: https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files
From what I have found it is not yet supported in .csproj files and you should use .nuspec to specify dependencies. Have a look how they do it in xUnit, for example.

Resources