原文连接:https://mattwarren.org/2016/07/04/How-the-dotnet-CLI-tooling-runs-your-code/
作者 Matt Warren。授权翻译,转载请保留原文链接。

就在一周前,.NET Core的正式1.0版本发布了(注:本文写于04 Jul 2016),该版本包括:

the .NET Core runtime, libraries and tools and the http://ASP.NET Core libraries.

但是,除了全新、经过改进并且跨平台的运行时之外,伴随着dotnet命令工具的出现,开发体验也发生了变化。

因此,你现在可以这样写:

dotnet new
dotnet restore
dotnet run

之后,你会获得如下输出:

Hello World!

本文主要会介绍dotnet CLI (Command Line Interface,命令行界面) 工具,更具体的说是它如何执行你的代码。如果你想要一个太长不看版本,可以参考下图,来自@citizenmatt的推文截图:

.NET可执行文件的传统执行方式

简要提醒一下,.NET可执行文件不能直接运行(它们只是IL,而不是机器代码),因此Windows操作系统始终需要一些技巧来执行它们,下文来自《CLR via C#》:

Windows检查完EXE文件的标头以确定是创建32位进程,64位进程还是WoW64进程后,Windows将x86,x64或IA64版本的MSCorEE.dll加载到进程的地址空间中。 …然后,该进程的主线程调用MSCorEE.dll内部定义的方法。 此方法初始化CLR,加载EXE程序集,然后调用其入口点方法(Main)。 此时,托管应用程序已启动并正在运行。

.NET可执行文件的新的执行方式

dotnet run

那么,现在有了新的、跨平台的CoreCLR和CLI工具之后,事情会发生什么变化呢? 首先,要了解幕后情况,我们需要设置一些环境变量(COREHOST_TRACE和DOTNET_CLI_CAPTURE_TIMING),以便获得更详细的输出:

在这里,参杂在这漂亮的ASCII风格的输出中,我们可以发现dotnet run实际上执行以下命令:

dotnet exec --additionalprobingpath C:\Users\matt\.nuget\packages c:\dotnet\bin\Debug\netcoreapp1.0\myapp.dll

注意:这是在运行控制台应用程序时发生的情况。 CLI工具支持其他方案,例如自托管网站,它们的工作方式有所不同。

dotnet exec 和 corehost

到目前为止,所有事情都发生在托管代码中。但是一旦dotnet exec被调用,我们就会跳到corehost应用内的非托管代码。另外会有一些其他的.dll被加载,最后一个就是CoreCLR运行时本身。(单击以转到每个模块的main源文件)

corehost的主要任务是计算并找到运行该应用程序所需的所有dll以及它们的依赖。完整的输出可以点击链接查看,但总的来说,它会处理:

可以发现这里有很多独立的文件,这是由于CoreCLR执行的是一套所谓的“按需付费”(pay-for-play)模型,可以看来自Motivation Behind .NET Core对此的描述:

通过分解CoreFX库并允许单个应用程序仅提取它所需的CoreFX某些部分(即所谓的“按需付费”模型),使用ASP. NET 5构建的基于服务器的应用程序可以最大程度地减少其依赖性。

最后,一旦完成所有的整理工作,控制权就会移交给corehost,但在设置以下属性来控制CoreCLR本身的执行之前,不会这样做:

  • TRUSTED_PLATFORM_ASSEMBLIES =
    • 235个 .dlls (99 托管, 136 原生)的路径, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.0.0-rc2-3002702
  • APP_PATHS =
    • c:\dotnet\bin\Debug\netcoreapp1.0
  • APP_NI_PATHS =
    • c:\dotnet\bin\Debug\netcoreapp1.0
  • NATIVE_DLL_SEARCH_DIRECTORIES =
    • C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.0.0-rc2-3002702
    • c:\dotnet\bin\Debug\netcoreapp1.0
  • PLATFORM_RESOURCE_ROOTS =
    • c:\dotnet\bin\Debug\netcoreapp1.0
    • C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.0.0-rc2-3002702
  • AppDomainCompatSwitch =
    • UseLatestBehaviorWhenTFMNotSpecified
  • APP_CONTEXT_BASE_DIRECTORY =
    • c:\dotnet\bin\Debug\netcoreapp1.0
  • APP_CONTEXT_DEPS_FILES =
    • c:\dotnet\bin\Debug\netcoreapp1.0\dotnet.deps.json
    • C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.0.0-rc2-3002702\Microsoft.NETCore.App.deps.json
  • FX_DEPS_FILE =
    • C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.0.0-rc2-3002702\Microsoft.NETCore.App.deps.json

