dotnet-clickonce-config dotnet-clickonce-config

这是一个用于配置.NET应用程序ClickOnce部署的专业技能,支持自动更新、先决条件管理、发布设置等功能。关键词:ClickOnce部署、.NET应用程序、自动更新、Windows桌面应用、发布配置、证书签名、部署清单、应用程序更新、先决条件管理、文件关联设置。

DevOps 0 次安装 0 次浏览 更新于 2/24/2026

name: dotnet-clickonce-config description: 为.NET应用程序配置具有自动更新、先决条件管理和发布设置的ClickOnce部署 allowed-tools: Read, Write, Edit, Bash, Glob, Grep tags: [dotnet, clickonce, deployment, auto-update, windows]

dotnet-clickonce-config

为.NET应用程序配置具有自动更新能力、先决条件管理和发布设置的ClickOnce部署。此技能设置完整的ClickOnce部署流水线。

能力

  • 配置ClickOnce发布设置
  • 设置自动更新检查
  • 管理应用程序先决条件
  • 配置文件关联
  • 设置证书签名
  • 生成发布配置文件
  • 配置部署清单
  • 设置Web或文件共享部署

输入模式

{
  "type": "object",
  "properties": {
    "projectPath": {
      "type": "string",
      "description": ".NET项目路径"
    },
    "publishSettings": {
      "type": "object",
      "properties": {
        "publishUrl": { "type": "string" },
        "installUrl": { "type": "string" },
        "updateMode": { "enum": ["foreground", "background"] },
        "updateInterval": { "type": "number" },
        "minimumVersion": { "type": "string" }
      }
    },
    "prerequisites": {
      "type": "array",
      "items": { "type": "string" }
    },
    "fileAssociations": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "extension": { "type": "string" },
          "description": { "type": "string" }
        }
      }
    },
    "signing": {
      "type": "object",
      "properties": {
        "certificatePath": { "type": "string" },
        "timestampUrl": { "type": "string" }
      }
    }
  },
  "required": ["projectPath", "publishSettings"]
}

输出模式

{
  "type": "object",
  "properties": {
    "success": { "type": "boolean" },
    "files": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "path": { "type": "string" },
          "type": { "enum": ["pubxml", "manifest", "settings"] }
        }
      }
    },
    "publishCommand": { "type": "string" }
  },
  "required": ["success"]
}

.csproj配置

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <UseWPF>true</UseWPF>

    <!-- ClickOnce设置 -->
    <PublishUrl>https://myserver.com/myapp/</PublishUrl>
    <InstallUrl>https://myserver.com/myapp/</InstallUrl>
    <UpdateUrl>https://myserver.com/myapp/</UpdateUrl>
    <ApplicationRevision>1</ApplicationRevision>
    <ApplicationVersion>1.0.0.*</ApplicationVersion>
    <IsWebBootstrapper>true</IsWebBootstrapper>
    <PublisherName>My Company</PublisherName>
    <ProductName>My Application</ProductName>
    <MapFileExtensions>true</MapFileExtensions>
    <Install>true</Install>
    <InstallFrom>Web</InstallFrom>
    <UpdateEnabled>true</UpdateEnabled>
    <UpdateMode>Foreground</UpdateMode>
    <UpdateInterval>7</UpdateInterval>
    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
    <UpdatePeriodically>true</UpdatePeriodically>
    <UpdateRequired>false</UpdateRequired>
  </PropertyGroup>

  <!-- 先决条件 -->
  <ItemGroup>
    <BootstrapperPackage Include=".NETFramework,Version=v4.8">
      <Visible>False</Visible>
      <ProductName>.NET Framework 4.8</ProductName>
      <Install>true</Install>
    </BootstrapperPackage>
  </ItemGroup>

</Project>

发布配置文件(pubxml)

