一个全面的.NET应用程序自动化打包解决方案,支持多种项目类型和版本管理
在现代.NET开发中,应用程序的打包和分发是开发流程中不可或缺的一环。本文将详细介绍一个通用的.NET应用程序打包工具,该工具能够自动化处理从项目分析到安装包生成的完整流程。
根据Microsoft官方支持政策,该打包工具支持以下.NET版本:
版本类型 | 版本号 | 支持状态 | 结束支持日期 | 推荐使用 |
---|---|---|---|---|
.NET 8 | 8.0.x | LTS (长期支持) | 2026年11月 | ⭐ 强烈推荐 |
.NET 9 | 9.0.x | STS (标准支持) | 2026年5月 | ✅ 推荐 |
.NET 6 | 6.0.x | 已结束支持 | 2024年11月 | ❌ 不推荐 |
注意:EOL (End of Life) 版本不再接收安全更新,建议尽快升级到支持版本。
前置准备
InnoSetup工具(点击直达)
Windows批处理文件(原文件地址点击直达)或者直接在本文相关资源中下载
使用方法
将innoset安装到默认目录后,将bat文件放置在和csproj文件放置在同一目录双击打开
示例演示
输出文件结构
您的项目目录/
├── publish/
│ └── standalone/ # 自包含发布文件
│ ├── YourApp.exe # 主程序
│ ├── YourApp.dll # 程序集
│ └── … # 运行时文件
├── installer/
│ └── YourApp-Setup-v1.2.3.exe # 最终安装程序
├── YourApp-installer-v1.2.3-ultimate.iss # 终极兼容脚本
└── .version-history.txt # 版本历史记录
要使用该打包工具,您的.csproj
文件需要包含特定的配置项。以下是一个完整的配置示例:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExeOutputType>
<TargetFramework>net8.0-windowsTargetFramework>
<UseWPF>trueUseWPF>
<Version>1.2.3Version>
<AssemblyVersion>1.2.3.0AssemblyVersion>
<FileVersion>1.2.3.0FileVersion>
<AssemblyName>MyApplicationAssemblyName>
<Product>My Amazing AppProduct>
<Company>My CompanyCompany>
<Copyright>Copyright © 2025 My CompanyCopyright>
<Description>这是一个演示应用程序Description>
<PublishSingleFile>truePublishSingleFile>
<SelfContained>trueSelfContained>
<RuntimeIdentifier>win-x64RuntimeIdentifier>
<PublishTrimmed>falsePublishTrimmed>
<PublishReadyToRun>truePublishReadyToRun>
PropertyGroup>
<PropertyGroup>
<ApplicationIcon>app.icoApplicationIcon>
PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsDesktop.App" />
ItemGroup>
Project>
<PropertyGroup>
<OutputType>WinExeOutputType>
<TargetFramework>net8.0-windowsTargetFramework>
<UseWPF>trueUseWPF>
<Version>1.0.0Version>
PropertyGroup>
<PropertyGroup>
<OutputType>WinExeOutputType>
<TargetFramework>net8.0-windowsTargetFramework>
<UseWindowsForms>trueUseWindowsForms>
<Version>1.0.0Version>
PropertyGroup>
<PropertyGroup>
<OutputType>ExeOutputType>
<TargetFramework>net8.0TargetFramework>
<Version>1.0.0Version>
PropertyGroup>
该工具遵循语义化版本控制规范:
主版本号.次版本号.修订号[-预发布标识符][+构建元数据]
工具使用PowerShell脚本来解析项目文件:
// C# 等效代码示例 - 项目信息提取
using System;
using System.Xml;
using System.IO;
public class ProjectAnalyzer
{
///
/// 从.csproj文件中提取项目信息
///
/// 项目文件路径
/// 项目信息对象
public static ProjectInfo ExtractProjectInfo(string projectFilePath)
{
var projectInfo = new ProjectInfo();
try
{
// 加载XML文档
var xmlDoc = new XmlDocument();
xmlDoc.Load(projectFilePath);
// 查找PropertyGroup节点
var propertyGroups = xmlDoc.SelectNodes("//PropertyGroup");
foreach (XmlNode propertyGroup in propertyGroups)
{
// 提取版本信息
var versionNode = propertyGroup.SelectSingleNode("Version");
if (versionNode != null)
{
projectInfo.Version = versionNode.InnerText;
}
// 提取程序集名称
var assemblyNameNode = propertyGroup.SelectSingleNode("AssemblyName");
if (assemblyNameNode != null)
{
projectInfo.AssemblyName = assemblyNameNode.InnerText;
}
// 提取目标框架
var targetFrameworkNode = propertyGroup.SelectSingleNode("TargetFramework");
if (targetFrameworkNode != null)
{
projectInfo.TargetFramework = targetFrameworkNode.InnerText;
}
// 判断项目类型
var useWpfNode = propertyGroup.SelectSingleNode("UseWPF");
var useWinFormsNode = propertyGroup.SelectSingleNode("UseWindowsForms");
var outputTypeNode = propertyGroup.SelectSingleNode("OutputType");
if (useWpfNode?.InnerText.ToLower() == "true")
{
projectInfo.ProjectType = ProjectType.WPF;
}
else if (useWinFormsNode?.InnerText.ToLower() == "true")
{
projectInfo.ProjectType = ProjectType.WinForms;
}
else if (outputTypeNode?.InnerText == "Exe")
{
projectInfo.ProjectType = ProjectType.Console;
}
else if (outputTypeNode?.InnerText == "WinExe")
{
projectInfo.ProjectType = ProjectType.Desktop;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"解析项目文件失败: {ex.Message}");
projectInfo.HasError = true;
}
return projectInfo;
}
}
///
/// 项目信息数据类
///
public class ProjectInfo
{
public string Version { get; set; } = "1.0.0";
public string AssemblyName { get; set; } = "";
public string TargetFramework { get; set; } = "net8.0";
public ProjectType ProjectType { get; set; } = ProjectType.Unknown;
public bool HasError { get; set; } = false;
}
///
/// 项目类型枚举
///
public enum ProjectType
{
Unknown,
WPF,
WinForms,
Console,
Desktop
}
工具会创建一个.version-history.txt
文件来跟踪版本变更:
LAST_VERSION=1.2.3
LAST_BUILD=2024-01-15 14:30:25
PROJECT_TYPE=WPF
自包含应用程序(Self-Contained Application)是包含.NET运行时的应用程序部署方式。这意味着:
工具使用以下dotnet publish命令:
dotnet publish "项目文件.csproj" \
-c Release \ # 发布配置:Release模式
-r win-x64 \ # 运行时标识符:Windows 64位
--self-contained true \ # 自包含:包含.NET运行时
-p:PublishSingleFile=true \ # 单文件发布:合并为单个可执行文件
-p:PublishTrimmed=false \ # 裁剪:不进行代码裁剪以保证兼容性
-o "publish\standalone" # 输出目录:指定发布路径
<PropertyGroup>
<PublishReadyToRun>truePublishReadyToRun>
PropertyGroup>
<PropertyGroup>
<PublishTrimmed>truePublishTrimmed>
<TrimMode>linkTrimMode>
PropertyGroup>
工具自动生成兼容所有Inno Setup版本的安装脚本:
; 自动生成的安装脚本 (终极兼容版)
; 项目: MyApp (WPF 应用程序)
; 版本: 1.2.3
#define MyAppName "MyApp"
#define MyAppVersion "1.2.3"
#define MyAppPublisher "本地开发者"
#define MyAppURL "https://github.com/example"
#define MyAppExeName "MyApp.exe"
[Setup]
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputDir=installer
OutputBaseFilename={#MyAppName}-Setup-v{#MyAppVersion}
Compression=lzma
SolidCompression=yes
PrivilegesRequired=lowest
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
MinVersion=6.1
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "创建桌面快捷方式"
Name: "startmenu"; Description: "添加到开始菜单"
[Files]
Source: "publish\standalone\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
Source: ".version-history.txt"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\卸载 {#MyAppName}"; Filename: "{uninstallexe}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "启动应用程序"; Flags: nowait postinstall
// MainWindow.xaml.cs - 示例WPF应用程序
using System.Windows;
namespace MyWpfApp
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// 设置窗口标题为程序版本
this.Title = $"我的WPF应用 v{GetApplicationVersion()}";
}
///
/// 获取应用程序版本号
///
/// 版本号字符串
private string GetApplicationVersion()
{
// 从程序集中获取版本信息
var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
return $"{version.Major}.{version.Minor}.{version.Build}";
}
///
/// 按钮点击事件处理
///
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello from packaged WPF app!", "消息",
MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}
对应的.csproj
文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExeOutputType>
<TargetFramework>net8.0-windowsTargetFramework>
<UseWPF>trueUseWPF>
<Version>1.2.3Version>
<AssemblyName>MyWpfAppAssemblyName>
<ApplicationIcon>app.icoApplicationIcon>
PropertyGroup>
Project>
// Program.cs - 示例控制台应用程序
using System;
using System.Threading.Tasks;
namespace MyConsoleApp
{
class Program
{
///
/// 程序入口点
///
/// 命令行参数
static async Task Main(string[] args)
{
// 显示欢迎信息
Console.WriteLine("=================================");
Console.WriteLine($"我的控制台应用 v{GetVersion()}");
Console.WriteLine("=================================");
Console.WriteLine();
try
{
// 模拟一些工作
await DoSomeWorkAsync();
Console.WriteLine("✅ 任务完成!");
}
catch (Exception ex)
{
Console.WriteLine($"❌ 发生错误: {ex.Message}");
}
Console.WriteLine("\n按任意键退出...");
Console.ReadKey();
}
///
/// 获取应用程序版本
///
/// 版本字符串
private static string GetVersion()
{
var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
return $"{version.Major}.{version.Minor}.{version.Build}";
}
///
/// 模拟异步工作
///
private static async Task DoSomeWorkAsync()
{
Console.WriteLine("正在处理数据...");
// 模拟耗时操作
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"进度: {i}/5");
await Task.Delay(500); // 等待500毫秒
}
}
}
}
症状:Inno Setup编译失败,出现语法错误
解决方案:
症状:工具无法正确识别项目版本
解决方案:
<PropertyGroup>
<Version>1.0.0Version>
PropertyGroup>
症状:生成的安装包文件过大
解决方案:
<PropertyGroup>
<PublishTrimmed>truePublishTrimmed>
<TrimMode>linkTrimMode>
PropertyGroup>
症状:发布后找不到.exe文件
解决方案:
AssemblyName
属性OutputType
设置正确<PropertyGroup>
<PublishReadyToRun>truePublishReadyToRun>
<PublishSingleFile>truePublishSingleFile>
<TieredCompilation>trueTieredCompilation>
PropertyGroup>
<PropertyGroup>
<PublishTrimmed>truePublishTrimmed>
<InvariantGlobalization>trueInvariantGlobalization>
<DebugType>noneDebugType>
<DebugSymbols>falseDebugSymbols>
PropertyGroup>
本文最后更新时间:2025年6月