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

作者:   出处:互联网   2015-07-02 22:39:57   阅读:5

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


 

AD:

 

 

好奇号火星车


 

.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 $@
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的。


 

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

 

Copyright© 2006-2015 ComponentCN.com all rights reserved.重庆磐岩科技有限公司(控件中国网) 版权所有 渝ICP备12000264号 法律顾问:元炳律师事务所
客服软件
live chat