dotnet cli是 .Net Core功能中最有用的特性之一。在这篇文章里,我们将介绍几个.Net OSS工具是如何使用dotnet cli,并介绍如何在日常开发中使用新的cli工具。

正文

关键要点

  • dotnet cli使得基于. Net项目的自动化和脚本编写变得非常简单,尤其是与十多年前的. Net技术相比。
  • dotnet cli可扩展性模型创造了条件,使得通过Nuget将外部.NET编写的命令行程序集成到你的自动化构建中成为可能。
  • dotnet cli允许在你的构建脚本中针对解决方案进行测试。
  • dotnet cli的测试输出有助于更好地使用持续集成(CI)。
  • 使用Docker之类的容器技术比使用dotnet cli要容易得多。

随着.NET Core 2.0的发布,微软拥有了通用、模块化、跨平台和开源平台的下一个主要版本,该版本最初于2016年发布。.NET Core已经创建了许多API,这些API在.NET框架的当前版本中是可用的。它最初是为了下一代ASP.NET解决方案创建的,但现在是许多其他场景的驱动和基础,包括物联网、云和下一代移动解决方案。在关于.NET Core的第二个系列的文章中,我们将进一步探讨.NET Core的优点,以及它如何不仅有益于传统的.NET开发人员,也有益于所有需要为市场提供强健的、高效的和经济的解决方案的技术人员。

InfoQ的这篇文章是“.NET Core\u0026quot;系列的一部分。您可以通过RSS订阅接收通知。

最近总有人问我,和那些要么迟疑,要么不能退出旧版本、全功能的.NET的人相比,选择.NET Core的优势是什么?我在回答中会提到.NET Core 有更好的性能、改进的csproj文件格式、改进的ASP可测试性,并且它是跨平台的。

作为几个OSS工具(Marten、StructureMap,以及在这个项目中作为例子被引用的Alba)的作者,对我个人而言最大的优势可能是dotnet cli的出现。我个人认为,结合新的.NET SDK csproj文件格式一起使用时,dotnet cli工具使我可以更容易创建项目和维护构建脚本。我可以更容易在构建脚本中运行测试,更容易使用和分发Nuget包,cli可扩展性机制非常适合将通过Nuget包分发的自定义可执行文件合并到自动构建中。

若要开始使用dotnet cli,首先要在开发机器上安装.NET SDK。安装完成后,给你一些有用的提示:

  • 将“dotnet”工具全局安装到你的PATH中,这样在任何地方都可以通过命令行提示符使用它。
  • dotnet cli采用Linux风格的命令语法,用“–word [value]”这种普通写法表示选择的参数,或者直接用缩写形式“-w [value]”。如果您习惯Git或Node.js命令行工具,就不会对dotnet cli感到陌生。
  • “dotnet --help”将列出已安装的命令和一些基本语法用法。
  • “dotnet --info”将告诉你使用的是哪个版本的dotnet cli。在持续集成构建中调用此命令可能是一个好主意,以便在本地工作并在构建服务器失败时排除故障,反之亦然。
  • 尽管我在本文中讨论的是.NET Core,但是请注意,你可以在完整.NET框架的以前版本中使用新的SDK项目格式和dotnet cli。

命令行中的Hello World

为了简单了解一下dotnet cli的一些亮点,让我们假设想构建一个简单的“Hello World”ASP.NET Core应用程序。不过,为了好玩,我们来添加一些新花样:

1.我们的web服务将在一个单独的项目中进行自动化测试。
2.我们将通过Docker容器部署我们的服务,因为这是很酷的做法(它展示了更多的dotnet cli)。
3.当然,我们将尽可能多地使用dotnet cli。
如果您想看到这段代码的最终结果,请查看this GitHub repository。

首先,让我们从一个名为“DotNetCliArticle”的空目录开始,并打开您最喜欢的命令行工具到该目录。我们将从使用“dotnet new”命令来生成解决方案文件和新项目开始。.NET SDK附带了几个用于创建常见项目类型或文件的通用模板,以及其他可作为外接程序使用的模板(稍后部分将对此进行详细介绍)。要查看在你的机器上可用的模板,可以使用以下命令dotnet new -help,它应该会给出如下输出:

