📜 ⬆️ ⬇️

.NET Core 2.1 Global Tools

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 basics


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> 

Under the hood


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:


  1. It dotnet restore with special parameters to download the package.
  2. Files are unpacked into the $HOME/.dotnet/.store/<package id>/<version> folder.
  3. A launch file is generated in the $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 .


How to create your package


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:



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> 

Build and Install Package


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/ 

What's inside the package


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.


Dependencies


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.


DotnetToolSettings.xml


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 :



<packageType name = "DotnetTool" />


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.


What can go wrong


Global utilities - global for the user, not for the computer


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.


Missing path in PATH variable


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:



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.


.NET Core CLI not installed in default folder


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:



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.


Conclusion


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