• 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:Usersmatt.nugetpackages c:dotnetinDebug etcoreapp1.0myapp.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 FilesdotnetsharedMicrosoft.NETCore.App1.0.0-rc2-3002702
    • APP_PATHS =
      • c:dotnetinDebug etcoreapp1.0
    • APP_NI_PATHS =
      • c:dotnetinDebug etcoreapp1.0
    • NATIVE_DLL_SEARCH_DIRECTORIES =
      • C:Program FilesdotnetsharedMicrosoft.NETCore.App1.0.0-rc2-3002702
      • c:dotnetinDebug etcoreapp1.0
    • PLATFORM_RESOURCE_ROOTS =
      • c:dotnetinDebug etcoreapp1.0
      • C:Program FilesdotnetsharedMicrosoft.NETCore.App1.0.0-rc2-3002702
    • AppDomainCompatSwitch =
      • UseLatestBehaviorWhenTFMNotSpecified
    • APP_CONTEXT_BASE_DIRECTORY =
      • c:dotnetinDebug etcoreapp1.0
    • APP_CONTEXT_DEPS_FILES =
      • c:dotnetinDebug etcoreapp1.0dotnet.deps.json
      • C:Program FilesdotnetsharedMicrosoft.NETCore.App1.0.0-rc2-3002702Microsoft.NETCore.App.deps.json
    • FX_DEPS_FILE =
      • C:Program FilesdotnetsharedMicrosoft.NETCore.App1.0.0-rc2-3002702Microsoft.NETCore.App.deps.json

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

    corehost.exe C:dotnetinDebug etcoreapp1.0myapp.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代码现在正在运行,真的很简单!

    额外的参考:

     
  • 相关阅读:
    X、Y轴抖动的动画
    ViewFlipper的简单用法
    让手机连接到指定的WIFI网络,适用于之前已经连过的网络
    Eclipse 离线汉化的方法
    自己写的SeekBarPreference,可以实现seekbar滑动监听和设置默认进度和最大进度
    录制Android屏幕软件——屏幕录像专家
    【转】解决Android因加载多个大图引起的OutOfMemoryError,内存溢出的问题
    Java中的线程实现
    获得手机当前的ip地址
    操作Wifi的工具类
  • 原文地址:https://www.cnblogs.com/murongxiaopifu/p/12689147.html
Copyright © 2020-2023  润新知