注意:你还可以通过使用以下命令直接调用corehost.exe来运行你的应用程序:

corehost.exe C:\dotnet\bin\Debug\netcoreapp1.0\myapp.dll

执行一个 .NET 程序集

最终,我们可以通过下面这段从unixinterface.cpp 中截取的代码来查看一下.NET dll/assembly是如何被加载和执行的。

hr = host->SetStartupFlags(startupFlags);
IfFailRet(hr); hr = host->Start();
IfFailRet(hr); hr = host->CreateAppDomainWithManager(
appDomainFriendlyNameW,
// Flags:
// APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS
// - By default CoreCLR only allows platform neutral assembly to be run. To allow
// assemblies marked as platform specific, include this flag
//
// APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP
// - Allows sandboxed applications to make P/Invoke calls and use COM interop
//
// APPDOMAIN_SECURITY_SANDBOXED
// - Enables sandboxing. If not set, the app is considered full trust
//
// APPDOMAIN_IGNORE_UNHANDLED_EXCEPTION
// - Prevents the application from being torn down if a managed exception is unhandled
//
APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS |
APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP |
APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT,
NULL, // Name of the assembly that contains the AppDomainManager implementation
NULL, // The AppDomainManager implementation type name
propertyCount,
propertyKeysW,
propertyValuesW,
(DWORD *)domainId);

如代码所示,这里利用了ICLRRuntimeHost接口,该接口是CLR基于COM的托管API的一部分。 尽管文件名是unixinterface.cpp,但它实际上来自Windows版的CLI工具。 在CoreCLR的跨平台世界中,最初为Unix编写的托管API已在所有平台上复制,以便任何想要使用它的工具都可以使用一个通用接口,有关与此的更多信息,请参见以下GitHub问题:

就是这样,你的.NET代码现在正在运行,真的很简单!

额外的参考:

 

dotnet CLI工具是如何运行你的代码的的更多相关文章

  1. NodeJS4-8静态资源服务器实战_构建cli工具

    Cli(command-line interface),中文是 命令行界面,简单来说就是可以通过命令行快速生成自己的项目模板等功能(比较熟悉的是vue-cli脚手架这些),把上述写的包做成Cli工具. ...

  2. 『.NET Core CLI工具文档』(六)dotnet 命令

    说明:本文是个人翻译文章,由于个人水平有限,有不对的地方请大家帮忙更正. 原文:dotnet command 翻译:dotnet 命令 名称 dotnet -- 运行命令行命令的一般驱动程序 概要 d ...

  3. 尝试在mac上用dotnet cli运行asp.net core示例程序

    自从知道微软用dotnet cli取代dnx之后,一直在等dotnet cli支持asp.net core... 昨天看到这篇新闻(ASP.NET Core 1.0 Hello World)后,才知道 ...

  4. 『.NET Core CLI工具文档』(十四)dotnet-install 脚本参考

    说明:本文是个人翻译文章,由于个人水平有限,有不对的地方请大家帮忙更正. 原文:dotnet-install scripts reference 翻译:dotnet-install 脚本参考 名称 d ...

  5. 『.NET Core CLI工具文档』(八)dotnet-restore

    说明:本文是个人翻译文章,由于个人水平有限,有不对的地方请大家帮忙更正. 原文:dotnet-restore 翻译:dotnet-restore 名称 dotnet-restore - 还原一个项目的 ...

  6. 『.NET Core CLI工具文档』(一).NET Core 命令行工具(CLI)

    说明:本文是个人翻译文章,由于个人水平有限,有不对的地方请大家帮忙更正. 原文:.NET Core Command Line Tools 翻译:.NET Core命令行工具 什么是 .NET Core ...

  7. dotnet cli

    前言 dotnet cli (Command-Line Interface) .net 源代码和二进制文件管理工具.需要安装 .NET Core SDK. 终端执行 dotnet --info 可以打 ...

  8. 微信 CLI 工具正式发布 v1.0

    前言 为了让开发者可以更加方便舒适地获取到微信开发的资源,今天我们基于 Senparc.Weixin SDK 正式发布了基于 .NET 的微信 CLI 工具:Weixin.CLI(v1.0). 通过 ...

  9. 『.NET Core CLI工具文档』(十一)dotnet-test

    说明:本文是个人翻译文章,由于个人水平有限,有不对的地方请大家帮忙更正. 原文:dotnet-test 翻译:dotnet-test 名称 dotnet-test - 使用配置的测试运行器运行单元测试 ...