你可能会留意到有一个sln模板,它针对的是空解决方案文件。我们将使用该模板,键入dotnet new sln命令,该命令将生成以下输出:

The template \u0026quot;Solution File\u0026quot; was created successfully.

默认情况下,此命令将以包含的目录命名解决方案文件。因为我将根目录命名为为“DotNetCliArticle”,所以生成的解决方案文件是“DotNetCliArticle.sln”。

接下来,让我们用以下命令添加“Hello,World”的实际项目:

dotnet new webapi --output HeyWorld

上面的命令意思是将“webapi”模板用到通过“output”参数选择的“HeyWorld”中。这个模板将生成一个精简的MVC Core项目结构,适合于无头API。同样,默认的做法是根据所在的目录命名项目文件,因此我们在目录下得到一个名为“HeyWorld.csproj”的文件,以及所有基本文件,组成一个最小的ASP.NET MVC Core API项目。该模板还设置了所有必要的Nuget对ASP.NET Core的引用,我们在新项目启动时会用到它们。

由于我刚好在一个小型Git存储库中构建了它,在使用Git add添加了任何新文件之后,我使用Git status查看新创建的文件:

    new file: HeyWorld/Controllers/ValuesController.cs    new file: HeyWorld/HeyWorld.csproj    new file: HeyWorld/Program.cs    new file: HeyWorld/Startup.cs    new file: HeyWorld/appsettings.Development.json    new file: HeyWorld/appsettings.json

现在,要将新项目添加到我们的空解决方案文件中,您可以像这样使用“dotnet sln”命令:

dotnet sln DotNetCliArticle.sln add HeyWorld/HeyWorld.csproj

现在我们有了一个新的ASP.NET Core API服务作为外壳,无需打开Visual Studio.NET(或者是JetBrains Rider)。为了更进一步,在编写任何实际代码之前启动我们的测试项目,我发出以下命令:

dotnet new xunit --output HeyWorld.Testsdotnet sln DotNetCliArticle.sln add HeyWorld.Tests/HeyWorld.Tests.csproj

上面的命令使用xUnit.NET创建一个新项目,并将该新项目添加到我们的解决方案文件中。测试工程需要对“HeyWorld”的工程引用,幸运的是,我们可以使用很棒的“dotnet add”工具添加工程引用,如下所示:

dotnet add HeyWorld.Tests/HeyWorld.Tests.csproj reference HeyWorld/HeyWorld.csproj

在打开解决方案之前,我知道还有一些Nuget参考资料,我想在测试项目中使用它们。我选择的断言工具是Shoully,因此我将通过对命令行发出另一个调用来添加对最新版本的shoully的引用:

dotnet add HeyWorld.Tests/HeyWorld.Tests.csproj package Shouldly

命令行的输出如下:

info : Adding PackageReference for package 'Shouldly' into project 'HeyWorld.Tests/HeyWorld.Tests.csproj'.log : Restoring packages for /Users/jeremydmiller/code/DotNetCliArticle/HeyWorld.Tests/HeyWorld.Tests.csproj...info : GET https://api.nuget.org/v3-flatcontainer/shouldly/index.jsoninfo : OK https://api.nuget.org/v3-flatcontainer/shouldly/index.json 109msinfo : Package 'Shouldly' is compatible with all the specified frameworks in project 'HeyWorld.Tests/HeyWorld.Tests.csproj'.info : PackageReference for package 'Shouldly' version '3.0.0' added to file '/Users/jeremydmiller/code/DotNetCliArticle/HeyWorld.Tests/HeyWorld.Tests.csproj'.

接下来,我想向名为Alba的测试项目添加至少一个Nuget引用。我将使用AspNetCore2来编写针对新的web应用程序的HTTP契约测试:

dotnet add HeyWorld.Tests/HeyWorld.Tests.csproj package Alba.AspNetCore2

现在,在使用代码之前先检查一下,我将在命令行发出以下命令构建解决方案中的所有项目,确保它们都可以正常编译:

