チュートリアル : ClickOnce 配置 API を使用して必要に応じてアセンブリをダウンロードする
既定では、ClickOnce アプリケーションの最初の実行時に、そのアプリケーションに含まれるすべてのアセンブリがダウンロードされます。一方、アプリケーションには、一部のユーザーだけが使用する機能が含まれている場合があります。この場合は、そのような機能を使用するときにだけ、対応するアセンブリがダウンロードされるようにすることができます。以下のチュートリアルでは、アプリケーション内の特定のアセンブリを "オプション" としてマークを付ける方法、および、共通言語ランタイム (CLR: Common Language Runtime) によって要求されたときに、System.Deployment.Application 名前空間にあるクラスを使用して、それらのアセンブリをダウンロードする方法を説明します。
[!メモ]
この手順を使用するには、アプリケーションが完全信頼で実行される必要があります。
必須コンポーネント
このチュートリアルを実行するには、次のいずれかのコンポーネントが必要です。
Windows SDK。Windows SDK は、Microsoft ダウンロード センターからダウンロードできます。
Visual Studio
プロジェクトの作成
オンデマンド アセンブリを使用するプロジェクトを作成するには
ClickOnceOnDemand という名前のディレクトリを作成します。
Windows SDK コマンド プロンプトまたは Visual Studio コマンド プロンプトを開きます。
ClickOnceOnDemand ディレクトリに移動します。
次のコマンドを使用して、公開キーと秘密キーのペアを生成します。
sn -k TestKey.snk
メモ帳などのテキスト エディターを使用して、Message という名前のプロパティ 1 つを持つ DynamicClass クラスを定義します。
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!"); } } } }
このテキストを、使用しているプログラミング言語に応じて ClickOnceLibrary.cs または ClickOnceLibrary.vb というファイル名で、ClickOnceOnDemand ディレクトリに保存します。
ファイルをアセンブリにコンパイルします。
csc /target:library /keyfile:TestKey.snk ClickOnceLibrary.cs
vbc /target:library /keyfile:TestKey.snk ClickOnceLibrary.vb
アセンブリの公開キー トークンを取得するには、次のコマンドを使用します。
sn -T ClickOnceLibrary.dll
テキスト エディターを使用して新しいファイルを作成し、次のコードを入力します。このコードは、必要なときに ClickOnceLibrary アセンブリをダウンロードする Windows フォーム アプリケーションを作成します。
Imports System Imports System.Windows.Forms Imports System.Deployment.Application Imports System.Drawing Imports System.Reflection Imports System.Collections.Generic Imports Microsoft.Samples.ClickOnceOnDemand Namespace Microsoft.Samples.ClickOnceOnDemand <System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Unrestricted:=true)> _ Class Form1 Inherits 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. Dim DllMapping as Dictionary(Of String, String) = new Dictionary(of String, String)() Public Sub New() ' Add button to form. Dim GetAssemblyButton As New Button() GetAssemblyButton.Location = New Point(100, 100) GetAssemblyButton.Text = "Get assembly on demand" AddHandler GetAssemblyButton.Click, AddressOf GetAssemblyButton_Click Me.Controls.Add(GetAssemblyButton) DllMapping("ClickOnceLibrary") = "ClickOnceLibrary" AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf CurrentDomain_AssemblyResolve End Sub <STAThread()> _ Shared Sub Main() Application.EnableVisualStyles() Application.Run(New Form1()) End Sub Private Function CurrentDomain_AssemblyResolve(ByVal sender As Object, ByVal args As ResolveEventArgs) As Assembly If ApplicationDeployment.IsNetworkDeployed Then Dim deploy As ApplicationDeployment = ApplicationDeployment.CurrentDeployment ' Get the DLL name from the Name argument. Dim nameParts() as String = args.Name.Split(",") Dim dllName as String = nameParts(0) Dim downloadGroupName as String = DllMapping(dllName) Try deploy.DownloadFileGroup(downloadGroupName) Catch de As DeploymentException End Try ' Load the assembly. Dim newAssembly As Assembly = Nothing Try newAssembly = Assembly.LoadFile(Application.StartupPath & "\\" & dllName & ".dll," & _ "Version=1.0.0.0, Culture=en, PublicKeyToken=03689116d3a4ae33") Catch ex As Exception MessageBox.Show("Could not download assembly on demand.") End Try CurrentDomain_AssemblyResolve = newAssembly Else CurrentDomain_AssemblyResolve = Nothing End If End Function Private Sub GetAssemblyButton_Click(ByVal sender As Object, ByVal e As EventArgs) Dim ourClass As New DynamicClass() MessageBox.Show("DynamicClass string is: " + ourClass.Message) End Sub End Class End Namespace
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); } } }
コード内で LoadFile の呼び出しを見つけます。
PublicKeyToken を、先に取得しておいた値に設定します。
ファイルに Form1.cs または Form1.vb の名前を付けて保存します。
これを、次のコマンドを使用して実行可能ファイルにコンパイルします。
csc /target:exe /reference:ClickOnceLibrary.dll Form1.cs
vbc /target:exe /reference:ClickOnceLibrary.dll Form1.vb
アセンブリをオプションとしてマークするには
MageUI.exe を使用して ClickOnce アプリケーション内のアセンブリをオプションとしてマークするには
MageUI.exe を使用して、「チュートリアル : ClickOnce アプリケーションを手動で配置する」の説明に従ってアプリケーション マニフェストを作成します。アプリケーション マニフェストに、次の設定を行います。
アプリケーション マニフェストに ClickOnceOnDemand という名前を付けます。
[Files] ページで、ClickOnceLibrary.dll 行の [File Type] 列を [None] に設定します。
[Files] ページで、ClickOnceLibrary.dll 行の [Group] 列に「ClickOnceLibrary.dll」と入力します。
MageUI.exe を使用して、「チュートリアル : ClickOnce アプリケーションを手動で配置する」の説明に従って配置マニフェストを作成します。配置マニフェストに、以下の設定を使用します。
- 配置マニフェストに ClickOnceOnDemand という名前を付けます。
新しいアセンブリのテスト
オンデマンド アセンブリをテストするには
作成した ClickOnce 配置を Web サーバーにアップロードします。
配置マニフェストの URL を Web ブラウザーに入力して、ClickOnce で配置したアプリケーションを Web ブラウザーから起動します。ClickOnce アプリケーションの名前が ClickOnceOnDemand であり、そのアップロード先が adatum.com のルート ディレクトリの場合、入力する URL は次のようになります。
http://www.adatum.com/ClickOnceOnDemand/ClickOnceOnDemand.application
メイン フォームが表示されたら、Button をクリックします。"Hello, World!" と書かれたメッセージ ボックスが表示されます。