.NET Core publish static single-file compilation AOT CoreRT, the .NET Core applications packaged into a single executable file and contains the runtime.
Support Windows, MacOS and Linux x64 w / RyuJIT codegen.
Sample project:
https://github.com/dotnet/corert/tree/master/samples/WebApi
Let's actual experience.
First make sure to install the C ++ compiler environment, as well as .NET Core 2.0 or later SDK.
New applications WebAPI
Open a command prompt, type the following:
dotnet new webapi -o zeroapi
cd zeroapi
New WebAPI application.
Adding to the project CoreRT
Currently CoreRT still alpha version, has a bag on myget.
Start by adding a nuget.config
dotnet new nuggets
Then <packageSources> node add the following:
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
Then add Microsoft.DotNet.ILCompiler package references:
dotnet add package Microsoft.DotNet.ILCompiler -v 1.0.0-alpha-*
Services and processes to replace the default reflection
Open Startup.cs, the services.AddMvc (); replace services.AddMvcCore () AddJsonFormatters ().;
Rd.xml then creates a profile for the run-time reflection treatment, the reflection assembly to ensure compiled into the program.
rd.xml configuration file as follows:
<Directives> <Application> <Assembly Name="zeroapi" Dynamic="Required All" /> <Assembly Name="Microsoft.AspNetCore.Server.Kestrel.Core"> <Type Name="Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Server.Kestrel.Core.Internal.KestrelServerOptionsSetup" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Server.Kestrel" Dynamic="Required All"/> <Assembly Name="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"> <Type Name="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportFactory" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.DependencyInjection" Dynamic="Required All"> <Type Name="Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteExpressionBuilder" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Options"> <Type Name="Microsoft.Extensions.Options.OptionsManager`1[[Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions,Microsoft.AspNetCore.Server.Kestrel.Core]]" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.Options.OptionsFactory`1[[Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions,Microsoft.AspNetCore.Server.Kestrel.Core]]" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.Options.OptionsMonitor`1[[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions,Microsoft.Extensions.Logging.Console]]" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Mvc.Core" Dynamic="Required All" /> <Assembly Name="Microsoft.AspNetCore.Routing"> <Type Name="Microsoft.AspNetCore.Routing.Internal.RoutingMarkerService" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Builder.RouterMiddleware" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Routing.Tree.TreeRouteBuilder" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Routing.DefaultInlineConstraintResolver" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Routing.RouteOptions" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Mvc.Formatters.Json"> <Type Name="Microsoft.AspNetCore.Mvc.Formatters.Json.Internal.MvcJsonMvcOptionsSetup" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Mvc.MvcJsonOptions" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Authorization"> <Type Name="Microsoft.AspNetCore.Authorization.DefaultAuthorizationPolicyProvider" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Authorization.AuthorizationOptions" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Http"> <Type Name="Microsoft.AspNetCore.Http.HttpContextFactory" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Hosting" Dynamic="Required All"> <Type Name="Microsoft.AspNetCore.Hosting.Internal.ApplicationLifetime" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Logging.Abstractions"> <Type Name="Microsoft.Extensions.Logging.Logger`1[[Microsoft.AspNetCore.Hosting.Internal.WebHost,Microsoft.AspNetCore.Hosting]]" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Logging"> <Type Name="Microsoft.Extensions.Logging.LoggerFactory" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Logging.Console"> <Type Name="Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Logging.Debug"> <Type Name="Microsoft.Extensions.Logging.Debug.DebugLogger" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.Logging.Debug.DebugLoggerProvider" Dynamic="Required All" /> </Assembly> <Assembly Name="System.Linq.Expressions"> <Type Name="System.Linq.Expressions.ExpressionCreator`1[[Newtonsoft.Json.Serialization.ObjectConstructor`1[[System.Object,System.Private.CoreLib]],Newtonsoft.Json]]" Dynamic="Required All" /> <Type Name="System.Linq.Expressions.ExpressionCreator`1[[System.Func`2[[System.Object,System.Private.CoreLib],[System.Object,System.Private.CoreLib]],System.Private.CoreLib]]" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.ObjectPool"> <Type Name="Microsoft.Extensions.ObjectPool.DefaultObjectPoolProvider" Dynamic="Required All" /> </Assembly> <Assembly Name="Newtonsoft.Json"> <Type Name="Newtonsoft.Json.Serialization.ObjectConstructor`1[[System.Object,System.Private.CoreLib]]" Dynamic="Required All" /> </Assembly> <Assembly Name="System.ComponentModel.TypeConverter"> <Type Name="System.ComponentModel.TypeConverter" Dynamic="Required All" /> <Type Name="System.ComponentModel.StringConverter" Dynamic="Required All" /> <Type Name="System.ComponentModel.Int32Converter" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Configuration.Json"> <Type Name="Microsoft.Extensions.Configuration.Json.JsonConfigurationSource" Dynamic="Required All" /> </Assembly> </Application> </Directives>
If you where to be replaced with their own procedures, change < Assembly the Name = "zeroapi " Dynamic = "All the Required " /> in the Name.
Open zeroapi.csproj
The <at <PropertyGroup> node RdXmlFile> rd.xml </ RdXmlFile> was added.
Then <PackageReference Include = "Microsoft.AspNetCore.All" Version = "2.0.3" /> replaced with the following:
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.1" /><PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.1" /><PackageReference Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="2.0.1" />
Then ValuesController changes to make sure that the normal function, as follows:
public class ValuesController { [HttpGet("/")] public string Hello() => "Hello World! LineZero AOT"; // GET api/values [HttpGet("/api/values")] public IEnumerable<string> Get() { return new string[] { "AOT", "CoreRT" }; } // GET api/values/5 [HttpGet("/api/values/{id}")] public string Get(int id) { return "Your value is " + id; } }
Program transformation is complete, then the most important release.
Restore and publish
Before publishing, make sure to use dotnet run function properly.
Open publishing x64 Native Tools for VS 2017 the Command Prompt , attention must be released in the command line. Find Visual Studio 2017 in the Start menu, open the find.
Issued an order or publish -r DOTNET <RID > -c <the Configuration >
Here released Windows 64-bit dotnet publish -r win-x64 -c release, for the first time, then by default the corresponding reduction package, take some time.
After publishing is complete, open the bin \ x64 \ release \ netcoreapp2.0 \ win-x64 \ publish folder, which shall be final zeroapi.exe file, you can execute.
We can see the final size of about 21m. Then visit http: // localhost: 5000 / Figure:
Console Demo
Create a new console application, using AOT release.
Simple console, there is no reflection of the content, no need rd.xml file.
code show as below:
class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.WriteLine("LineZero AOT Demo!"); Console.ReadKey(); } }
最终 dotnet publish -r win-x64 -c release 发布
最终单个文件大小不到4m!
目前该技术还是早期版本,期待微软最终带到正式版。
GitHub:https://github.com/dotnet/corert
.NET Core单文件发布静态编译AOT CoreRT,将.NET Core应用打包成一个可执行文件并包含运行时。
支持Windows, MacOS and Linux x64 w/ RyuJIT codegen。
示例项目:
https://github.com/dotnet/corert/tree/master/samples/WebApi
下面来实际体验。
首先确保安装C++编译环境,以及.NET Core 2.0 以上版本SDK。
新建WebAPI应用
打开命令提示符,输入如下:
dotnet new webapi -o zeroapi
cd zeroapi
新建WebAPI应用。
添加CoreRT到项目
目前CoreRT还是alpha版,在myget上有包。
首先添加一个nuget.config
dotnet new nuget
然后在 <packageSources> 节点添加如下:
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
接着添加Microsoft.DotNet.ILCompiler包引用:
dotnet add package Microsoft.DotNet.ILCompiler -v 1.0.0-alpha-*
替换默认services并处理反射
打开Startup.cs ,将 services.AddMvc(); 替换成 services.AddMvcCore().AddJsonFormatters();
接着创建一个rd.xml 配置文件,用于反射处理运行时,确保反射程序集编译到程序中。
rd.xml配置文件如下:
<Directives> <Application> <Assembly Name="zeroapi" Dynamic="Required All" /> <Assembly Name="Microsoft.AspNetCore.Server.Kestrel.Core"> <Type Name="Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Server.Kestrel.Core.Internal.KestrelServerOptionsSetup" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Server.Kestrel" Dynamic="Required All"/> <Assembly Name="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"> <Type Name="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportFactory" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.DependencyInjection" Dynamic="Required All"> <Type Name="Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteExpressionBuilder" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Options"> <Type Name="Microsoft.Extensions.Options.OptionsManager`1[[Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions,Microsoft.AspNetCore.Server.Kestrel.Core]]" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.Options.OptionsFactory`1[[Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions,Microsoft.AspNetCore.Server.Kestrel.Core]]" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.Options.OptionsMonitor`1[[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions,Microsoft.Extensions.Logging.Console]]" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Mvc.Core" Dynamic="Required All" /> <Assembly Name="Microsoft.AspNetCore.Routing"> <Type Name="Microsoft.AspNetCore.Routing.Internal.RoutingMarkerService" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Builder.RouterMiddleware" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Routing.Tree.TreeRouteBuilder" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Routing.DefaultInlineConstraintResolver" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Routing.RouteOptions" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Mvc.Formatters.Json"> <Type Name="Microsoft.AspNetCore.Mvc.Formatters.Json.Internal.MvcJsonMvcOptionsSetup" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Mvc.MvcJsonOptions" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Authorization"> <Type Name="Microsoft.AspNetCore.Authorization.DefaultAuthorizationPolicyProvider" Dynamic="Required All" /> <Type Name="Microsoft.AspNetCore.Authorization.AuthorizationOptions" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Http"> <Type Name="Microsoft.AspNetCore.Http.HttpContextFactory" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.AspNetCore.Hosting" Dynamic="Required All"> <Type Name="Microsoft.AspNetCore.Hosting.Internal.ApplicationLifetime" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Logging.Abstractions"> <Type Name="Microsoft.Extensions.Logging.Logger`1[[Microsoft.AspNetCore.Hosting.Internal.WebHost,Microsoft.AspNetCore.Hosting]]" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Logging"> <Type Name="Microsoft.Extensions.Logging.LoggerFactory" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Logging.Console"> <Type Name="Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Logging.Debug"> <Type Name="Microsoft.Extensions.Logging.Debug.DebugLogger" Dynamic="Required All" /> <Type Name="Microsoft.Extensions.Logging.Debug.DebugLoggerProvider" Dynamic="Required All" /> </Assembly> <Assembly Name="System.Linq.Expressions"> <Type Name="System.Linq.Expressions.ExpressionCreator`1[[Newtonsoft.Json.Serialization.ObjectConstructor`1[[System.Object,System.Private.CoreLib]],Newtonsoft.Json]]" Dynamic="Required All" /> <Type Name="System.Linq.Expressions.ExpressionCreator`1[[System.Func`2[[System.Object,System.Private.CoreLib],[System.Object,System.Private.CoreLib]],System.Private.CoreLib]]" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.ObjectPool"> <Type Name="Microsoft.Extensions.ObjectPool.DefaultObjectPoolProvider" Dynamic="Required All" /> </Assembly> <Assembly Name="Newtonsoft.Json"> <Type Name="Newtonsoft.Json.Serialization.ObjectConstructor`1[[System.Object,System.Private.CoreLib]]" Dynamic="Required All" /> </Assembly> <Assembly Name="System.ComponentModel.TypeConverter"> <Type Name="System.ComponentModel.TypeConverter" Dynamic="Required All" /> <Type Name="System.ComponentModel.StringConverter" Dynamic="Required All" /> <Type Name="System.ComponentModel.Int32Converter" Dynamic="Required All" /> </Assembly> <Assembly Name="Microsoft.Extensions.Configuration.Json"> <Type Name="Microsoft.Extensions.Configuration.Json.JsonConfigurationSource" Dynamic="Required All" /> </Assembly> </Application> </Directives>
其中如果你要替换成自己的程序,更改 <Assembly Name="zeroapi" Dynamic="Required All" /> 中的Name。
打开zeroapi.csproj
在<PropertyGroup>节点下将 <RdXmlFile>rd.xml</RdXmlFile> 加入。
接着将 <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" /> 替换成如下:
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.1" /><PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.1" /><PackageReference Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="2.0.1" />
接着将 ValuesController 更改一下,确保功能正常,如下:
public class ValuesController { [HttpGet("/")] public string Hello() => "Hello World! LineZero AOT"; // GET api/values [HttpGet("/api/values")] public IEnumerable<string> Get() { return new string[] { "AOT", "CoreRT" }; } // GET api/values/5 [HttpGet("/api/values/{id}")] public string Get(int id) { return "Your value is " + id; } }
程序改造完成,接着最重要的发布。
还原并发布
发布之前,使用dotnet run 确保功能正常运行。
发布请打开 x64 Native Tools Command Prompt for VS 2017 ,注意一定在此命令行发布。在开始菜单找到 Visual Studio 2017,打开就能找到。
发布命令还是 dotnet publish -r <RID> -c <Configuration>
这里发布Windows 64位 dotnet publish -r win-x64 -c release,初次的话会默认还原对应的包,需要一些时间。
发布完成后,打开bin\x64\release\netcoreapp2.0\win-x64\publish 文件夹,里面zeroapi.exe即为最终文件,执行即可。
可以看到最终大小为21m左右。然后访问http://localhost:5000/ 如图:
控制台Demo
新建一个控制台应用,使用AOT发布。
单纯控制台,没有反射的内容,无需要rd.xml 文件。
代码如下:
class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.WriteLine("LineZero AOT Demo!"); Console.ReadKey(); } }
The final dotnet publish -r win-x64 -c release issued
The final single file size is less than 4m!
Currently the technology is still in earlier versions, Microsoft finally look forward to the official version.
GitHub:https://github.com/dotnet/corert