Tutorial: Descargar ensamblados a petición con la API de implementación de ClickOnce

De forma predeterminada, todos los ensamblados incluidos en una aplicación ClickOnce se descargan la primera vez que se ejecuta la aplicación. Sin embargo, puede que un pequeño conjunto de usuarios utilice algunos componentes de la aplicación. En este caso, sólo descargará un ensamblado cuando cree uno de los tipos. En el tutorial siguiente se muestra cómo marcar determinados ensamblados de la aplicación como "opcional" y cómo descargarlos utilizando clases del espacio de nombres System.Deployment.Application cuando Common Language Runtime (CLR) los solicite.

Nota

Para poder utilizar este procedimiento, es necesario que la aplicación se ejecute con plena confianza.

Requisitos previos

Necesitará uno de los componentes siguientes para completar este tutorial:

  • SDK de Windows. El SDK de Windows se puede descargar desde el Centro de descarga de Microsoft.

  • Visual Studio.

Crear los proyectos

Para crear un proyecto que utilice un ensamblado a petición

  1. Cree un directorio denominado ClickOnceOnDemand.

  2. Abra el símbolo del sistema del SDK de Windows o de Visual Studio.

  3. Cambie al directorio ClickOnceOnDemand.

  4. Cree un par de claves pública y privada con el comando siguiente:

    sn -k TestKey.snk
    
  5. Con el Bloc de notas u otro editor de texto, defina una clase denominada DynamicClass con una propiedad única denominada 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. Guarde el texto como un archivo denominado ClickOnceLibrary.cs o ClickOnceLibrary.vb, en función del lenguaje que utilice, en el directorio ClickOnceOnDemand.

  7. Compile el archivo en un ensamblado.

    csc /target:library /keyfile:TestKey.snk ClickOnceLibrary.cs
    
    vbc /target:library /keyfile:TestKey.snk ClickOnceLibrary.vb
    
  8. Para obtener el token de clave pública del ensamblado, utilice el comando siguiente:

    sn -T ClickOnceLibrary.dll
    
  9. Cree un nuevo archivo mediante el editor de texto y escriba el código siguiente. Este código crea una aplicación de formularios Windows Forms que descarga el ensamblado ClickOnceLibrary cuando así se requiere.

    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. En el código, busque la llamada a LoadFile.

  11. Establezca PublicKeyToken en el valor que recuperó anteriormente.

  12. Guarde el archivo como Form1.cs o Form1.vb.

  13. Compílelo en un ejecutable mediante el comando siguiente.

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

Marcar los ensamblados como opcional

Para marcar los ensamblados como opcionales en la aplicación ClickOnce utilizando MageUI.exe

  1. Con MageUI.exe, cree un manifiesto de aplicación, tal y como se describe en Tutorial: Implementar manualmente una aplicación ClickOnce. Utilice la configuración siguiente para el manifiesto de aplicación:

    • Llame al manifiesto de la aplicación ClickOnceOnDemand.

    • En la página Archivos, en la fila de ClickOnceLibrary.dll, establezca la columna Tipo de archivo en Ninguno.

    • En la página Archivos, en la fila de ClickOnceLibrary.dll, escriba ClickOnceLibrary.dll en la columna Grupo.

  2. Utilizando MageUI.exe, cree un manifiesto de implementación, tal y como se describe en Tutorial: Implementar manualmente una aplicación ClickOnce. Utilice la configuración siguiente para el manifiesto de implementación:

    • Llame ClickOnceOnDemand al manifiesto de implementación.

Probar el nuevo ensamblado

Para probar el ensamblado a petición

  1. Cargue la implementación de ClickOnce en un servidor web.

  2. Inicie la aplicación implementada con ClickOnce desde un explorador web; para ello, escriba la dirección URL del manifiesto de implementación. Si llama a la aplicación de ClickOnce ClickOnceOnDemand y la carga en el directorio raíz de adatum.com, la dirección URL presentará el siguiente aspecto:

    http://www.adatum.com/ClickOnceOnDemand/ClickOnceOnDemand.application
    
  3. Cuando aparezca el formulario principal, presione Button. Verá una cadena en una ventana de cuadro de mensaje con el texto, "Hello, World!".

Vea también

Referencia

ApplicationDeployment