Best practice to include console app in NuGet - c#

I'm developing an open-source library which mainly consists of one class-library project targeting .NET Standard 2.0. On top of that, I've also implemented a console app which is the CLI to this library. The console project (for historic reasons) only targets .NET Framework 4.6.2.
Now I wonder what would be the best practice in order to make this console app available to the community. On the broadest level, I see two possibilities:
Ship the console app as a separate NuGet.
Ship the console app in the same NuGet as the class library because it's just a minor add-on and does not justify an own package.
Historically, I've been using the second approach but considering that the class library can be used in a multi-targeting scenario, I'm not sure anymore. Maybe it's cleaner to separate the console app in a NuGet of its own so that it's dependency on the full .NET framework is clear.
Either way I wonder where the console exe belongs to in the file structure of the NuGet. Historically, I've been putting it under tools\net462 but a comment about the tools folder on this page made me insecure:
Powershell scripts and programs accessible from the Package Manager Console
I'm not necessarily imagining someone using the CLI from the Package Manager Consoler. Rather it would be used as stand-alone exe somewhere is some shell.

Ther is a solution that seems to fit your needs. You can create a command line extension for the dotnet tools. Like dotnet ef you can create a dotnet myAwesomeTool command. The only thing that you need to do is the Following:
Create a console application and add the following code to your .csproj
<PackageId>Company.MyAwesomeTool</PackageId>
<AssemblyName>dotnet-myAwesomeTool</AssemblyName>
<PackageType>DotnetCliTool</PackageType>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
Build the solution and you will find a nuget package in your bin folder. This nuget package can be distributed and when you have installed it, you can run dotnet myAwesomeTool in the projects where the nuget is installed. Works like a charm for me =)
To install it on other projects, add this to the csproj:
<ItemGroup>
<PackageReference Include="company.MyAwesomeTool" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="company.MyAwesomeTool" Version="1.0.0" />
</ItemGroup>
For more infos:
https://blog.maartenballiauw.be/post/2017/04/10/extending-dotnet-cli-with-custom-tools.html

In general, NuGet is meant only for delivering class libraries (note the wording "if your library...").
Use Chocolatey instead for deploying command-line and GUI apps to Windows. It has a CLI that can be used to easily install and update applications. It is not NuGet, but uses a similar method to package and deploy the app.
There are also package managers to target other platforms:
apt-get (for Debian/Ubuntu/Mint)
Brew (for MacOS)
RPM (for Fedora/Red Hat)
NOTE: As Martin Ullrich pointed out in the comments, there is now a way to deploy build tool CLIs with NuGet, which is primarily meant for continuous integration deployment scenarios.

When time pass by, other solutions come available...
https://learn.microsoft.com/nl-nl/dotnet/core/tools/global-tools-how-to-create
<PackAsTool>true</PackAsTool>
<ToolCommandName>botsay</ToolCommandName>
<PackageOutputPath>./nupkg</PackageOutputPath>

Related

How to install CrossGen to optimize .NET Core Library in ci/cd

I am attempting to pre-jit/Ahead-Of-Time (AOT) compile a .NET Core 5 Library to a Native Image using Microsoft's CrossGen utility as described here to improve start up time.
However the instructions for Getting CrossGen are vague:
If you install CoreCLR using a NuGet package, you can find CrossGen in the tools folder of the NuGet package.
How do I install CrossGen via NuGet?
What I've tried so far:
Create a build script that writes deleteme.csproj to disk and has a <PackageReference Include="Microsoft.NETCore.App.Runtime.win-x64" Version="3.1.6" />
Run dotnet restore deleteme.csproj. This will download the Crossgen nuget package to local cache.
I can now run ~/.nuget/packages/microsoft.netcore.app.runtime.win-x64\3.1.6\tools\crossgen.exe
NOTE: I know I can use the ReadyToRun feature for Self-Contained Deployment executable (as described here) HOWEVER I need to optimize a Class Library, so ReadyToRun doesn't work.
Problem
The Nuget package has a big warning:
Internal implementation package not meant for direct consumption. Please do not reference directly.
2. Installation like this seems incorrect. I'd expect CrossGen to be installed as a dotnet tool rather than needing to create a dummy project and run dotnet restore in order to download a copy of a nuget package in cache.
Is there a correct way to pre-jit a .NET Core 5 Library during a ci/cd build?
AntonLapounov answered your question on Github:
<PublishReadyToRun>true</PublishReadyToRun> does work for libraries when targeting netcoreapp3.1, net5.0, and the upcoming net6.0 framework. If you run the following commands in an empty directory:
dotnet new classlib
dotnet publish -p:PublishReadyToRun=True -c Release -r win-x64 -v:n
you will see the crossgen.exe command line. The r2rdump.exe utility can be used to see generated native code placed into the managed DLL.
On my machine, it's indeed %USERPROFILE%\.nuget\packages\microsoft.netcore.app.runtime.win-x64\5.0.13\tools\crossgen.exe. It seems the .NET SDK installs that package automatically.
in case that you have not found a solution to this problem, first of all, crossgen now has a new implement named crossgen2, for getting crossgen2 you can build it as it is open source or just download and unzip it as all nuget files are zip files. crossgen is an internal tool for MSBuild so if you want to use it separately you have to use the command line, fortunately, crossgen has a built-in help page so you hopefully get to know what you want to do. by the way, why won't you just use R2R? R2R contains both IL and AOT your app is optimized with R2R, the downside is as Tomas Says here: https://devblogs.microsoft.com/dotnet/conversation-about-ready-to-run/
Tomas: The version resiliency concept and automatic switch-over to runtime JIT upon a mismatch also mean that a given R2R app can silently experience a perf degradation that may be hard to understand for an end-user.
I assume you don't want to use R2R because of double size as it contains both IL and AOT native images. in that case with a combine of Trim, compressed single file a blank dotnet self-contained program drops from 70 MB to 20 MB.

