zoukankan      html  css  js  c++  java
  • ASP.NET 5是如何通过XRE实现跨平台的

    挡不住的好奇心:ASP.NET 5是如何通过XRE实现跨平台的

     

    好奇号火星车

    .NET程序员也有自己的幸福,.NET的跨平台是一种幸福,.NET的开源也是一种幸福,而更幸福的是可以通过开源的.NET了解.NET是如何一步步走向跨平台的,所以幸福是一种过程。

    在.NET跨平台的进程中,ASP.NET显然走在了前头,而通过探究ASP.NET 5是如何实现跨平台的,可以稍稍满足一下自己的好奇心。

    体验ASP.NET 5跨平台有2种方式:

    1)在Mac下,git签出XRE的源代码(前身是KRuntime),然后运行sh build.sh,就能完成整个XRE项目的生成。

    2)在Mac下,写一个简单的ASP.NET项目,然后用k kestrel运行,详见不写1行代码,在Mac上体验ASP.NET 5的最简单方法

    这篇博文就从k命令下手,一探ASP.NET 5跨平台的究竟。

    运行k kestrel(即将是dotnet kestrel),实际运行的是下面的命令(根据project.json中的commands配置):

    k "Microsoft.AspNet.Hosting --server kestrel --server.urls http://localhost:8002"

    Microsoft.AspNet.Hosting是一个.NET控制台程序实现的OWIN Host(源码),kestrel是一个基于libuv用.NET实现的OWIN Server(也是Web Server,源码),kestel是由Microsoft.AspNet.Hosting加载的。

    既然Microsoft.AspNet.Hosting是一个托管程序,它自己是无法直接运行的。因为运行一个.NET程序的前提条件是CLR已运行,而CLR自己不能运行自己,CLR运行的前提是有一个host程序将它加载。

    如果你在Mac下用过Mono,就你就知道运行一个.NET程序需要用mono命令,mono命令的作用就是创建一个进程,加载Mono Runtime(Mono CLR),然后由Mono Runtime执行.NET程序。

    而在ASP.NET 5中,并没有直接用mono命令,而是k命令,自从KRuntime改名为XRE之后,k命令也将会被dotnet命令取代。

    dotnet.sh

    在非Windows平台下,k命令对应的是k.sh。现在改为XRE之后,也就是donet命令对应dotnet.sh。所以ASP.NET 5跨平台的秘密就藏在dotnet.sh中。

    下面就直击XRE项目中的scripts/dotnet.sh:

    复制代码
    #...
    if [ -f "$DIR/mono" ]; then
      exec "$DIR/mono" $MONO_OPTIONS "$DIR/dotnet.mono.managed.dll" "$@"
    else
      exec mono $MONO_OPTIONS "$DIR/dotnet.mono.managed.dll" "$@"
    fi
    复制代码

    毫无悬念,依然用的是mono。但是用了mono,如何加载.NET Core CLR,难道还是用Mono Runtime?

    带着这个疑问,顺藤摸瓜,看dotnet.mono.managed.dll干了啥。

    dotnet.mono.managed.dll的实现代码就在XRE项目中,是一个简单的C#控制台程序,它干了两件事:1)分析命令行参数;2)调用RuntimeBootstrapper.Execute():

    复制代码
    public class EntryPoint
    {
        public static int Main(string[] arguments)
        {
            //...
            arguments = ExpandCommandLineArguments(arguments);
            //...
            return RuntimeBootstrapper.Execute(arguments);
        }
    }
    复制代码

    继续顺藤摸瓜至 [dotnet.hosting.RuntimeBootstrapper],[RuntimeBootstrapper.Execute()] 调用了 [RuntimeBootstrapper.ExecuteAsync()]。

    而托管的 [RuntimeBootstrapper.ExecuteAsync()] 竟然拐了个弯,执行了非托管的dotnet命令(一个由dotnet.cpp实现的C++程序)。

    mono命令(非托管) -> Mono Runtime -> dotnet.mono.managed(托管) -> RuntimeBootstrapper(托管) -> dotnet命令(非托管),ASP.NET 5 XRE的代码真是十八弯。

    千呼万唤始出来,原来真正的主角就藏在十八弯之后。

    dotnet.cpp加载了非托管的dotnet.coreclr.dll:

    LPCWSTR pwzHostModuleName = L"dotnet.coreclr.dll";
    m_hHostModule = ::LoadLibraryExW(pwzHostModuleName, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
    pfnCallApplicationMain = (FnCallApplicationMain)::GetProcAddress(m_hHostModule, pszCallApplicationMainName);

    而dotnet.coreclr.dll是由XRE中的C++程序dotnet.coreclr.cpp实现的,最终由dotnet.coreclr.cpp加载了coreclr.dll: 

    hCoreCLRModule = ::LoadLibraryExW(L"coreclr.dll", NULL, 0);

    dotnet.coreclr.cpp就是加载CLR的主角。

    这不让人产生疑问,这也可以?仅靠一个C++程序就能加载CLR,执行.NET程序,那我们在Windows上为什么要安装一个庞大的.NET Framework?

    真的可以!一个非托管的host程序+CLR,就能运行.NET程序,不信你可以看这篇文章震撼一下:Hosting .NET Core Clr in your own process 。

    加载CLR的目的是为了执行.NET程序集中的IL代码,而要执行的程序集是由dotnet命令(前身是k命令)的命令行参数所传递过来的,比如dotnet kestrel(之前是k kestrel),对应的程序集是 Microsoft.AspNet.Hosting。CLR调用 Microsoft.AspNet.Hosting.Program.Main() 方法开始执行,ASP.NET 5就开始干活了。

    Core CLR被加载、Microsoft.AspNet.Hosting被运行之后,在 RuntimeBootstrapper.ExecuteAsync() 中,还继续加载了一些dotnet.host的相关程序集(注意:这时不是Core CLR,而是Mono Runtime)。

    复制代码
    //...
    var assembly = Assembly.Load(new AssemblyName("dotnet.host"));
    //...
    var loaderContainerType = assembly.GetType("dotnet.host.LoaderContainer");
    var cachedAssemblyLoaderType = assembly.GetType("dotnet.host.CachedAssemblyLoader");
    var pathBasedLoaderType = assembly.GetType("dotnet.host.PathBasedAssemblyLoader");
    //...
    复制代码

    到这里,不知你有没有被这十八弯给绕晕,如果没被绕晕,请继续往下看。

    疑问

    这时一个大大的问号浮现在眼前,既然dotnet命令能直接加载Core CLR,为什么还要用mono命令中转一下?

    百思不得其解。。。

    在写这篇博文的过程中,突然产生了一个大胆猜想——

    在Core CLR被加载,Microsoft.AspNet.Hosting被执行之后,为什么还要用Mono Runtime加载一些dotnet.host相关的程序集?为什么不直接用Core CLR加载呢?这只能用一个原因来解释,dotnet.host依赖的一些程序集在在.NET Framework中有实现,但是在.NET Core Framework中还没有实现,而Mono是.NET Framework的一个跨平台实现,在Mono中也有对应的实现。完整的.NET Core Framework(github.com/dotnet/corefx)还在紧张开发之中,在它出来之前,微软只能借助Mono。这也是ASP.NET的跨平台走在前面要付出的代价,随着.NET Core Framework的完成,XRE的改进,可以预计ASP.NET的跨平台是会脱离Mono的。

    当然,这只是一个猜想,如果你知道真相,欢迎来揭开。

     
     
    标签: DotNetCoreASP.NET5XRE
  • 相关阅读:
    hdu 3790 最短路径问题
    hdu 2112 HDU Today
    最短路问题 以hdu1874为例
    hdu 1690 Bus System Floyd
    hdu 2066 一个人的旅行
    hdu 2680 Choose the best route
    hdu 1596 find the safest road
    hdu 1869 六度分离
    hdu 3339 In Action
    序列化和反序列化
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4252545.html
Copyright © 2011-2022 走看看