Exemplarische Vorgehensweise: Bedarfsgerechtes Herunterladen von Assemblys mit der API für die ClickOnce-Bereitstellung unter Verwendung des Designers
Standardmäßig werden alle in einer ClickOnce-Anwendung enthaltenen Assemblys beim ersten Ausführen der Anwendung heruntergeladen. Möglicherweise werden jedoch bestimmte Teile der Anwendung nur von wenigen Benutzern verwendet. In diesem Fall ist es sinnvoll, eine Assembly erst dann herunterzuladen, wenn Sie einen der zugehörigen Typen erstellen. Die folgende exemplarische Vorgehensweise zeigt, wie Sie bestimmte Assemblys einer Anwendung als "optional" markieren und wie Sie diese unter Verwendung von Klassen im System.Deployment.Application-Namespace herunterladen, wenn die Common Language Runtime sie anfordert.
Tipp
Die Anwendung muss mit voller Vertrauenswürdigkeit ausgeführt werden, um dieses Verfahren zu verwenden.
Tipp
Je nach den aktiven Einstellungen oder der Version unterscheiden sich die Dialogfelder und Menübefehle auf Ihrem Bildschirm möglicherweise von den in der Hilfe beschriebenen. Klicken Sie im Menü Extras auf Einstellungen importieren und exportieren, um die Einstellungen zu ändern. Weitere Informationen finden Sie unter Arbeiten mit Einstellungen.
Erstellen der Projekte
So erstellen Sie mit Visual Studio ein Projekt mit einer bedarfsabhängigen Assembly
Erstellen Sie in Visual Studio ein neues Windows Forms-Projekt. Zeigen Sie im Menü Datei auf Hinzufügen, und klicken Sie auf Neues Projekt. Wählen Sie im Dialogfeld die Projektvorlage Klassenbibliothek aus, und nennen Sie das Projekt ClickOnceLibrary.
Tipp
In Visual Basic wird empfohlen, die Projekteigenschaften zu bearbeiten, um den Stammnamespace für dieses Projekt in Microsoft.Samples.ClickOnceOnDemand oder einen Namespace Ihrer Wahl zu ändern. Der Einfachheit halber befinden sich die beiden Projekte in dieser exemplarischen Vorgehensweise im gleichen Namespace.
Definieren Sie eine Klasse mit dem Namen DynamicClass und einer einzigen Eigenschaft mit dem Namen 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!"); } } } }
Wählen Sie das Windows Forms-Projekt im Projektmappen-Explorer aus. Fügen Sie einen Verweis auf die System.Deployment.Application-Assembly und einen Projektverweis auf das ClickOnceLibrary-Projekt hinzu.
Tipp
In Visual Basic wird empfohlen, die Projekteigenschaften zu bearbeiten, um den Stammnamespace für dieses Projekt in Microsoft.Samples.ClickOnceOnDemand oder einen Namespace Ihrer Wahl zu ändern. Der Einfachheit halber befinden sich die beiden Projekte in dieser exemplarischen Vorgehensweise im gleichen Namespace.
Klicken Sie mit der rechten Maustaste auf das Formular, klicken Sie im Menü auf Code anzeigen, und fügen Sie dem Formular die folgenden Verweise hinzu.
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;
Fügen Sie den folgenden Code hinzu, um diese Assembly bei Bedarf herunterzuladen. Dieser Code zeigt, wie Sie mit der generischen Dictionary-Klasse einem Gruppennamen mehrere Assemblys zuordnen. Da in dieser exemplarischen Vorgehensweise nur eine Assembly heruntergeladen wird, enthält die Gruppe nur eine Assembly. In einer realen Anwendung würden Sie wahrscheinlich alle Assemblys, die mit einem bestimmten Feature in der Anwendung verknüpft sind, auf einmal herunterladen. Anhand der Zuordnungstabelle ist dies problemlos möglich, indem Sie alle DLLs, die zu einer Funktion gehören, einem Downloadgruppennamen zuordnen.
' 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); }
Klicken Sie im Menü Ansicht auf Toolbox. Ziehen Sie einen Button aus der Toolbox auf das Formular. Doppelklicken Sie auf die Schaltfläche, und fügen Sie dem Click-Ereignishandler den folgenden Code hinzu.
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); }
Markieren von Assemblys als optional
So markieren Sie mit Visual Studio Assemblys in der ClickOnce-Anwendung als optional
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Windows Forms-Projekt, und klicken Sie auf Eigenschaften. Wählen Sie die Registerkarte Veröffentlichen aus.
Klicken Sie auf die Schaltfläche Anwendungsdateien.
Suchen Sie die Auflistung für ClickOnceLibrary.dll. Legen Sie das Dropdownfeld Veröffentlichungsstatus auf Einschließen fest.
Erweitern Sie das Dropdownfeld Gruppieren, und wählen Sie Neu aus. Geben Sie den Namen ClickOnceLibrary als neuen Gruppenname ein.
Fahren Sie mit dem Veröffentlichen der Anwendung fort, wie unter Gewusst wie: Veröffentlichen einer ClickOnce-Anwendung mit dem Webpublishing-Assistenten beschrieben.
So markieren Sie Assemblys in der ClickOnce-Anwendung mit dem grafischen Client des Tools zum Generieren und Bearbeiten von Manifesten (MageUI.exe) als optional
Erstellen Sie die ClickOnce-Manifeste, wie unter Exemplarische Vorgehensweise: Manuelles Bereitstellen einer ClickOnce-Anwendung beschrieben.
Wählen Sie vor dem Schließen von MageUI.exe die Registerkarte aus, die das Anwendungsmanifest der Bereitstellung enthält, und wählen Sie auf dieser Registerkarte die Registerkarte Dateien aus.
Suchen Sie ClickOnceLibrary.dll in der Liste der Anwendungsdateien, und legen Sie die Spalte Dateityp auf Kein fest. Geben Sie für die Spalte Gruppieren den Namen ClickOnceLibrary.dll ein.
Testen der neuen Assembly
So testen Sie die bedarfsabhängige Assembly
Starten Sie die mit ClickOnce bereitgestellte Anwendung.
Wenn das Hauptformular angezeigt wird, klicken Sie auf den Button. Nun sollte in einem Meldungsfenster die Zeichenfolge "Hello, World!" angezeigt werden.