<!-- Properties/PublishProfiles/ClickOnce.pubxml -->
<?xml version="1.0" encoding="utf-8"?>
<Project>
  <PropertyGroup>
    <PublishProtocol>ClickOnce</PublishProtocol>
    <PublishDir>bin\publish\</PublishDir>
    <PublishUrl>https://myserver.com/myapp/</PublishUrl>
    <InstallUrl>https://myserver.com/myapp/</InstallUrl>
    <UpdateUrl>https://myserver.com/myapp/</UpdateUrl>
    <ApplicationVersion>1.0.0.*</ApplicationVersion>
    <Configuration>Release</Configuration>
    <Platform>Any CPU</Platform>
    <TargetFramework>net8.0-windows</TargetFramework>
    <SelfContained>false</SelfContained>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <PublishSingleFile>false</PublishSingleFile>
    <PublishReadyToRun>false</PublishReadyToRun>

    <!-- 安装设置 -->
    <Install>true</Install>
    <InstallFrom>Web</InstallFrom>
    <CreateDesktopShortcut>true</CreateDesktopShortcut>
    <CreateWebPageOnPublish>true</CreateWebPageOnPublish>
    <WebPageFileName>publish.htm</WebPageFileName>

    <!-- 更新设置 -->
    <UpdateEnabled>true</UpdateEnabled>
    <UpdateMode>Foreground</UpdateMode>
    <UpdateInterval>7</UpdateInterval>
    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
    <UpdatePeriodically>true</UpdatePeriodically>
    <UpdateRequired>false</UpdateRequired>

    <!-- 安全设置 -->
    <SignManifests>true</SignManifests>
    <ManifestCertificateThumbprint>1234567890ABCDEF</ManifestCertificateThumbprint>
    <ManifestTimestampRFC3161Url>http://timestamp.digicert.com</ManifestTimestampRFC3161Url>

    <!-- 文件关联 -->
    <TargetCulture>en-US</TargetCulture>
    <ProductName>My Application</ProductName>
    <PublisherName>My Company</PublisherName>
    <OpenBrowserOnPublish>false</OpenBrowserOnPublish>
  </PropertyGroup>
</Project>

程序化更新检查

using System.Deployment.Application;

public class UpdateManager
{
    public async Task<bool> CheckForUpdatesAsync()
    {
        if (!ApplicationDeployment.IsNetworkDeployed)
        {
            return false;
        }

        var deployment = ApplicationDeployment.CurrentDeployment;

        try
        {
            var info = deployment.CheckForDetailedUpdate();

            if (info.UpdateAvailable)
            {
                if (info.IsUpdateRequired)
                {
                    // 强制更新
                    deployment.Update();
                    Application.Restart();
                    return true;
                }
                else
                {
                    // 可选更新 - 提示用户
                    var result = MessageBox.Show(
                        $"版本 {info.AvailableVersion} 已可用。立即更新?",
                        "更新可用",
                        MessageBoxButton.YesNo);

                    if (result == MessageBoxResult.Yes)
                    {
                        deployment.Update();
                        Application.Restart();
                        return true;
                    }
                }
            }
        }
        catch (DeploymentDownloadException ex)
        {
            MessageBox.Show($"更新失败:{ex.Message}");
        }

        return false;
    }

    public Version GetCurrentVersion()
    {
        if (ApplicationDeployment.IsNetworkDeployed)
        {
            return ApplicationDeployment.CurrentDeployment.CurrentVersion;
        }
        return Assembly.GetExecutingAssembly().GetName().Version;
    }
}

发布命令

# 通过dotnet CLI发布
dotnet publish -p:PublishProfile=ClickOnce

# 通过MSBuild发布
msbuild /t:Publish /p:PublishProfile=ClickOnce

# 带版本增量发布
dotnet publish -p:PublishProfile=ClickOnce -p:ApplicationRevision=$(($(date +%s)))

签名配置

<!-- 使用证书签名清单 -->
<PropertyGroup>
  <SignManifests>true</SignManifests>
  <ManifestCertificateThumbprint>YOUR_CERT_THUMBPRINT</ManifestCertificateThumbprint>
  <ManifestTimestampRFC3161Url>http://timestamp.digicert.com</ManifestTimestampRFC3161Url>
</PropertyGroup>
# 查找证书指纹
Get-ChildItem -Path Cert:\CurrentUser\My | Format-Table Thumbprint, Subject

# 手动签名
mage -sign MyApp.application -CertFile cert.pfx -Password mypassword

服务器设置(IIS)

<!-- 用于ClickOnce托管的web.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <staticContent>
      <mimeMap fileExtension=".application" mimeType="application/x-ms-application"/>
      <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest"/>
      <mimeMap fileExtension=".deploy" mimeType="application/octet-stream"/>
    </staticContent>
  </system.webServer>
</configuration>

最佳实践

  1. 始终签名清单:生产环境必需
  2. 使用语义版本控制:清晰的版本更新
  3. 设置最低版本:强制关键修复更新
  4. 测试更新流程:发布前验证
  5. 使用HTTPS:安全下载通道
  6. 监控发布文件夹:验证部署成功

相关技能

  • windows-authenticode-signer - 代码签名
  • auto-update-system 流程 - 更新工作流
  • desktop-build-pipeline 流程 - CI/CD

相关代理

  • wpf-dotnet-expert - .NET专业知识
  • release-manager - 发布协调