演练:使用 ClickOnce 部署 API 按需下载程序集

默认情况下,首次运行应用程序时会下载 ClickOnce 应用程序中包含的所有程序集。 但是,你的应用程序可能有某些部分仅被一小部分用户使用。 在这种情况下,只有在创建程序集类型之一时,才需要下载程序集。 以下演练演示如何将应用程序中的某些程序集标记为“可选”,以及如何在公共语言运行时(CLR)要求它们时使用命名空间中的 System.Deployment.Application 类下载它们。

注释

ApplicationDeployment 类和System.Deployment.Application 命名空间中的 API 在 .NET Core 和 .NET 5 及更高版本中不受支持。 在 .NET 7 中,支持访问应用程序部署属性的新方法。 有关详细信息,请参阅 .NET 中的 Access ClickOnce 部署属性。 .NET 7 不支持 ApplicationDeployment 方法的等效项。

注释

应用程序需要在完全信任的环境中运行才能使用此过程。

先决条件

需要以下组件之一才能完成本演练:

  • Windows SDK。 可以从Microsoft下载中心下载 Windows SDK。

  • Visual Studio。

创建项目

创建使用按需程序集的项目

  1. 创建名为 ClickOnceOnDemand 的目录。

  2. 打开 Windows SDK 命令提示符或 Visual Studio 命令提示符。

  3. 更改为 ClickOnceOnDemand 目录。

  4. 使用以下命令生成公钥/私钥对:

    sn -k TestKey.snk
    
  5. 使用记事本或其他文本编辑器定义一个名为 DynamicClass 的类,并设置一个属性 Message

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Microsoft.Samples.ClickOnceOnDemand
    {
        public class DynamicClass
        {
            public DynamicClass() {}
    
            public string Message
            {
                get
                {
                    return ("Hello, world!");
                }
            }
        }
    }
    
  6. 根据所用语言将文本另存为名为 ClickOnceLibrary.csClickOnceLibrary.vb的文件保存到 ClickOnceOnDemand 目录。

  7. 将文件编译为程序集。

    csc /target:library /keyfile:TestKey.snk ClickOnceLibrary.cs
    
  8. 若要获取程序集的公钥令牌,请使用以下命令:

    sn -T ClickOnceLibrary.dll
    
  9. 使用文本编辑器创建新文件,并输入以下代码。 此代码创建一个 Windows 窗体应用程序,该应用程序在需要时下载 ClickOnceLibrary 程序集。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Reflection;
    using System.Deployment.Application;
    using Microsoft.Samples.ClickOnceOnDemand;
    
    namespace ClickOnceOnDemand
    {
        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Unrestricted=true)]
        public class Form1 : Form
        {
            // Maintain a dictionary mapping DLL names to download file groups. This is trivial for this sample,
            // but will be important in real-world applications where a feature is spread across multiple DLLs,
            // and you want to download all DLLs for that feature in one shot. 
            Dictionary<String, String> DllMapping = new Dictionary<String, String>();
    
            public static void Main()
            {
                Form1 NewForm = new Form1();
                Application.Run(NewForm);
            }
    
            public Form1()
            {
                // Configure form. 
                this.Size = new Size(500, 200);
                Button getAssemblyButton = new Button();
                getAssemblyButton.Size = new Size(130, getAssemblyButton.Size.Height);
                getAssemblyButton.Text = "Test Assembly";
                getAssemblyButton.Location = new Point(50, 50);
                this.Controls.Add(getAssemblyButton);
                getAssemblyButton.Click += new EventHandler(getAssemblyButton_Click);
    
                DllMapping["ClickOnceLibrary"] = "ClickOnceLibrary";
                AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            }
    
            /*
             * Use ClickOnce APIs to download the assembly on demand.
             */
            private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
            {
                Assembly newAssembly = null;
    
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    ApplicationDeployment deploy = ApplicationDeployment.CurrentDeployment;
    
                    // Get the DLL name from the Name argument.
                    string[] nameParts = args.Name.Split(',');
                    string dllName = nameParts[0];
                    string downloadGroupName = DllMapping[dllName];
    
                    try
                    {
                        deploy.DownloadFileGroup(downloadGroupName);
                    }
                    catch (DeploymentException de)
                    {
                        MessageBox.Show("Downloading file group failed. Group name: " + downloadGroupName + "; DLL name: " + args.Name);
                        throw (de);
                    }
    
                    // Load the assembly.
                    // Assembly.Load() doesn't work here, as the previous failure to load the assembly
                    // is cached by the CLR. LoadFrom() is not recommended. Use LoadFile() instead.
                    try
                    {
                        newAssembly = Assembly.LoadFile(Application.StartupPath + @"\" + dllName + ".dll," +  
                "Version=1.0.0.0, Culture=en, PublicKeyToken=03689116d3a4ae33");
                    }
                    catch (Exception e)
                    {
                        throw (e);
                    }
                }
                else
                {
                    //Major error - not running under ClickOnce, but missing assembly. Don't know how to recover.
                    throw (new Exception("Cannot load assemblies dynamically - application is not deployed using ClickOnce."));
                }
    
    
                return (newAssembly);
            }
    
            private void getAssemblyButton_Click(object sender, EventArgs e)
            {
                DynamicClass dc = new DynamicClass();
                MessageBox.Show("Message: " + dc.Message);
            }
        }
    }
    
  10. 在代码中,找到对LoadFile的调用。

  11. 请将 PublicKeyToken 设置为您之前检索到的值。

  12. 将文件另存为 Form1.csForm1.vb

  13. 使用以下命令将其编译为可执行文件。

    csc /target:exe /reference:ClickOnceLibrary.dll Form1.cs
    

将程序集标记为可选

使用 MageUI.exe 在 ClickOnce 应用程序中将程序集标记为可选

  1. 使用 MageUI.exe,按照演练中所述创建应用程序清单 :手动部署 ClickOnce 应用程序。 对应用程序清单使用以下设置:

    • 将应用程序清单 ClickOnceOnDemand命名为 。

    • “文件” 页上的 ClickOnceLibrary.dll 行中,将 “文件类型 ”列设置为 “无”。

    • 文件页的ClickOnceLibrary.dll行中,在列中键入ClickOnceLibrary.dll

  2. 使用 MageUI.exe,按照演练中所述创建部署清单 :手动部署 ClickOnce 应用程序。 对部署清单使用以下设置:

    • 将部署清单 ClickOnceOnDemand命名为 。

测试新程序集

测试按需程序集

  1. 将 ClickOnce 部署上传到 Web 服务器。

  2. 通过输入部署清单的 URL,从 Web 浏览器启动使用 ClickOnce 部署的应用程序。 如果调用 ClickOnce 应用程序 ClickOnceOnDemand,并将其上传到 adatum.com 的根目录,则 URL 如下所示:

    http://www.adatum.com/ClickOnceOnDemand/ClickOnceOnDemand.application
    
  3. 当主窗体出现时,按Button。 应在消息框窗口中看到一个字符串,该窗口显示“Hello, World!”。