Since the successful running of the first "Hello World". NET core application with dotnet run, there has always been a curiosity: How dotnet Run runs a. NET core application?
This curiosity was further stimulated after the upgrade from ASP. RC1 to ASP. NET Core 1.0 and running an ASP. NET core site on Linux with local machine code, so "Quest dotnet Run" logically became. NET cross-platform journey to the next station.
First we know what the dotnet command is? The dotnet command is actually a C # write simple. NET console program (see Program.cs), but why is the dotnet command a local executable after installing the dotnet CLI on a different operating system platform? The hero is still behind the. NET native,dotnet command that has seen its power in the previous post. NET console program is compiled into a local machine code for different operating systems, the dotnet command itself is a practical application of. NET Native.
Next, we follow the dotnet command's Program.cs to explore the secret of Dotnet run running the. NET Core application.
Dotnet Program.cs's C # code does not exceed 200 lines, and the most relevant to our quest is the following piece of code:
varBuiltins =Newdictionary<string, func<string[],int>>{ //...["Run"] =Runcommand.run,//...}; Func<string[],int>builtIn;if(Builtins.trygetvalue (Command, outbuiltIn)) { returnbuiltIn (Appargs.toarray ());}
As can be seen from the above code, the dotnet Run command actually executes the RunCommand run () method, moving forward along the run () method, from the Start () method to the Runexecutable () method, where the scenery attracts us.
In the Runexecutable () method, the Buildcommand.run () method is executed first-build the. NET Core Application:
var result = Build.BuildCommand.Run (new []{$ " , $ " {_context. targetframework} , $ " --configuration " , Configuration, $ {_context. Projectfile.projectdirectory}
If build succeeds, the appropriate assembly (. dll file) is generated in the Bin folder of the. NET Core application. How to build is not the concern of our journey, but what we care about is how the build-out assembly is run.
So skip the landscape here and go ahead and discover the following code:
result = Command.create (outputname, _args) . Forwardstdout () . Forwardstderr () . Execute () . ExitCode;
From the code above, it can be analyzed that dotnet run finally executes a command line, which is generated by Command.create () based on Outputname, and Outputname is the assembly name of the application generated by Buildcommand. Clearly, the secret must be hidden in the command.create ().
Target Command.create (), running forward ... See the Command.create () in the Command.cs:
Public StaticCommand Create (stringCommandName, IEnumerable<string>args, nugetframework framework=NULL, stringConfiguration =constants.defaultconfiguration) { varCommandspec = commandresolver.tryresolvecommandspec(commandName, args, framework, CONFIGURATION:C onfiguration); if(Commandspec = =NULL) { Throw Newcommandunknownexception (commandName); } varCommand =NewCommand (COMMANDSPEC); returncommand;}
Discover Commandresolver, trot into Commandresolver.tryresolvecommandspec (), and see what the landscape is like:
Public StaticCommandspec Tryresolvecommandspec (stringCommandName, IEnumerable<string>args, nugetframework framework=NULL, stringconfiguration=Constants.defaultconfiguration,stringOutputpath=NULL){ varCommandresolverargs =Newcommandresolverarguments {CommandName=CommandName, Commandarguments=args, Framework=Framework, Projectdirectory=directory.getcurrentdirectory (), Configuration=configuration, OutputPath=OutputPath}; varDefaultcommandresolver = defaultcommandresolverpolicy.create(); returndefaultcommandresolver.resolve (Commandresolverargs);}
Discover Defaultcommandresolverpolicy, fearlessly, in its Create () method:
Public Staticcompositecommandresolver Create () {varEnvironment =NewEnvironmentprovider (); varPackagedcommandspecfactory =New packagedcommandspecfactory(); varPlatformcommandspecfactory =default(iplatformcommandspecfactory); if(PlatformServices.Default.Runtime.OperatingSystemPlatform = =platform.windows) {platformcommandspecfactory=Newwindowsexepreferredcommandspecfactory (); } Else{platformcommandspecfactory=Newgenericplatformcommandspecfactory (); } return createdefaultcommandresolver(Environment, Packagedcommandspecfactory, platformcommandspecfactory);}
There are two landscapes--packagedcommandspecfactory and Platformcommandspecfactory, both of which are passed as parameters to the Createdefaultcommandresolver () method.
The heart is not two, first look at one of the scenery--packagedcommandspecfactory, impatient to rush to Createdefaultcommandresolver () method.
Public Staticcompositecommandresolver createdefaultcommandresolver (ienvironmentprovider environment, IPackagedCommandSpecF Actory packagedcommandspecfactory, Iplatformcommandspecfactory platformcommandspecfactory) {varCompositecommandresolver =NewCompositecommandresolver (); //..Compositecommandresolver.addcommandresolver (New projecttoolscommandresolver(packagedcommandspecfactory)); //.. returnCompositecommandresolver;}
Packagedcommandspecfactory leads us to a new landscape--projecttoolscommandresolver. After the gallop, the Resolve () method is immediately attracted (after the previous defaultcommandresolverpolicy.create () execution, the Defaultcommandresolver.resolve ( Commandresolverargs), the method is called).
The scenery here is 18 bends. In Projecttoolscommandresolver seven around eight, from Resolvefromprojecttools (), Resolvecommandspecfromalltoollibraries () Resolvecommandspecfromtoollibrary () ... Back to the packagedcommandspecfactory and into the Createcommandspecfromlibrary () method.
Continue to wander in the Packagedcommandspecfactory, from Createcommandspecwrappingwithcorehostfdll () to Createpackagecommandspecusingcorehost (), found a new East Sky--corehost:
PrivateCommandspec Createpackagecommandspecusingcorehost (stringCommandpath, IEnumerable<string>commandarguments,stringDepsfilepath, Commandresolutionstrategy commandresolutionstrategy) { var corehost = Corehost.hostexepath; vararguments =Newlist<string>(); Arguments. ADD (Commandpath); if(Depsfilepath! =NULL) {arguments. ADD ($"--depsfile:{depsfilepath}"); } arguments. AddRange (commandarguments); returnCreatecommandspec (corehost, arguments, commandresolutionstrategy);}
What's the corehost variable here? There was a big question mark in the heart.
Looking behind the Corehost, found the Createcommandspec () method (Corehost is one of its parameters), all the way to the past:
Private commandspec createcommandspec ( string commandpath, IEnumerable<string > commandarguments, commandresolutionstrategy commandresolutionstrategy) { var Escapedargs = Argumentescaper.escapeandconcatenateargarrayforprocessstart (commandarguments); return New Commandspec (Commandpath, Escapedargs, commandresolutionstrategy);}
The original corehost is the value of Commandpath, that is, Command.create () created by the dotnet run the corresponding command line is Corehost beginning, the secret must be in the front of the corehost not far away.
The value of Corehost is from Corehost.hostexepath, the value of Hostexepath is from Constants.hostexecutablename, and the value of Hostexecutablename is:
Public Static ReadOnly string " Corehost " + exesuffix;
Corehost Command! The dotnet Run command eventually executes the corehost command, Corehost is the real protagonist behind it, and the. NET Core application is run by it.
Go to dotnet installation directory of the CLI look, sure enough there is a corehost executable file.
1 31208 Mar 2:/usr/share/dotnet-nightly/bin/corehost
Since Corehost is the protagonist, then not through dotnet run, directly with Corehost should also be able to run the. NET Core program, let's try it.
Enter the build output folder for the sample site about.cnblogs.com:
Cd/git/aboutus/bin/debug/netstandardapp1.3/ubuntu.14.04-x64
Then run the assembly directly with the Corehost command:
/usr/share/dotnet-nightly/bin/corehost AboutUs.dll
Run successfully! It turns out that Corehost is the protagonist running the. NET Core program.
DBUG:MICROSOFT.ASPNETCORE.HOSTING.INTERNAL.WEBHOST[3] Hosting startingdbug: MICROSOFT.ASPNETCORE.HOSTING.INTERNAL.WEBHOST[4] Hosting startedhosting environment:productionapplication Base path:/git/aboutus/bin/debug/netstandardapp1.3/ubuntu.14.04-x64now listening on:http://*:8001application Started. Press CTRL + C to shut down.
Go to dotnet CLI source code to see the implementation of Corehost, is written in C + +, which is the only part of the dotnet CLI implemented in C + +, it also has to use C + +, because it has an important responsibility-loading CORECLR, once again confirmed Cor Ehost is the protagonist.
Quest Dotnet Run, pale, through the mountains, finally found you--corehost, finally satisfied the restless curiosity.
. NET Cross-platform tour: Discover how dotnet Run runs the. NET Core Application