dotnet build DotNetCliArticle.sln

由于Alba.AspNetCore2和ASP.NET Core Nuget在HeyWorld项目中的引用之间的菱形依赖版本的冲突,所以没有编译。不过不用担心,因为这个问题很容易解决,只需修复Microsoft.AspNetCore的版本依赖关系即可。测试项目中的所有Nuget都是这样的:

dotnet add HeyWorld.Tests/HeyWorld.Tests.csproj package Microsoft.AspNetCore.All --version 2.1.2

在上面的示例中,使用值为“2.1.2”的“–version”标志将修复对该版本的引用,而不仅仅是使用从Nuget提要中找到的最新版本。
为了再次检查我们的Nuget依赖问题是否已经解决,我们可以使用下面的命令进行检查,它比重新编译所有东西要更快:

dotnet clean \u0026amp;\u0026amp; dotnet restore DotNetCliArticle.sln

作为一个有经验的.NET开发人员,我非常担心临时/obj和/bin文件夹中残留的文件。因此,我在Visual Studio中使用“Clean Solution”命令,以防我试图改变引用的时候落下些什么。从命令行执行“dotnet clean”命令是完全相同的操作。

同样,针对众所周知的Nuget依赖问题,“dotnet restore”命令在解决方案中都试着去解决了。在这种情况下,使用“dotnet restore”可以让我们快速发现任何潜在的冲突或丢失的Nuget引用,而无需进行完整的编译,我在自己的工作中主要就采用该命令。在最新版本的dotnet cli中,在调用“dotnet build/test/pack/etc”时,会自动为您完成Nuget解析(该行为可以用标记覆盖),这将首先需要Nuget。

我们调用的“dotnet restore DotNetCliArticle.sln”干净利落地运行完毕,没有错误,所以我们终于可以准备编写一些代码了。让我们打开您选择的C#编辑器,向HeyWorld添加一个代码文件。测试项目包含一个非常简单的HTTP协议测试,它将指定我们希望从新的HeyWorld应用程序中的“GET: /”路由获得的行为:

using System.Threading.Tasks;using Alba;using Xunit;namespace HeyWorld.Tests{    public class verify_the_endpoint    {        [Fact]        public async Task check_it_out()        {            using (var system = SystemUnderTest.ForStartup\u0026lt;Startup\u0026gt;())            {                await system.Scenario(s =\u0026gt;                {                    s.Get.Url(\u0026quot;/\u0026quot;);                    s.ContentShouldBe(\u0026quot;Hey, world.\u0026quot;);                    s.ContentTypeShouldBe(\u0026quot;text/plain; charset=utf-8\u0026quot;);                });            }        }    }}

结果文件应该保存在具有适当名称(如verify_the_endpoints.cs)的HeyWorld.Tests目录。

在没有深入了解Alba机制前,我们的新HeyWorld应用的首页路由应该写出“Hey, world”。虽然我们还没有在HeyWorld应用中编写任何实际的代码,但是我们仍然可以运行这个测试,看看它能够连接正确,还是因为某些“理所当然的理由”而失败。

回到命令行,我可以使用以下命令运行测试项目中的所有测试:

dotnet test HeyWorld.Tests/HeyWorld.Tests.csproj

我们的一个测试会失败,因为还没有实现任何东西,它给了我们这样的输出:

Build started, please wait...Build completed.Test run for /Users/jeremydmiller/code/DotNetCliArticle/HeyWorld.Tests/bin/Debug/netcoreapp2.1/HeyWorld.Tests.dll(.NETCoreApp,Version=v2.1)Microsoft (R) Test Execution Command Line Tool Version 15.7.0Copyright (c) Microsoft Corporation. All rights reserved.Starting test execution, please wait...Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.Test Run Successful.Test execution time: 2.4565 Seconds

