演练:在设计器中使用 ClickOnce 部署 API 按需下载程序集
默认情况下,首次运行 ClickOnce 应用程序时,会下载该应用程序中包含的所有程序集。 不过,少数用户可能仅使用应用程序的某些部分。 在这种情况下,您可能希望只有在创建某一类型的程序集时,才下载一个该类型的程序集。 下面的演练演示如何将应用程序中的某些程序集标记为“可选”,以及如何在公共语言运行时需要这些程序集时,通过使用 System.Deployment.Application 命名空间中的类来下载这些程序集。
备注
要使用此过程,应用程序必须以完全信任的方式运行。
备注
显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您现用的设置或版本。若要更改设置,请单击“工具”菜单上的“导入和导出设置”。有关更多信息,请参见 Visual Studio 设置。
创建项目
通过 Visual Studio 创建使用按需程序集的项目
在 Visual Studio 中创建一个新的 Windows 窗体项目。 在**“文件”菜单上指向“添加”,然后单击“新建项目”。 在对话框中选择一个“类库”**项目,将其命名为 ClickOnceLibrary。
备注
在 Visual Basic 中,我们建议您修改项目属性,以便将此项目的根命名空间更改为 Microsoft.Samples.ClickOnceOnDemand 或所选的命名空间。为简单起见,本演练中的两个项目被放置在同一命名空间中。
定义一个名为 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!"); } } } }
在**“解决方案资源管理器”**中选择相应的 Windows 窗体项目。 在 System.Deployment.Application 程序集中添加一个引用,在 ClickOnceLibrary 项目中添加一个项目引用。
备注
在 Visual Basic 中,我们建议您修改项目属性,以便将此项目的根命名空间更改为 Microsoft.Samples.ClickOnceOnDemand 或所选的命名空间。为简单起见,本演练中的两个项目被放置在同一命名空间中。
右击窗体,从菜单中单击**“查看代码”**,然后在窗体中添加下列引用。
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;
添加下面的代码以按需下载此程序集。 本代码演示如何使用泛型 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); }
在**“视图”菜单上单击“工具箱”。 从“工具箱”**中将一个 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 应用程序中将程序集标记为可选
在**“解决方案资源管理器”中右击 Windows 窗体项目,再单击“属性”。 选择“发布”**选项卡。
单击**“应用程序文件”**按钮。
查找 ClickOnceLibrary.dll 的列表。 将**“发布状态”下拉框设置为“包含”**。
展开**“组”下拉框,然后选择“新建”**。 输入名称 ClickOnceLibrary 作为新的组名称。
如 如何:使用发布向导发布 ClickOnce 应用程序 中所述,继续发布应用程序。
使用清单生成和编辑工具“图形客户端”(MageUI.exe),在 ClickOnce 应用程序中将程序集标记为可选
如演练:手动部署 ClickOnce 应用程序中所述,创建 ClickOnce 清单。
选择包含部署的应用程序清单的选项卡,并在该选项卡中选择**“文件”**选项卡,然后关闭 MageUI.exe。
在应用程序文件的列表中查找 ClickOnceLibrary.dll,将它的**“文件类型”列设置为“无”。 对于“组”**列键入 ClickOnceLibrary.dll。
测试新的程序集
测试按需程序集
启动使用 ClickOnce 部署的应用程序。
显示主窗体时,按 Button。 此时,消息框窗口中应该显示“Hello, World!”这样的字符串。