随机推荐

  1. MySQL记录操作(多表查询)

    准备 建表与数据准备 #建表 create table department( id int, name varchar(20) ); create table employee( id int pr ...

  2. js 碰撞+拖拽

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. Scikit-learn之特征抽取

    一.安装包 pip install Scikit-learn 二.字典特征抽取 1.字典特征抽取 #!/usr/bin/env python # -*- coding: utf-8 -*- #auth ...

  4. MAC下安装Fiddler抓包工具

    需求 我们都知道在Mac电脑下面有一个非常好的抓包工具:Charles.但是这个只能抓代理的数据包.但是有时候想要调试本地网卡的数据库 Charles 就没办法了.就想到了在windows下面的一个F ...

  5. 表单配置项写法,表单写成JSON数组套对象,一行是一个数组单位,一列是一个对象单位,然后再写一个公共组件读取这个配置,循环加载slot,外层载入slot的自定义部分,比如input select等,这种写法就是把组件嵌套改为配置方式

    表单配置项写法,表单写成JSON数组套对象,一行是一个数组单位,一列是一个对象单位,然后再写一个公共组件读取这个配置,循环加载slot,外层载入slot的自定义部分,比如input select等,这 ...

  6. 《ASP.NET Core 3框架揭秘》5折预售暨样章发布

    <ASP.NET Core 3框架揭秘>于昨天在下午京东正式开始预售,并在半天之内销售近一千套.为了回馈读者,出版社与京东谈了一个5折的价格.与此同时,我将本书最核心的内容作为样章(3章) ...

  7. Git 的简单使用及ssh配置问题-赖大大

    软件安装 第一步当然是安装啦. 官方网址:https://git-scm.com/ 具体操作 在你本地电脑的文件夹里右击鼠标,选Git base here 显然,你是在本地仓库的master分支上,通 ...

  8. SOFARPC模式下的Consul注册中心

    Consul大家不陌生,就是和Zookeeper.Nacos一伙的,能够作为微服务基础架构的注册中心,算是比较成熟的组件,和Springcloud集成顺滑, 考虑到Eureka已经停止更新,所以有必要 ...

  9. Go语言之Go语言变量

    GO 语言变量 Go语言是静态类型语言,因此变量(variable)是有明确类型的,编译器也会检查变量类型的正确性. 标识符 在编程语言中标识符就是程序员定义的具有特殊意义的词,比如变量名.常量名.函 ...

  10. shell编程学习之使用jq对json数据进行提取

    shell编程学习之使用jq对json提取 jq命令允许直接在命令行下对JSON进行操作,包括分片.过滤.转换等 ,jq是用C编写,没有运行时依赖,所以几乎可以运行在任何系统上.预编译的二进制文件可以 ...