Where is PackageReference located in console application C#

I have came across this line of code in a code and its quite confusing
One of my client send a dependancy file that contains
<ItemGroup>
<PackageReference Include="xyzrefrence" Version="1.3.0" />
and said it is console application. I created same kind of application but within packages.config
I found this thing
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="xyz" version="1.7.7.7" targetFramework="net452" />
My question is that where the dependacy file located with the client setting(First settings)
The reference (<ItemGroup><PackageReference.....) to the dependency can be
found by editing the Visual Studio project file. *.csproj
The dependency file itself can be found in your project's /bin/debug or /bin/release folders.
Where is PackageReference located in console application C#
There are two nuget mamangement format(Packages.config and PackageReference) to intall nuget packages.
In fact, PackageReference is a new nuget management format for new sdk projects(net standard and net core) since VS2017 while Packages.config is an old tranitional nuget management format for net framework projects.
However, you should note that for traditional framework projects, Microsoft made a concession to use the new SDK's pacakgeReference format, but there are still various compatibility issues.--------(net frameowork projects can use both of them while net core/net standard projects can only use PackageReference).
If you use a net framework project, you can change these two format before you install nuget packages at the beginning by Tools-->Options-->NuGet Package Manager-->General-->Package Management.
And you should specifiy this format before you install the first nuget package at the beginning and when you specify this format, the nugets you install later will use this method by default and cannot be changed.
My question is that where the dependacy file located with the client
setting(First settings)
1) If you use a net framework console project with PackageReference, l am afraid that you cannnot see the depenencies of the nuget. The old sdk projects with PackageReference does not support showing the depenencies of the nuget packages due to several compatibility issues.
2) If you use a net core console project, you can see the dependencies in the Solution Explorer and the latest new sdk projects does support this. It has a new behavior that you can see every nuget package's depenencies under its branch in the Soluton Explorer.
Besides, since you use a framework project with packages.config, you can only see all of them(the premise is that this nuget package has dependencies.) in the packages.config file or in the xxxx.csproj file but it cannot subdivide dependencies for every nuget package.
In additon, if you still want to show the depenencies of the net framework projects with PackageReference, l suggest you could post a feature request in our User Voice forum(DC)-suggest a feature to get Micorosft's attention.

Resolving nuget package references

I am writing an app which needs to load nuget packages dynamically (it uses Roslyn to scan for documentation, type information, etc).
I have a situation where I want to load the following package (info derived from a csproj file):
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>J4JSoftware.Logging</AssemblyName>
<RootNamespace>J4JSoftware.Logging</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
</ItemGroup>
The challenge is that my system's nuget cache does not have an assembly/DLL for a netstandard2.0 version of Serilog.Sinks.Console 3.1.1 (I don't think one exists online, either). All it has is one for netstandard1.3.
Yet the app that I'm scanning (i.e., the one with the requirement for Serilog.Sinks.Console 3.1.1 netstandard2.0) works perfectly fine. So the package requirement is being resolved, I presume, to the netstandard1.3 version...even though the project is netstandard2.0.
Questions:
what's the best place for documentation on how nuget packages are resolved at runtime? Perhaps I could duplicate the resolving function in my scanning app.
better yet, is there a library that handles the resolution automagically? Perhaps something that's part of nuget itself? I studied the nuget github project but didn't see such a thing, but I don't pretend to be a nuget expert.
I would do something like: nuget update or nuget list and interact from C# etc with the console. That way you are sort of getting a library like behavior but not baking your own code that may break across nuget versions.
NetStandard 1.3 is likely usable for Netstandard 2.0 as mentioned here (but not the other way around).
Nuget versioning would declare that you want say Netstandard 2.0 and the package you are using might say it supports NetStandard 1.3+ (which includes Netstandard 2.0 implicitly). Nuget will select the highest one provided that suites your needs, in this case probably 1.3 as you indicated. Details are here on how nuget selects dependencies. I assume that this is the same way in how it determines runtime folders.

