チュートリアル : デザイナーを使用し、ClickOnce 配置 API で必要に応じてアセンブリをダウンロードする
既定では、ClickOnce アプリケーションの最初の実行時に、そのアプリケーションに含まれるすべてのアセンブリがダウンロードされます。しかしアプリケーションには、一部のユーザーだけが使用する機能が含まれている場合があります。この場合は、そのような機能を使用するときにだけ、対応するアセンブリがダウンロードされるようにすることができます。以下のチュートリアルでは、アプリケーション内の特定のアセンブリに "オプション" マークを付ける方法、および、共通言語ランタイム (CLR: Common Language Runtime) によって要求されたときに、System.Deployment.Application 名前空間にあるクラスを使用して、それらのアセンブリをダウンロードする方法を説明します。
[!メモ]
この手順を使用するには、アプリケーションが完全信頼で実行される必要があります。
[!メモ]
実際に画面に表示されるダイアログ ボックスとメニュー コマンドは、アクティブな設定またはエディションによっては、ヘルプの説明と異なる場合があります。設定を変更するには、[ツール] メニューの [設定のインポートとエクスポート] をクリックします。詳細については、「Visual Studio の設定」を参照してください。
プロジェクトの作成
オンデマンド アセンブリを使用するプロジェクトを Visual Studio で作成するには
Visual Studio で Windows フォーム プロジェクトを新規作成します。[ファイル] メニューの [追加] をポイントし、[新しいプロジェクト] をクリックします。ダイアログ ボックスの [クラス ライブラリ] プロジェクトをクリックし、ClickOnceLibrary という名前を付けます。
[!メモ]
Visual Basic では、プロジェクトのプロパティを変更して、このプロジェクトのルート名前空間を Microsoft.Samples.ClickOnceOnDemand または独自の名前空間に変更することをお勧めします。このチュートリアルでは、簡単にするために、2 つのプロジェクトを同じ名前空間に置いています。
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!"); } } } }
ソリューション エクスプローラーで、この Windows フォーム プロジェクトを選択します。System.Deployment.Application アセンブリへの参照と、ClickOnceLibrary プロジェクトへのプロジェクト参照を追加します。
[!メモ]
Visual Basic では、プロジェクトのプロパティを変更して、このプロジェクトのルート名前空間を Microsoft.Samples.ClickOnceOnDemand または独自の名前空間に変更することをお勧めします。このチュートリアルでは、簡単にするために、2 つのプロジェクトを同じ名前空間に置いています。
フォームを右クリックします。ショートカット メニューの [コードの表示] をクリックし、次の参照をフォームに追加します。
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 ジェネリック クラスを使ってグループ名にマップする方法を示しています。このチュートリアルでダウンロードされるアセンブリは 1 つだけなので、グループに存在するアセンブリも 1 つしかありません。実際のアプリケーションでは、アプリケーションの特定の機能に関連したすべてのアセンブリを同時にダウンロードするのが一般的です。この処理は、特定の機能に属するすべての 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 を終了する前に、作成した配置のアプリケーション マニフェストが含まれているタブをクリックし、このページにある [Files] タブをクリックします。
アプリケーション ファイルの一覧から ClickOnceLibrary.dll を探し、その [File Type] 列を [None] に設定します。[Group] 列には、「ClickOnceLibrary.dll」と入力します。
新しいアセンブリのテスト
オンデマンド アセンブリをテストするには
アプリケーションを ClickOnce で配置してから起動します。
メイン フォームが表示されたら、Button をクリックします。"Hello, World!" と書かれたメッセージ ボックスが表示されます。