演练:在设计器中使用 ClickOnce 部署 API 按需下载程序集

默认情况下,首次运行 ClickOnce 应用程序时,会下载该应用程序中包含的所有程序集。不过,少数用户可能仅使用应用程序的某些部分。在这种情况下,您可能希望只有在创建某一类型的程序集时,才下载一个该类型的程序集。下面的演练演示如何将应用程序中的某些程序集标记为“可选”,以及如何在公共语言运行时需要这些程序集时,通过使用 System.Deployment.Application 命名空间中的类来下载这些程序集。

说明说明

要使用此过程,应用程序必须以完全信任的方式运行。

说明说明

显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您现用的设置或版本。若要更改设置,请单击“工具”菜单上的“导入和导出设置”。有关更多信息,请参见 Visual Studio 设置

创建项目

通过 Visual Studio 创建使用按需程序集的项目

  1. 在 Visual Studio 中创建一个新的 Windows 窗体项目。在**“文件”菜单上指向“添加”,然后单击“新建项目”。在对话框中选择一个“类库”**项目,将其命名为 ClickOnceLibrary。

    说明说明

    在 Visual Basic 中,我们建议您修改项目属性,以便将此项目的根命名空间更改为 Microsoft.Samples.ClickOnceOnDemand 或所选的命名空间。为简单起见,本演练中的两个项目被放置在同一命名空间中。

  2. 定义一个名为 DynamicClass 的类,该类仅包含一个名为 Message 的属性。

    Public Class DynamicClass
        Sub New()
    
        End Sub
    
        Public ReadOnly Property Message() As String
            Get
                Message = "Hello, world!"
            End Get
        End Property
    End Class
    
    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!");
                }
            }
        }
    }
    
  3. 在**“解决方案资源管理器”**中选择相应的 Windows 窗体项目。在 System.Deployment.Application 程序集中添加一个引用,在 ClickOnceLibrary 项目中添加一个项目引用。

    说明说明

    在 Visual Basic 中,我们建议您修改项目属性,以便将此项目的根命名空间更改为 Microsoft.Samples.ClickOnceOnDemand 或所选的命名空间。为简单起见,本演练中的两个项目被放置在同一命名空间中。

  4. 右击窗体,从菜单中单击**“查看代码”**,然后在窗体中添加下列引用。

    Imports System.Reflection
    Imports System.Deployment.Application
    Imports System.Collections.Generic
    Imports Microsoft.Samples.ClickOnceOnDemand
    Imports System.Security.Permissions
    
    using System.Reflection;
    using System.Deployment.Application;
    using Microsoft.Samples.ClickOnceOnDemand;
    using System.Security.Permissions;
    
  5. 添加下面的代码以按需下载此程序集。本代码演示如何使用泛型 Dictionary 类将一组程序集映射到一个组名称上。因为在本演练中我们只下载了一个程序集,所以组中只有一个程序集。在实际应用中,您可能希望同时下载与应用程序中的一个功能相关的所有程序集。使用此映射表,您可以通过将属于某一功能的所有 DLL 与某个下载组名称相关联,来轻松实现此目的。

    ' 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. 
    Dim DllMappingTable As New Dictionary(Of String, String)()
    
    <SecurityPermission(SecurityAction.Demand, ControlAppDomain:=True)> _
    Sub New()
        ' This call is required by the Windows Form Designer.
        InitializeComponent()
    
        ' Add any initialization after the InitializeComponent() call.
        DllMappingTable("ClickOnceLibrary") = "ClickOnceLibrary"
    End Sub
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf Me.CurrentDomain_AssemblyResolve
    End Sub
    
    Private Function CurrentDomain_AssemblyResolve(ByVal sender As Object, ByVal args As ResolveEventArgs) As System.Reflection.Assembly
        Dim NewAssembly As Assembly = Nothing
    
        If (ApplicationDeployment.IsNetworkDeployed) Then
            Dim Deploy As ApplicationDeployment = ApplicationDeployment.CurrentDeployment
    
            ' Get the DLL name from the argument.
            Dim NameParts As String() = args.Name.Split(",")
            Dim DllName As String = NameParts(0)
            Dim DownloadGroupName As String = DllMappingTable(DllName)
    
            Try
                Deploy.DownloadFileGroup(DownloadGroupName)
            Catch ex As Exception
                MessageBox.Show("Could not download file group from Web server. Contact administrator. Group name: " & DownloadGroupName & "; DLL name: " & args.Name)
                Throw (ex)
            End Try
    
            ' 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")
            Catch ex As Exception
                Throw (ex)
            End Try
        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.")
        End If
    
        Return NewAssembly
    End Function
    
    // 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>();
    
    [SecurityPermission(SecurityAction.Demand, ControlAppDomain=true)]
    public Form1()
    {
        InitializeComponent();
    
        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");
            }
            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);
    }
    
  6. 在**“视图”菜单上单击“工具箱”。从“工具箱”**中将一个 Button 拖到窗体上。双击该按钮,然后向 Click 事件处理程序中添加下面的代码。

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim DC As New DynamicClass()
        MessageBox.Show("Message is " & DC.Message)
    End Sub
    
    private void getAssemblyButton_Click(object sender, EventArgs e)
    {
        DynamicClass dc = new DynamicClass();
        MessageBox.Show("Message: " + dc.Message);
    }
    

将程序集标记为可选

使用 Visual Studio 在 ClickOnce 应用程序中将程序集标记为可选

  1. 在**“解决方案资源管理器”中右击 Windows 窗体项目,再单击“属性”。选择“发布”**选项卡。

  2. 单击**“应用程序文件”**按钮。

  3. 查找 ClickOnceLibrary.dll 的列表。将**“发布状态”下拉框设置为“包含”**。

  4. 展开**“组”下拉框,然后选择“新建”**。输入名称 ClickOnceLibrary 作为新的组名称。

  5. 如何:使用发布向导发布 ClickOnce 应用程序 中所述,继续发布应用程序。

使用清单生成和编辑工具“图形客户端”(MageUI.exe),在 ClickOnce 应用程序中将程序集标记为可选

  1. 演练:手动部署 ClickOnce 应用程序中所述,创建 ClickOnce 清单。

  2. 选择包含部署的应用程序清单的选项卡,并在该选项卡中选择**“文件”**选项卡,然后关闭 MageUI.exe。

  3. 在应用程序文件的列表中查找 ClickOnceLibrary.dll,将它的**“文件类型”列设置为“无”。对于“组”**列键入 ClickOnceLibrary.dll。

测试新的程序集

测试按需程序集

  1. 启动使用 ClickOnce 部署的应用程序。

  2. 显示主窗体时,按 Button。此时,消息框窗口中应该显示“Hello, World!”这样的字符串。

请参见

参考

ApplicationDeployment