NET Core 2.1 Global Tools


微軟工程師Nate McMaster的博文.NET Core 2.1 Global Tools

https://natemcmaster.com/blog/2018/05/12/dotnet-global-tools/

Getting started with creating a .NET Core global tool package. Also, a peek under the hood.
.NET Core 2.1 RC1 was released this week. This is the first supported version of the .NET Core CLI which includes a feature called “.NET Core Global Tools”. This feature provides a simple way to create and share cross-platform console tools. In this post, I’ll go over some of the basics, and then walk though what is going on under the hood. You will need to download .NET Core 2.1 to use this to try this on your own.

Tip: For a real-world example of a global tool, see https://github.com/natemcmaster/dotnet-serve/.

Basic design
A .NET Core global tool is a special NuGet package that contains a console application. When installing a tool, .NET Core CLI will download and make your console tool available as a new command.

Users install tools by executing “dotnet tool install”:

dotnet tool install -g awesome-tool
Once installed, the command “awesome-tool” can now be used.

awesome-tool
Creating your own package
To simplify getting started, I’ve created a project templates.

Install the templates package

dotnet new --install McMaster.DotNet.GlobalTool.Templates
Create a new project

dotnet new global-tool --command-name awesome-tool
Once you have this project, you can create your tool package like this:

dotnet pack --output ./
This creates a file named awesome-tool.1.0.0.nupkg You can install your package like this:

dotnet tool install -g awesome-tool --add-source ./
When you are ready to share with world, upload the package to https://nuget.org.

Note: in 2.1 RC1, use --source-feed instead of --add-source. This was renamed in https://github.com/dotnet/cli/pull/9164

Additional commands
dotnet tool has other commands you can invoke. For example,

dotnet tool list -g
dotnet tool uninstall -g awesome-tool
dotnet tool update -g awesome-tool
Under the hood
The NuGet package that contains the tool is produced by running dotnet publish and putting everything in publish output into the NuGet package, with a few manifest files.

When dotnet tool install --global executes, it…

uses dotnet restore with special parameters to fetch the package.
extracts the package into $HOME/.dotnet/.store/(package id)/(version)
Generates an executable in $HOME/.dotnet/tools
The executable generated is a small console app (written in C++) which automatically knows how to find your .NET Core .dll file and launch it.

When dotnet tool install --tool-path $installDir executes, it does the same thing, but installs into $installDir, not $HOME/.dotnet/tools

Package authoring and SDK
Authoring a global tool requires the .NET Core SDK. This SDK provides a few simple settings to control the naming and contents of a .NET Core global tool package.

The required minimum project for a global tool looks like this.

true Exe netcoreapp2.1 Additional properties can be set to control the generated tool.

ToolCommandName - the command name users will invoke. It defaults to the name of the .dll file produced (i.e. assembly name)
This does not need to start with dotnet-. It can be anything without spaces.
If it begins with dotnet-, it can be used as a subcommand on dotnet, provided that command doesn’t already exist. Example: dotnet-serve can be invoked as either dotnet serve or dotnet-serve.
PackageId - the ID of the NuGet package (defaults to the .csproj file name)
The package ID can be different than the command name and assembly name
PackageVersion - the version of the NuGet package (defaults to 1.0.0)
AssemblyName - can be used to change the file name of the .dll file
Example of using these properties:

true Exe netcoreapp2.1 pineapple dole-cli 1.0.0-alpha-$(BuildNumber) Dole.Cli Deep-dive: package requirements There are some very specific requirements for global tools. The SDK takes care of most of these for you when you specify PackAsTool=true.

Publish output into pack
As mentioned above, the tools package must contain all your apps dependencies. This can be collected into one place by using dotnet publish. By default, dotnet pack only contains the output of dotnet build. This output does not normally contain third-party assemblies, static files, and the DotnetToolSettings.xml file, which is why you need to specify PackAsTool. This instructs the SDK to gather all publish output, not just assembly you compile.

DotnetToolSettings.xml
This file must exist in the package. If not install will fail with