为了把输出求和,执行了一个测试,但是失败了。我们还可以看到标准的xUnit输出,它提供了一些关于测试失败原因的信息。这里需要注意的是,“dotnet test”命令将返回一个退出代码,如果所有测试都通过,则返回0,表示成功;如果任何测试失败,则返回一个非零退出代码,表示失败。这对于持续集成(CI)脚本非常重要,大多数CI工具使用任何命令的退出代码来确定构建何时失败。

我认为上面的测试之所以失败是因为“理所当然的原因”,这意味着测试工具似乎能够引导真正的应用程序,我希望得到404响应,因为还没有编写任何代码。接下来,让我们为预期的行为实现一个MVC Core 端点:

public class HomeController : Controller{    [HttpGet(\u0026quot;/\u0026quot;)]    public string SayHey()    {        return \u0026quot;Hey, world!\u0026quot;;    }}

(注意,前面的代码应该作为HeyWorld\\startup.cs文件中的附加类添加)

再次回到命令行,让我们运行前面的“dotnet test HeyWorld.Tests/HeyWorld.Tests.csproj”命令,希望看到这样的结果:

Build started, please wait...Build completed.Test run for /Users/jeremydmiller/code/DotNetCliArticle/HeyWorld.Tests/bin/Debug/netcoreapp2.1/HeyWorld.Tests.dll(.NETCoreApp,Version=v2.1)Microsoft (R) Test Execution Command Line Tool Version 15.7.0Copyright (c) Microsoft Corporation. All rights reserved.Starting test execution, please wait...Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.Test Run Successful.Test execution time: 2.4565 Seconds

好了,现在测试通过了,让我们运行实际的应用程序。由于“dotnet new webapi”模板使用进程内的 in-process Kestrel web server 来处理HTTP请求,所以要运行新的HeyWorld应用程序,我们唯一需要做的一件事就是从命令行使用以下命令启动它:

 dotnet run --project HeyWorld/HeyWorld.csproj

运行上面的命令应该会得到如下输出:

Using launch settings from HeyWorld/Properties/launchSettings.json...: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]User profile is available. Using '/Users/jeremydmiller/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.Hosting environment: DevelopmentContent root path: /Users/jeremydmiller/code/DotNetCliArticle/HeyWorldNow listening on: https://localhost:5001Now listening on: http://localhost:5000Application started. Press Ctrl+C to shut down.

要测试我们现在正在运行的新应用程序,只需在浏览器中导航如下:

处理HTTPS设置超出了本文的范围。

请再次注意,我假设所有命令都是在将当前目录设置为解决方案根文件夹的情况下执行的。如果当前目录是一个项目目录,并且只有一个*.csproj。那么,您只需在该目录下键入“dotnet run”即可。现在我们已经有了一个经过测试的web api应用程序,接下来让我们将HeyWorld放到Docker镜像中。使用 the standard template for dockerizing a .NET Core application,我们将向HeyWorld项目添加一个Dockerfile,内容如下:

FROM microsoft/dotnet:sdk AS build-envWORKDIR /appCopy csproj and restore as distinct layersCOPY *.csproj ./RUN dotnet restoreCopy everything else and buildCOPY . ./RUN dotnet publish -c Release -o outBuild runtime imageFROM microsoft/dotnet:aspnetcore-runtimeWORKDIR /appCOPY --from=build-env /app/out .ENTRYPOINT [\u0026quot;dotnet\u0026quot;, \u0026quot;HeyWorld.dll\u0026quot;]

(注意,前面的文本应该保存到项目目录中名为Dockerfile的文本文件中——在本例中是HeyWorld\\Dockerfile)。

因为这篇文章仅仅是关于dotnet cli的,我只想关注Dockerfile中它的两种用法:

1.“dotnet restore”–正如我们在上面学到的,这个命令将解决应用程序的任何Nuget依赖关系。

2.“dotnet publish -c Release -o out”–“dotnet publish”命令将构建指定的项目,并将组成应用程序的所有文件复制到给定位置。在我们的例子中,“dotnet publish”将为HeyWorld本身复制已编译的程序集、从Nuget依赖项引用的所有程序集、配置文件以及csproj文件中引用的任何文件。