Using Microsoft.AspNetCore.Hosting.WindowsServices with .Net Core 2.x

I'm trying to use a Windows Service to host a simple ASP.Net Core web app targeting .Net core 2.x, as detailed here by Microsoft.
This should be simple with the docs, but I'm getting nowhere because the Microsoft.AspNetCore.Hosting.WindowsServices package doesn't seem to work with any version of .Net Core (the NuGet page says it depends on .Net Standard). Simply opening a project will cause Visual Studio to get stuck at NuGet restore, without any error message whatsoever (I have to kill the VS process manually, as closing VS would cause it to stop responding). Running dotnet restore from command will cause cmd gets stuck at "Restoring packages for XXX".
The same thing happens with the sample code in ASP.Net official docs. I guess this must mean a machine- or platform-specific issue to me but I have tried with various (fresh) VMs and am out of ideas. The only thing that works so far is this answer here, i.e targeting .Net Framework and explicitly list all the package references rather than using Microsoft.AspNetCore.All.
I'm using VS2017 15.7.6. Any help on this issue would be greatly appreciated!
Update
The problem magically disappeared after I installed the Azure development workload in VS2017. I already had ASP.Net and .Net Core workloads before, so I really can't figure out which individual component did the trick, but it did solve the problem.
Yes, this answer is correct. The windows-service package only runs on windows. You have to directly target each package you need, because the Microsoft.AspNetCore.App (.NET-Core >= 2.1) and Microsoft.AspNetCore.All (.NET-Core >= 1.1 <= 2.0) packages, contain package(s) that target .NET-Core instead of .NET-Standard.
You could target both frame-works using
<TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
and have conditional includes in your project file + compiler directives in your c# code.
<!-- CSPROJ CONDITIONAL REFERENCE -->
<PackageReference Include="Microsoft.AspNetCore.Hosting.WindowsServices" Version="2.1.1" Condition="'$(TargetFramework)' == 'net471'" />
// c#-code compiler directive
#if net471
using Microsoft.AspNetCore.Hosting.WindowsServices;
#endif
Keep in mind that using the full .NET-Framework will make you lose the performance improvements introduced with .NET-Core.
I am sure you could also have a batch script / windows task that starts your .NET-Core service each time your windows machine restarts.
I just had a similar problem. We have multiple Nuget package stores, and one of them was experiencing certificate issues.
I fixed it by doing the following:
Right-click on project Dependencies in Solution Explorer, and click Manage Nuget packages.
In the Package Manager, in the Installed tab, you should see the package, select the Microsoft.AspNetCore.Hosting.WindowsServices package. It will be showing a version 0 and some indication that it is failing to download.
You may also see the Package source in the top-right pointing to one of the custom Nuget stores. Change the Package Source to ALL. That will cause the window to refresh, and then you may see the correct version and an Update button.
Now click the Update button to update. My version is now 2.1.1.
Looking at the project file now, it changed the package reference to:
<PackageReference Include="Microsoft.AspNetCore.Hosting.WindowsServices" Version="2.1.1" />

Nuget 3.2.0 don't add additional files/folder in project

Since a recent update of Nuget Package Manager (from 2.9 to 3.2.0 I guess), installing package via nuget doesn't add addition files of the package anymore. It just adds the libraries only, update the "project.json" and something like that.
For example: Installing MVVMLight to a project will add Models, ViewModels and Views folder to project. Also, it will add a MainViewModel.cs, ViewModelLocator.cs to ViewModels folder. Now none of these files/folders are added to project.
Any suggestion will help
Since Nuget 3.1 this is no longer supported: https://docs.nuget.org/release-notes/nuget-3.1. One of the main reasons is that packages can copy in files on install, but you're not sure what to do with it on uninstall (as content might have changed manually). But do note that there's an open issue to maybe re-enable this functionality.
Laurent Bugnion of MVVM Light is aware of this issue as well:
Caution: Full package in Windows 10 Universal applications (UWP)
There is a known issue when you install the “mvvmlight” package in
Windows 10 universal applications. The Nuget team unfortunately
changed the way that Nuget works for this framework, and it doesn’t
allow installing additional files, or running scripts anymore. Because
of this, installing the “mvvmlight” package in Windows 10 UWP
applications creates the exact same result as installing the
“mvvmlightlibs” package. Because running a script is not allowed, it
is not even possible to warn the user.
I will publish more detailed information on how to add the scaffolding
to a Windows 10 UWP application manually. Stay tuned.
As of today, he didn't post a full guide yet, but you could try to run the packaged powershell script manually.

Categories