A couple of weeks ago .NET Core 2.1 RC1 was released . This is the first SDK version where there is a feature called ".NET Core Global Utilities" (".NET Core Global Tools"). It provides an easy way to create cross-platform console utilities.
We will get acquainted with the basics of using .NET Core Global Tools and briefly see what's inside. You can also download the .NET Core 2.1 SDK and try to write your own example.
The .NET Core global tool is a special NuGet package in which the console application is located. When you install it, the .NET Core CLI downloads the package and makes it available as a new global console command.
Users can install utilities using the dotnet tool install
command:
dotnet tool install -g <nuget package name>
After installation, the console utilities in the package will be globally available by name:
<command name>
dotnet tool
has other commands. For example:
dotnet tool list -g dotnet tool uninstall -g <nuget package name> dotnet tool update -g <nuget package name>
The NuGet package with the console utility contains all the files resulting from the dotnet publish
command, as well as several additional files with meta-information.
When you run dotnet tool install --global
, the following happens:
dotnet restore
with special parameters to download the package.$HOME/.dotnet/.store/<package id>/<version>
folder.$HOME/.dotnet/tools
folder.The generated startup file is a small console application ( written in C ++ ) that knows where your .NET Core DLL file is located and automatically launches it.
You can also run dotnet tool install
with the argument --tool-path $installDir
. This command does the same thing, but installs the console application in the $installDir
folder, not in $HOME/.dotnet/tools
.
To create global console utilities, you need the .NET Core SDK version 2.1 . This version adds several additional project settings for managing the naming and package contents with global console utilities.
Minimum required project parameters:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <PackAsTool>true</PackAsTool> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.1</TargetFramework> </PropertyGroup> </Project>
Additional (optional) parameters controlling the package build:
AssemblyName
- sets the name of the .dll file of your console application.ToolCommandName
- the name of the command by which the user will run your console utility. By default, it is the same as the name of the .dll file (which is specified in the AssemblyName
parameter).dotnet-
. You can use any name without spaces.dotnet-
, then the utility can be run as a command of the dotnet
utility (make sure that there is no command with this name yet). For example, the dotnet-say-moo
utility can be called both as dotnet-say-moo
, and as dotnet say-moo
.PackageId
- NuGet identifier of the package. The default is the name of the .csproj file. This ID must be specified during installation. However, it may differ from the command name ( ToolCommandName
) and the name of the .dll file ( AssemblyName
).PackageVersion
- NuGet version of the package ( 1.0.0
by default). Also, instead of PackageVersion
you can use VersionPrefix
and VersionSuffix
.An example of using these parameters:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <PackAsTool>true</PackAsTool> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.1</TargetFramework> <ToolCommandName>pineapple</ToolCommandName> <PackageId>dole-cli</PackageId> <PackageVersion>1.0.0-alpha-$(BuildNumber)</PackageVersion> <AssemblyName>Dole.Cli</AssemblyName> </PropertyGroup> </Project>
The package is assembled as usual - using the dotnet pack
command. The SDK will see that the PackAsTool=true
parameter is PackAsTool=true
and will automatically generate the necessary additional files.
dotnet pack --output ./packages
Using the --source-feed
option you can install a package that has not yet been published in the NuGet package repository. This can be useful for checking that everything is done correctly. Also, if the version of the package is not release (for example, 3.0.0-alpha
- contains something other than three numbers), you must explicitly specify it during installation.
For example:
dotnet tool install -g my-package-name --version 3.0.0-alpha --source-feed ./packages/
As I wrote above, the dotnet pack
command collects a package in a special way, if the PackAsTool=true
parameter is specified in the project file.
The package includes not only the files obtained via dotnet build
, but also all other dependencies of your project (connected third-party NuGet packages). All files necessary for your console utility to work should be included in the NuGet package. The dotnet-tool-install
command does not install the dependencies specified in the <dependencies>
.nuspec
your .nuspec
file.
A special DotnetToolSettings.xml
file is DotnetToolSettings.xml
that contains information about your console application. If this file is not in the package for some reason (for example, trying to install an arbitrary package as a console utility), then during installation you will get an error:
NuGet package is invalid: Settings file 'DotnetToolSettings.xml is not found in the package.
Sample file content:
<DotNetCliTool Version="1"> <Commands> <Command Name="my-command-name" EntryPoint="my-file.dll" Runner="dotnet" /> </Commands> </DotNetCliTool>
Now there are the following DotnetToolSettings.xml
file DotnetToolSettings.xml
:
DotnetToolSettings.xml
file should be located in the tools/$targetframework/any/
folder. For example: tools/netcoreapp2.1/any/DotnetToolSettings.xml
.DotnetToolSettings.xml
file.<Command>
section should be described in the DotnetToolSettings.xml
file.Runner
attribute must be "dotnet"
.EntryPoint
attribute should be the name of the .dll file, which lies in the same folder as the DotnetToolSettings.xml
file.The parameter <packageType name="DotnetTool" />
automatically added to the .nuspec
file. For example:
<?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"> <metadata> <!-- ! --> <packageTypes> <packageType name="DotnetTool" /> </packageTypes> <!-- ... --> </metadata> </package>
If the packageType[name]
parameter is not specified as DotnetTool
, then during installation you will receive an error:
error NU1212: Invalid project-package combination for awesome-tool 1.0.0. DotnetToolReference project style can only contain references of the DotnetTool type
Of course, this is not a very clear error message. There is an issue on Github to improve this.
The .NET Core CLI installs global utilities in the $HOME/.dotnet/tools
folder (on Linux / macOS) or in the %USERPROFILE%\.dotnet\tools
folder (on Windows) by %USERPROFILE%\.dotnet\tools
. This means that you cannot install the package globally for all users of the computer using the dotnet tool install --global
. Installed utilities are available only to the user who installed them.
Usually, .NET Core automatically adds the path to the folder with installed utilities to the PATH environment variable, so that they are accessible by name, without the full path. But sometimes it may not work. For example:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE
environment DOTNET_SKIP_FIRST_TIME_EXPERIENCE
(for example, to speed up the first launch of a .NET Core), then the value of the PATH
variable may not be set when you first use.tar.gz
file (and not from a .pkg
file), then you may not have the /etc/paths.d/dotnet-cli-tool
file that sets the PATH
variable.~/.bash_profile
or ~/.zshrc
In this case, when you start your console utility, you will receive an error. For example:
bash: my-command-name: command not found
To make it work, you need to add the path to the utility folder to the PATH
variable. Like this (after adding you need to restart the terminal):
cat << \EOF >> ~/.bash_profile # Add .NET Core SDK tools export PATH="$PATH:/Users/<user-name>/.dotnet/tools" EOF
Or you can add this for the current session:
export PATH="$PATH:/Users/<user-name>/.dotnet/tools"
The examples above are for MacOS. For other systems, everything is the same. In addition, when installing your global console utility, the dotnet tool install
command dotnet tool install
verify that the PATH
variable is properly configured and will suggest solutions if this is not the case.
If you downloaded the .NET Core CLI as a .zip / .tar.gz archive and unpacked it into a folder that is different from the default folder, then when you run your console utility you may get an error:
A fatal error occurred, the required library hostfxr.dll could not be found
A fatal error occurred, the required library libhostfxr.so could not be found
A fatal error occurred, the required library libhostfxr.dylib could not be found
The error message will also include additional information:
If this is a self-contained application, that library should exist in [some path here].
If this is a framework-dependent application, it is to specify the runtime location.
The reason is that we are launching the file that is generated by the dotnet tool install
command when installing the package, it looks for .NET Core in the default folder. You can override the default paths by setting the DOTNET_ROOT
environment DOTNET_ROOT
. For example:
# Windows set DOTNET_ROOT=C:\Users\username\dotnet # MacOS/Linux export DOTNET_ROOT=/Users/username/Downloads/dotnet
Details in the issue on GitHub.
We met with global console utilities in .NET Core. In my opinion, this is a very cool thing. I am extremely happy that the .NET Core team has written it down. I can’t wait for everyone to start using it :)
Source: https://habr.com/ru/post/359006/
All Articles