The settings file in the tool’s NuGet package is invalid: Settings file ‘DotnetToolSettings.xml’ was not found in the package.

The schema for this file looks like this:

Currently, there are many restrictions on how this file can be used.

The file must exist in the NuGet package under tools/$targetframework/any/. Example: tools/netcoreapp2.1/any/DotnetToolSettings.xml.
You may only specify one DotnetToolSettings.xml file per package.
You may only specify one per DotnetToolSettings.xml file.
The only allowed value for Runner is "dotnet".
The value for EntryPoint must be a .dll file that sits next to DotnetToolSettings.xml in the package.
Error NU1212 and package type
Installation may fail with this error

error NU1212: Invalid project-package combination for awesome-tool 1.0.0. DotnetToolReference project style can only contain references of the DotnetTool type
This error message is not very clear (see https://github.com/NuGet/Home/issues/6630 for improvement). What this means is that dotnet-tool-install is currently restricted to only installing a .NET Core package that has specific metadata. That metadata can be defined in your nuspec file and must be set as follows:

Dependencies You must redistribute any of your dependencies in your tools package. Dependencies defined in the metadata of your NuGet package are not honored by dotnet-tool-install.

Common errors
Here are some common errors encountered when using global tools.

PATH and command not after installing

dotnet tool install -g awesome-tool

awesome-tool
awesome-tool: command not found
awesome-tool : The term 'awesome-tool' is not recognized as the name of a cmdlet, function, script file, or operable program.
Global tools are actually “user global”, and are installed to %USERPROFILE%.dotnet\tools (Windows) or $HOME/.dotnet/tools (macOS/Linux). The .NET Core CLI tool makes a best effort to help you ensure this is in your PATH environment variable. However, this can easily be broken. For instance:

if you have set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to speed up intial runs of .NET Core, then your PATH may not be updated on first use
macOS: if you install the CLI via .tar.gz and not .pkg, you’ll be missing the /etc/paths.d/dotnet-cli-tool file that configures PATH.
Linux: you will need to edit your shell environment file. e.g. ~/.bash_profile or ~/.zshrc
Workarounds

(May require restarting your shell.)

Windows:

setx PATH "$env:PATH;$env:USERPROFILE/.dotnet/tools"
Linux/macOS:

echo "export PATH="$PATH:$HOME/.dotnet/tools"" >> ~/.bash_profile
Tools are user-specific, not machine global
The .NET Core CLI installs global tools to $HOME/.dotnet/tools (Linux/macOS) or %USERPROFILE%.dotnet\tools (Windows). This means you cannot install a global tool for the entire machine using dotnet tool install --global. Installed tools are only available to the user who installed them.

Installing the .NET Core CLI into a non-default location
If you download the .NET Core CLI as a .zip/.tar.gz and extract it to a non default location, then you may encounter an error after installing and launching a tool:

Windows: A fatal error occurred, the required library hostfxr.dll could not be found
Linux: A fatal error occurred, the required library libhostfxr.so could not be found
macOS: A fatal error occurred, the required library libhostfxr.dylib could not be found
The error will also contain additional details such as:

If this is a self-contained application, that library should exist in [some path here].
If this is a framework-dependent application, install the runtime in the default location [default location] or use the DOTNET_ROOT environment variable to specify the runtime location.
The reason this happens is that the generated shim created by dotnet tool install only searchs for .NET Core in the default install locations. You can override the default location by setting the DOTNET_ROOT environment variable.

set DOTNET_ROOT=C:\Users\nate\dotnet
export DOTNET_ROOT=/Users/nate/Downloads/dotnet
See https://github.com/dotnet/cli/issues/9114 for more details.

Wrapping up
This is an awesome feature. Super happy the .NET Core CLI team created it. Can’t wait to see what people make.

用過npm開發都知道,npm包都可以以全局的方式安裝,例如安裝一個http-server服務,可以使用npm i http-server -g來將http-server包安裝到全局環境。安裝完之后,就可以通過cmd或者powershell運行全局工具http-server命令,來使用靜態托管服務。dotnet tool 就是一個類似npm全局工具的新特性,在.net core2.1正式加入。它的詳細使用方法可在微軟官方文檔查看,本文主要介紹如何編寫一個global tool並發布至nuget。

安裝.net core 2.1
安裝最新版.net core SDK 可前往DotNet官方站點的下載頁面,下載完成后雙擊安裝即可。安裝完成后打開cmd運行dotnet --version 返回版本大於或等於2.1.300表示安裝成功。

安裝global tool 項目模板
打開cmd 鍵入dotnet new --install McMaster.DotNet.GlobalTool.Templates安裝完成后運行dotnet new

模板 短名稱 語言 標記

Console Application console [C#], F#, VB Common/Console
Class library classlib [C#], F#, VB Common/Library
.NET Core Global Console Tool global-tool [C#] Console/Empty
Unit Test Project mstest [C#], F#, VB Test/MSTest
xUnit Test Project xunit [C#], F#, VB Test/xUnit
Razor Page page [C#] Web/ASP.NET
MVC ViewImports viewimports [C#] Web/ASP.NET
MVC ViewStart viewstart [C#] Web/ASP.NET
ASP.NET Core Empty web [C#], F# Web/Empty
ASP.NET Core Web App (Model-View-Controller) mvc [C#], F# Web/MVC
ASP.NET Core Web App razor [C#] Web/MVC/Razor Pages
ASP.NET Core with Angular angular [C#] Web/MVC/SPA
ASP.NET Core with React.js react [C#] Web/MVC/SPA
ASP.NET Core with React.js and Redux reactredux [C#] Web/MVC/SPA
Razor Class Library razorclasslib [C#] Web/Razor/Library/Razor Class Library
ASP.NET Core Web API webapi [C#], F# Web/WebAPI
global.json file globaljson Config
NuGet Config nugetconfig Config
Web Config webconfig Config
Solution File sln Solution
多出一個global-tool模板

.NET Core Global Console Tool global-tool [C#] Console/Empty
編寫一個網頁下載工具
接下來通過編寫一個網頁下載的小工具來演示global tool的創建過程,此小工具的功能是根據網址,下載相應的頁面html並保存為文件。

首先新建一個WebDownloader文件夾。在文件夾中運行dotnet new global-tool生成項目如下

obj
Program.cs
WebDownloader.csproj
打開WebDownloader.csproj修改為

web-downloader True Exe netcoreapp2.1 打開Program.cs修改為

using System;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Net.Http;
using McMaster.Extensions.CommandLineUtils;

namespace WebDownloader
{
[Command(Description = "網頁下載小工具")]
class Program
{
public static int Main(string[] args) => CommandLineApplication.Execute (args);

    [Argument(0, Description = "網址")]
    [Required]
    public string Url { get; }

    [Option(Description = "保存路徑")]
    public string Path { get; } = "./";

    [Option(Description = "文件名")]
    public string Name { get; } = "content.txt";

    private int OnExecute()
    {
        var client = new HttpClient();
        var content = client.GetStringAsync(Url).Result;
        var path = System.IO.Path.Combine(Path, Name);
        File.WriteAllText(path, content);
        return 0;
    }
}

}
修改完成后全部保存文件,運行dotnet pack -o ./會在項目根目錄生成一個WebDownloader.1.0.0.nupkg包。此包就是最終的nuget包,可上傳至nuget.org共享。

為了測試,我們直接將此包安裝至本地計算機。運行dotnet tool install WebDownloader -g --add-source ./完成安裝。運行web-downloader -h可以看到項目幫助文檔

網頁下載小工具

Usage: WebDownloader [arguments] [options]

Arguments:
Url 網址

Options:
-p|--path 保存路徑
-n|--name 文件名
-?|-h|--help Show help information
運行web-downloader http://www.sina.com后我們發現項目根目錄生成了一個content.txt文件內容為新浪的首頁html

新浪首頁 ... ... 如果不再使用此工具通過dotnet tool uninstall WebDownloader -g卸載即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM