dotnet CLI工具是如何運行你的代碼的


原文連接:
作者 Matt Warren。授權翻譯,轉載請保留原文鏈接。

就在一周前,.NET Core的正式1.0版本發布了(注:本文寫於04 Jul 2016),該版本包括:

the .NET Core runtime, libraries and tools and the   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代碼現在正在運行,真的很簡單!

額外的參考:

 


免責聲明!

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



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