Dependencies in Nuspec vs. csproj - .net-core

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.

Related

What does PrivateAssets='All' mean?

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>

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.

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.

Convert .Net Core to .Net Framework

I have a .Net Core project web project, and for various reasons want to convert it to a .Net Framework project.
Is there an easy way to do this, or do I have to start again and import the code from the previous projects
I have loaded core project to the VS 2017 RC Community and open *.csproj in text editor.
Just delete teg
<RuntimeFrameworkVersion>
and replace
<TargetFramework>netcoreapp1.1</TargetFramework>
to
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
And after all in project properties set to any another framework and reset back (VS reload and repair *.csproj file).
This worked for me in VS2017:
Start with .net core web project template.
Edit *.csproj so it looks like this:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.3" />
<PackageReference Include="Microsoft.AspNetCore.CookiePolicy" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.HttpsPolicy" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.RazorPages" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.1" />
</ItemGroup>
</Project>
Save and close.
Try running project.
The PackReferences is just the NuGet files, and you can add them through the GUI if the versions are different from mine above.
There's lots of similar answers here, but I didn't see one that was quite what I ended up doing, so I'd like to leave this here just in case someone else is in the same shoes.
Just to be clear, my project was a console program. So, if you're trying to use this answer for something else, your mileage may vary.
In your .csproj file, inside of the <PropertyGroup></PropertyGroup> tag, modify <TargetFramework> to reflect the following:
<TargetFramework>net461</TargetFramework>
Now, in this example, I was using v4.6.1. I can only assume that you'll plug in your version behind the word "net", without the periods. Good luck!
None of the answers here worked for me. In .Net Core 2 the project.json file no longer exists. However, I did solve this problem using the following steps.
1) I removed all nuget packages from my existing project.
2) I created a separate .net core web app project, targeting .net 4.61. This was to get the default nuget packages.
3) I edited the temporary project's .csproj file, copied all the PackageReference nodes inside ItemGroup, and pasted them into my existing projects .csproj file.
4) Edited the TargetFramework node (inside PropertyGroup) from "netstandard2" to "net461"
I had a few package changes to track down and resolve, but otherwise I was able to run.
In my version of Visual Studio 2017 (15.6.2) after 'Unloading the Project', right-clicking and selecting 'Edit <your project file>, I had to:
Add the node:
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
Delete the nodes:
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.16299.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
There are several steps that you need to do, in order to achieve this.
Firstly right click on the .csproj file and add the following
<TargetFrameworks>netstandard2.0;netcoreapp2.0;net35;</TargetFrameworks>
<RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers> <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
Once you have made these changes reload the project and build it.
This will generate the .dll files and Nuget package for this
build in the Debug/Release folder of the project.
Add these .dll to the nuget and access these projects from
nuget.
Try the above steps. This should work.
My .net standard project is relatively simple with few Nuget packages. I just changed
<TargetFramework>netstandard2.0</TargetFramework>
TO
<TargetFramework>**net461**</TargetFramework> under PropertyGroup section of .csproj file and this did the job for me.. Thanks to Brandon Barkley for your answer in the comments.
add below in csproj
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
</PropertyGroup>
I had only a handful of source files. For me it worked best by
Closing Visual Studio 2022
Renaming away the solution folder
Creating a new Visual Studio solution of type "WPF App (.NET Framework)" with the original folder name and same project name
Copying all *.xaml. *.xaml.cs and *.cs from the old project to the new, not touching *.sln, *.csproj and *.config.
Project->Add Existing Item… and adding the copied items
Adding all the special references.
That rebuilt all without a complaint.

Resources