能否用C#程序化生成.NET Core AppHost以运行自定义带入口点的DLL?
问题背景与提问
从.NET Core开始,构建C#可执行项目(如控制台应用、Windows Forms、WPF等桌面应用)时,生成的文件不止一个.exe——实际IL代码存储在DLL文件中,.exe是用于定位.NET运行时并加载该DLL的非托管存根(即AppHost),此外还有.deps.json和.runtimeconfig.json等配套文件。生成文件示例:
ConsoleApp1.deps.json - 依赖配置文件 ConsoleApp1.dll - 存储IL代码的核心文件 ConsoleApp1.exe - 非托管存根(AppHost) ConsoleApp1.pdb - 程序调试数据库(包含变量名等调试信息) ConsoleApp1.runtimeconfig.json - .NET运行时配置文件
现有需求:我通过Mono.Cecil生成了一个包含IL代码及入口点的DLL文件,需要上述的非托管存根.exe来运行这个DLL。请问能否通过C#程序化生成这类作为.NET存根的非托管可执行文件(AppHost),用于自行生成的带IL代码的DLL?
可行方案
当然可以,以下是几种实用的程序化实现方式:
1. 复制并修改.NET SDK内置的AppHost模板
.NET SDK安装目录中自带了不同架构(x86、x64、arm64)的AppHost模板文件(通常命名为apphost.exe)。操作步骤:
- 找到对应架构的模板文件路径,例如x64架构的路径可能是:
C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\<版本号>\runtimes\win-x64\native\apphost.exe - 用C#代码复制该模板文件到目标路径,重命名为你需要的文件名
- 修改文件内部的嵌入资源:模板中默认嵌入了
apphost.dll字符串,这是AppHost要加载的DLL名称。你可以通过文件流操作找到该字符串,替换为你的目标DLL文件名(注意保持字符串长度一致,可用填充符补全,避免破坏文件结构)
2. 程序化调用dotnet publish生成临时存根
通过启动进程调用dotnet publish命令,基于临时空项目生成AppHost,再提取使用:
- 创建临时控制台项目目录,包含最基础的
.csproj文件(指定目标框架、输出类型等) - 执行命令:
dotnet publish -r <目标运行时架构> --self-contained false,例如dotnet publish -r win-x64 --self-contained false - 从输出目录复制生成的
exe文件,修改其嵌入的DLL名称为你的目标DLL - 清理临时项目文件
3. 使用Microsoft.NET.HostModel NuGet包(推荐)
这个包是.NET SDK内部用于处理AppHost的工具库,可直接用于程序化生成:
- 安装
Microsoft.NET.HostModelNuGet包 - 使用
AppHost.Patch方法完成模板修补,示例代码:
using Microsoft.NET.HostModel.AppHost; // 替换为实际的模板路径、目标输出路径和DLL名称 string appHostTemplatePath = @"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\8.0.0\runtimes\win-x64\native\apphost.exe"; string targetExePath = @"MyCustomStub.exe"; string targetDllName = @"MyGenerated.dll"; // 自动修补模板,替换目标DLL名称 AppHost.Patch(appHostTemplatePath, targetExePath, targetDllName);
该方法会自动处理嵌入字符串的替换,无需手动操作文件流,是最简便的实现方式。
注意事项
- 确保AppHost模板的架构与目标DLL的运行架构一致(x86/x64/arm64)
- 除了AppHost的
exe文件,还需要为目标DLL生成对应的.runtimeconfig.json文件(可手动构建或代码生成,指定.NET运行时版本等信息),否则存根无法正确加载.NET运行时
内容的提问来源于stack exchange,提问作者winscripter
相关产品推荐
相关产品推荐

