Condividi tramite


Procedura dettagliata: download di assembly su richiesta con l'API della distribuzione ClickOnce

Per impostazione predefinita, tutti gli assembly inclusi in un'applicazione ClickOnce vengono scaricati alla prima esecuzione dell'applicazione. È tuttavia possibile che alcune parti dell'applicazione vengano utilizzate solo da un gruppo limitato di utenti. In questo caso è preferibile scaricare un assembly solo quando viene creato uno dei relativi tipi. Nella procedura dettagliata riportata di seguito vengono illustrate le operazioni da eseguire per impostare come facoltativi determinati assembly inclusi nell'applicazione nonché per scaricarli utilizzando le classi dello spazio dei nomi System.Deployment.Application, quando richiesti da Common Language Runtime (CLR).

Nota

L'applicazione dovrà essere eseguita in condizioni di attendibilità totale per utilizzare questa procedura.

Prerequisiti

Per completare questa procedura dettagliata, è necessario disporre di uno dei componenti seguenti:

  • Windows SDK, scaricabile dall'Area download Microsoft.

  • Visual Studio.

Creazione dei progetti

Per creare un progetto che utilizza un assembly su richiesta

  1. Creare una directory denominata ClickOnceOnDemand.

  2. Aprire il prompt dei comandi di Windows SDK o di Visual Studio.

  3. Passare alla directory ClickOnceOnDemand.

  4. Generare una coppia di chiavi pubblica/privata utilizzando il comando seguente:

    sn -k TestKey.snk
    
  5. Utilizzando il Blocco note o un altro editor di testo, definire una classe DynamicClass con una singola proprietà 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!");
                }
            }
        }
    }
    
  6. A seconda del linguaggio utilizzato, salvare il testo con il nome ClickOnceLibrary.cs o ClickOnceLibrary.vb nella directory ClickOnceOnDemand.

  7. Compilare il file in un assembly.

    csc /target:library /keyfile:TestKey.snk ClickOnceLibrary.cs
    
    vbc /target:library /keyfile:TestKey.snk ClickOnceLibrary.vb
    
  8. Per ottenere il token della chiave pubblica per l'assembly, utilizzare il comando seguente:

    sn -T ClickOnceLibrary.dll
    
  9. Creare un nuovo file utilizzando l'editor di testo e immettere il codice riportato di seguito. Questo codice crea un'applicazione Windows Form che scarica l'assembly ClickOnceLibrary quando è richiesto.

    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);
            }
        }
    }
    
  10. Nel codice individuare la chiamata a LoadFile.

  11. Impostare PublicKeyToken sul valore recuperato in precedenza.

  12. Salvare il file come Form1.cs o Form1.vb.

  13. Compilarlo in un eseguibile utilizzando il comando seguente:

    csc /target:exe /reference:ClickOnceLibrary.dll Form1.cs
    
    vbc /target:exe /reference:ClickOnceLibrary.dll Form1.vb
    

Impostazione degli assembly come facoltativi

Per impostare come facoltativi gli assembly nell'applicazione ClickOnce mediante MageUI.exe

  1. Utilizzando MageUI.exe, creare un manifesto di applicazione come descritto nella sezione Procedura dettagliata: distribuzione manuale di un'applicazione ClickOnce. Specificare quindi le impostazioni seguenti :

    • Assegnare al manifesto dell'applicazione il nome ClickOnceOnDemand.

    • Nella riga ClickOnceLibrary.dll della pagina File impostare la colonna Tipo file su Nessuno.

    • Nella riga ClickOnceLibrary.dll della pagina File digitare ClickOnceLibrary.dll nella colonna Gruppo.

  2. Utilizzando MageUI.exe, creare un manifesto di distribuzione come descritto nella sezione Procedura dettagliata: distribuzione manuale di un'applicazione ClickOnce. Specificare quindi le impostazioni seguenti:

    • Assegnare al manifesto di distribuzione il nome ClickOnceOnDemand.

Test del nuovo assembly

Per testare l'assembly su richiesta

  1. Caricare la distribuzione di ClickOnce su un server Web.

  2. Avviare l'applicazione distribuita con ClickOnce da un browser Web immettendo l'URL del manifesto di distribuzione. Se all'applicazione ClickOnce è stato assegnato il nome ClickOnceOnDemand e l'applicazione viene caricata nella directory radice di adatum.com, l'URL sarà simile al seguente:

    http://www.adatum.com/ClickOnceOnDemand/ClickOnceOnDemand.application
    
  3. Quando viene visualizzato il form principale, scegliere il controllo Button. Verrà visualizzata una finestra di messaggio contenente la stringa "Hello, World!".

Vedere anche

Riferimenti

ApplicationDeployment