是的,您可以将dotnet Windows应用程序压缩成单个.exe文件。
只需按照以下步骤操作:
ILMerge 可以将程序集合并为一个单一的程序集,前提是该程序集仅包含托管代码。您可以使用命令行应用程序或添加对 EXE 文件的引用并以编程方式进行合并。对于 GUI 版本,有 Eazfuscator 和 .Netz,两者都是免费的。付费应用程序包括 BoxedApp 和 SmartAssembly。
如果您需要合并带有非托管代码的程序集,我建议使用SmartAssembly。我从未在SmartAssembly中遇到过任何问题,但在其他所有工具中都遇到了问题。在这里,它可以将所需的依赖项作为资源嵌入到您的主EXE文件中。
您可以手动完成所有这些操作,无需担心程序集是托管的还是混合模式的,只需将DLL文件嵌入到您的资源中,然后依靠AppDomain的Assembly ResolveHandler
。这是一种一站式解决方案,适用于最坏情况,即带有非托管代码的程序集。
class Program
{
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName.EndsWith(".resources"))
return null;
string dllName = assemblyName + ".dll";
string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
{
byte[] data = new byte[stream.Length];
s.Read(data, 0, data.Length);
// Or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);
File.WriteAllBytes(dllFullPath, data);
}
return Assembly.LoadFrom(dllFullPath);
};
}
}
其中Program
是类名。关键在于将字节写入文件并从其位置加载。为避免鸡生蛋问题,您必须确保在访问程序集之前声明处理程序,并且在加载(程序集解析)部分内不访问程序集成员(或实例化任何与程序集有关的内容)。还要注意确保GetMyApplicationSpecificPath()
不是任何临时目录,因为其他程序或您自己可能会尝试删除临时文件(虽然在程序访问DLL文件时它不会被删除,但至少这是一个麻烦。AppData是一个好的位置)。还要注意,您每次都必须写入字节;不能仅因为DLL文件已经驻留在那里就从位置加载。
对于托管的DLL文件,您无需编写字节,而是直接从DLL文件的位置加载,或者只需读取字节并从内存加载程序集。像这样:
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
{
byte[] data = new byte[stream.Length];
s.Read(data, 0, data.Length);
return Assembly.Load(data);
}
// Or just
return Assembly.LoadFrom(dllFullPath); // If location is known.
VS2022 .net 6.0。
在 PS1 文件中使用此命令(例如,将文件命名为 publishSingleFile.ps1):
$startFolder = $PSScriptRoot
$container = $startFolder + "/SingleFileExe"
dotnet publish --runtime win-x86 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true --output $container
然后将文件放置在与您的projectName.sln文件相同的文件夹中。右键单击ps1文件,选择“使用powershell运行”(如果不可用,则必须先在Windows上启用powershell),这将在项目内创建一个名为“SingleFileExe”的文件夹,并将您的单个文件放置其中。
您可以删除projectName.xml和projectName.pdb文件。然后您将拥有包含所有内容的projectName.exe文件。
干杯。