请注意,在上面的用法中,我们必须通过使用“-c Release”标志明确地告知“dotnet publish”用“Release”配置编译。那些用于编码的dotnet cli命令(例如“build”、“publish”、“pack”)如果没有指定,将以 “Debug”为默认值。注意这种行为,如果要发布用于生产的Nuget或应用程序,请记住指定“-c Release”或“-configuration Release”。别怪我没提醒你。

为了完成整个周期,我们现在可以使用以下命令通过Docker构建和部署我们的小HeyWorld应用程序:

docker build -t heyworld .docker run -d -p 8080:80 --name myapp heyworld

第一个命令为我们的应用程序“heyworld”构建并本地发布Docker镜像。第二个命令实际上作为一个名为“myapp”的Docker容器运行我们的应用程序。您可以打开浏览器访问“http://localhost:8080”予以验证。

总结

dotnet cli使得基于. NET项目的自动化和脚本编写变得非常简单,尤其是与十多年前的.NET技术相比。在许多情况下,您甚至可能会避开任何基于任务的构建脚本工具(Cake、Fake、Rake、Psake等),而选择只委托给dotnet cli的简单shell脚本。此外,dotnet cli可扩展性模型可以很容易地将外部.NET授权的命令行应用程序通过Nuget分布到自动构建程序中。

关于作者

杰里米·米勒(Jeremy Miller)在密苏里州一个农场社区长大,那里有一群“特别”的人,名叫“树荫技工”。通常,他们不是世界上最有名望的人,但他们有解决机械问题的诀窍,而且做事鲁莽无畏。如果你发现从一辆停在街区的通勤车下伸出来两条腿,那他想必就是名修理工了,他的周围是一些骨架车,堆挤在他那长满灌木、堆满垃圾的院子里。你看到的被遗弃在他周围的打浆机并不是没用的,他们是素材。他会零零碎碎地进行些小调整,然后根据你的需要想出一个创造性的解决方案。尽管名声一般,但一个树荫技工知道如何让东西运行。虽然米勒没有任何特殊的机械能力(尽管他拥有机械工程学位),但他喜欢把自己当成一个像树荫技工似的开发人员。他的硬盘上肯定到处都是废弃的开源项目碎片。

随着.NET Core 2.0的发布,微软拥有了通用、模块化、跨平台和开源平台的下一个主要版本,该版本最初于2016年发布。.NET Core已经创建了许多API,这些API在.NET框架的当前版本中是可用的。它最初是为了下一代ASP.NET解决方案创建的,但现在是许多其他场景的驱动和基础,包括物联网、云和下一代移动解决方案。在关于.NET Core的第二个系列的文章中,我们将进一步探讨.NET Core的优点,以及它如何不仅有益于传统的.NET开发人员,也有益于所有需要为市场提供强健的、高效的和经济的解决方案的技术人员。

InfoQ的这篇文章是“.NET Core\u0026quot;系列的一部分。您可以通过RSS订阅接收通知。
查看英文原文:A Quick Tour of the .NET CLI

一文带你快速读懂.NET CLI相关推荐

  1. 七个步骤,带你快速读懂 RPC 框架原理

    1. RPC框架的概念 RPC(Remote Procedure Call)–远程过程调用,通过网络通信调用不同的服务,共同支撑一个软件系统,微服务实现的基石技术.使用RPC可以解耦系统,方便维护,同 ...

  2. chrome session丢失_一文带你彻底读懂Cookie、Session、Token到底是什么

    在了解这三个概念之前我们先要了解HTTP是无状态的Web服务器,什么是无状态呢?就像上面夏洛特烦恼中经典的一幕对话一样,一次对话完成后下一次对话完全不知道上一次对话发生了什么.如果在Web服务器中只是 ...

  3. 六大维度层层剖析,一篇文章带你快速读懂信息无障碍

    我的同事和朋友有一部分是视障人士--盲人或者低视力. 这类群体,据中国盲人协会最新统计在中国有1700多万,加上病变.意外.功能性退化,视障人群比例大约是100比1,这个比例其实很高. 我的这些朋友习 ...

  4. 红黑树效率为甚恶魔是log_一文带你彻底读懂红黑树(附详细图解)

    红黑树简介 红黑树是一种自平衡的二叉查找树,是一种高效的查找树.它是由 Rudolf Bayer 于1972年发明,在当时被称为对称二叉 B 树(symmetric binary B-trees).后 ...

  5. 如何快速读懂开源代码?

    文章目录 **RUN起来** **调试** **把控关键数据结构和函数** **从小的开始** **关注一个模块** **工具** **一.阅读开源代码存在的一些误区** 二.阅读代码的心态 **三. ...

  6. 快速读懂UML类图,搞懂类之间的6大关系,轻松绘制UML类图

    快速读懂UML类图,搞懂类之间的6大关系,轻松绘制UML类图 前言 一.UML类图简介 二.类之间的六大关系及UML类图 1.依赖关系及UML类图表示 2.泛化关系及UML类图表示 3.实现关系及UM ...

  7. html语言代码大全,菜鸟快速读懂HTML语言_html

    html语言是网页制作的基础,是初学者必学的内容.虽然现在有许多所见即所得的网页制作工具,但是说到底,还是有必要了解一些HTML的语法.这样,您可以更精确的控制页面的排版,可以实现更多的功能.HTML ...

  8. 网络编程懒人入门(十二):快速读懂Http/3协议,一篇就够!

    本文中文译文由作者"ably.io"发布于公众号"高可用架构",译文原题:<深入解读HTTP3的原理及应用>.英文原题:<HTTP/3 dee ...

  9. 23、90秒快速“读懂”STP(生成树)工作原理

    23.90秒快速"读懂"STP(生成树)工作原理 https://www.toutiao.com/i6794982558787437063/?tt_from=weixin& ...

最新文章

  1. 如何:对 SharePoint 列表项隐藏 ECB 中的菜单项
  2. PHP 连接 MSSQL用port时候的注意事项
  3. 【Android 应用开发】Canvas 精准绘制文字 ( 测量文本真实边界 | 将文本中心点与给定中心点对齐 )
  4. 【mysql】成绩单表,找到所有成绩都不及格的所有人
  5. boost::typeindex::runtime_cast相关的测试程序
  6. Eclipse vs IDEA快捷键对比大全
  7. XML DTD用法【转载】
  8. 在CentOS 7上利用systemctl添加自定义系统服务 /usr/lib/systemd/
  9. 微信小程序开发学习笔记001--认识微信小程序,第一个微信小程序
  10. vue 写门户网站_你不得不知道的Vue项目技巧
  11. C#之判断Mysql数据库是否存在
  12. Word2013无法正常加载mathtype
  13. CmsEasy可视化编辑商城系统源码
  14. 关于工作后定居城市的思考以及房价…
  15. 网秦创始人林宇称遭史文勇非法拘禁 后者称是恶意中伤
  16. 轻松学编曲,论FL钢琴卷帘
  17. @loj - 2478@「九省联考 2018」林克卡特树
  18. 布谷鸟哈希函数的参数_Cuckoo Hash 布谷鸟哈希
  19. 数字电路之Verilog红绿灯设计
  20. 360极速浏览器浏览网页字体模糊的解决方法

热门文章

  1. VS2008 包加载失败导致VS2008打开 WebApplication项目时没有设计视图
  2. sql中 set 和select 的区别
  3. 设计一个算法找一条从迷宫入口到出口的最短路径。_我花了一夜用数据结构给女朋友写个H5走迷宫游戏...
  4. lncRNA是什么?
  5. 北斗导航 | 现代授时技术——北斗GPS导航系统
  6. php中表单的非空验证,Javascript的表单与验证-非空验证_javascript技巧
  7. java pl0 四元式,【编译原理】c++实现自下而上语法分析及中间代码(四元式)生成...
  8. 如何计算像素当量_基于非线性标定的桥梁裂缝精确视频测量技术研究
  9. mysql 不停机_mysql之 mysql 5.6不停机主从搭建(一主一从基于日志点复制)
  10. 关于char[]转换成LPCWSTR的有关问题