Tutorial: Crear una aplicación extensible

En este tutorial se describe cómo se crea una canalización para un complemento que realiza las funciones de una calculadora sencilla. No muestra un escenario real; más bien, muestra la funcionalidad básica de una canalización y cómo un complemento puede proporcionar servicios a un host.

En este tutorial se describen las tareas siguientes:

  • Crear una solución de Visual Studio.

  • Crear la estructura de directorios de canalización.

  • Crear el contrato y las vistas.

  • Crear el adaptador de conversión.

  • Crear el adaptador del host.

  • Crear el host.

  • Crear el complemento.

  • Implementar la canalización.

  • Ejecutar la aplicación host.

Esta canalización sólo pasa tipos serializables (Double y String) entre el host y el complemento. Para obtener un ejemplo en el que se muestra cómo se pasan colecciones de tipos de datos complejos, vea Tutorial: Pasar colecciones entre hosts y complementos.

El contrato de esta canalización define un modelo de objetos de cuatro operaciones aritméticas: sumar, restar, multiplicar y dividir. El host proporciona al complemento una ecuación que hay que calcular, por ejemplo 2 + 2, y el complemento devuelve el resultado al host.

La versión 2 del complemento de calculadora proporciona otras posibilidades de cálculo y muestra el control de versiones. Esta versión se describe en Tutorial: Habilitar la compatibilidad con versiones anteriores al cambiar el host.

NotaNota

Puede encontrar más código de ejemplo y vistas previas de herramientas con la tecnología de clientes para compilar canalizaciones de complementos en el sitio Managed Extensibility and Add-In Framework de CodePlex.

Requisitos previos

Necesita lo siguiente para poder llevar a cabo este tutorial:

  • Visual Studio.

Crear una solución de Visual Studio

Utilice una solución de Visual Studio que contenga los proyectos de sus segmentos de canalización.

Para crear la solución de canalización

  1. En Visual Studio, cree un nuevo proyecto denominado Calc1Contract. Utilice como base la plantilla Biblioteca de clases.

  2. Llame a la solución CalculatorV1.

Crear la estructura de directorios de canalización

El modelo de complementos requiere que los ensamblados de los segmentos de canalización se sitúen en una estructura de directorios específica. Para obtener más información sobre la estructura de canalización, vea Requisitos del desarrollo de canalizaciones.

Para crear la estructura de directorios de canalización

  1. Cree en una carpeta de aplicación en cualquier ubicación del equipo.

  2. En esa carpeta, cree la estructura siguiente:

    Pipeline
      AddIns
        CalcV1
        CalcV2
      AddInSideAdapters
      AddInViews
      Contracts
      HostSideAdapters
    

    No es necesario que sitúe la estructura de carpetas de la canalización en la carpeta de la aplicación; aquí sólo lo hacemos por comodidad. En el paso correspondiente, el tutorial explica cómo debe cambiarse el código si la estructura de carpetas de la canalización se encuentra en una ubicación diferente. Vea los comentarios sobre los requisitos de los directorios de la canalización en Requisitos del desarrollo de canalizaciones.

    NotaNota

    La carpeta CalcV2 no se utiliza en este tutorial; es un marcador de posición de Tutorial: Habilitar la compatibilidad con versiones anteriores al cambiar el host.

Crear el contrato y las vistas

El segmento del contrato de esta canalización define la interfaz ICalc1Contract, que, a su vez, define cuatro métodos: add, subtract, multiply y divide.

Para crear el contrato

  1. En la solución de Visual Studio denominada CalculatorV1, abra el proyecto Calc1Contract.

  2. En el Explorador de soluciones, agregue referencias de los siguientes ensamblados al proyecto Calc1Contract:

    System.AddIn.Contract.dll

    System.AddIn.dll

  3. En el Explorador de soluciones, excluya la clase predeterminada que se agrega a los nuevos proyectos de Biblioteca de clases.

  4. En el Explorador de soluciones, agregue un nuevo elemento al proyecto utilizando la plantilla Interfaz. En el cuadro de diálogo Agregar nuevo elemento, denomine la interfaz ICalc1Contract.

  5. En el archivo de interfaz, agregue referencias de espacio de nombres a System.AddIn.Contract y System.AddIn.Pipeline.

  6. Utilice el código siguiente para completar este segmento del contrato. Tenga en cuenta que esta interfaz debe tener el atributo AddInContractAttribute.

    Imports System.AddIn.Contract
    Imports System.AddIn.Pipeline
    
    Namespace CalculatorContracts
    
        ' The AddInContractAttribute identifes this pipeline segment as a
        ' contract.
        <AddInContract()> _
        Public Interface ICalc1Contract
            Inherits IContract
    
            Function Add(ByVal a As Double, ByVal b As Double) As Double
            Function Subtract(ByVal a As Double, ByVal b As Double) As Double
            Function Multiply(ByVal a As Double, ByVal b As Double) As Double
            Function Divide(ByVal a As Double, ByVal b As Double) As Double
        End Interface
    
    End Namespace
    
    using System.AddIn.Contract;
    using System.AddIn.Pipeline;
    
    namespace CalculatorContracts
    {
        // The AddInContractAttribute identifes this pipeline segment as a 
        // contract.
        [AddInContract]
        public interface ICalc1Contract : IContract
        {
        double Add(double a, double b);
        double Subtract(double a, double b);
        double Multiply(double a, double b);
        double Divide(double a, double b);
        }
    }
    
  7. De manera opcional, compile la solución de Visual Studio. La solución no se puede ejecutarse hasta el procedimiento final, pero si la compila después de cada procedimiento, se asegura de que cada proyecto es correcto.

Dado que la vista de complemento y la vista de host del complemento normalmente tienen el mismo código, en concreto la primera versión del complemento, resulta sencillo crear las vistas al mismo tiempo. Sólo se diferencian en un aspecto: la vista de complemento requiere el atributo AddInBaseAttribute, mientras que la vista de host del complemento no requiere ningún atributo.

Para crear la vista de complemento

  1. Agregue un nuevo proyecto denominado Calc1AddInView a la solución CalculatorV1. Utilice como base la plantilla Biblioteca de clases.

  2. En el Explorador de soluciones, agregue una referencia de System.AddIn.dll al proyecto Calc1AddInView.

  3. En el Explorador de soluciones, excluya la clase predeterminada que se agrega a los nuevos proyectos de Biblioteca de clases y agregue un nuevo elemento al proyecto, utilizando la plantilla Interfaz. En el cuadro de diálogo Agregar nuevo elemento, denomine la interfaz ICalculator.

  4. En el archivo de interfaz, agregue una referencia de espacio de nombres a System.AddIn.Pipeline.

  5. Utilice el código siguiente para completar esta vista de complemento. Tenga en cuenta que esta interfaz debe tener el atributo AddInBaseAttribute.

    Imports System.AddIn.Pipeline
    
    Namespace CalcAddInViews
    
        ' The AddInBaseAttribute identifes this interface as the basis for the
        ' add-in view pipeline segment.
        <AddInBaseAttribute()> _
        Public Interface ICalculator
    
            Function Add(ByVal a As Double, ByVal b As Double) As Double
            Function Subtract(ByVal a As Double, ByVal b As Double) As Double
            Function Multiply(ByVal a As Double, ByVal b As Double) As Double
            Function Divide(ByVal a As Double, ByVal b As Double) As Double
        End Interface
    
    End Namespace
    
    using System.AddIn.Pipeline;
    
    namespace CalcAddInViews 
    {
        // The AddInBaseAttribute identifes this interface as the basis for
        // the add-in view pipeline segment.
        [AddInBase()]
        public interface ICalculator 
        {
        double Add(double a, double b);
        double Subtract(double a, double b);
        double Multiply(double a, double b);
        double Divide(double a, double b);
        }
    }
    
  6. De manera opcional, compile la solución de Visual Studio.

Para crear la vista de host del complemento

  1. Agregue un nuevo proyecto denominado Calc1HVA a la solución CalculatorV1. Utilice como base la plantilla Biblioteca de clases.

  2. En el Explorador de soluciones, excluya la clase predeterminada que se agrega a los nuevos proyectos de Biblioteca de clases y agregue un nuevo elemento al proyecto, utilizando la plantilla Interfaz. En el cuadro de diálogo Agregar nuevo elemento, denomine la interfaz ICalculator.

  3. En el archivo de interfaz, utilice el código siguiente para completar la vista de host del complemento.

    Namespace CalcHVAs
    
        Public Interface ICalculator
            Function Add(ByVal a As Double, ByVal b As Double) As Double
            Function Subtract(ByVal a As Double, ByVal b As Double) As Double
            Function Multiply(ByVal a As Double, ByVal b As Double) As Double
            Function Divide(ByVal a As Double, ByVal b As Double) As Double
        End Interface
    
    End Namespace
    
    namespace CalcHVAs 
    {
        public interface ICalculator 
        {
            double Add(double a, double b);
            double Subtract(double a, double b);
            double Multiply(double a, double b);
            double Divide(double a, double b);
        }
    }
    
  4. De manera opcional, compile la solución de Visual Studio.

Crear el adaptador de conversión

Este adaptador de conversión se compone de un adaptador de vista a contrato. Este segmento de la canalización convierte los tipos de la vista de complemento al contrato.

En esta canalización, el complemento proporciona un servicio al host y los tipos fluyen del complemento al host. Dado que ningún tipo fluye del host al complemento, no es necesario incluir un adaptador de contrato a vista en el complemento de esta canalización.

Para crear el adaptador de conversión

  1. Agregue un nuevo proyecto denominado Calc1AddInSideAdapter a la solución CalculatorV1. Utilice como base la plantilla Biblioteca de clases.

  2. En el Explorador de soluciones, agregue referencias de los siguientes ensamblados al proyecto Calc1AddInSideAdapter:

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. Agregue referencias a los proyectos en los segmentos del conductor adyacentes:

    Calc1AddInView

    Calc1Contract

  4. Seleccione la referencia de cada proyecto y en Propiedades establezca Copia local en False. En Visual Basic, use la ficha Referencias de Propiedades del proyecto para establecer Copia local en False en las dos referencias del proyecto.

  5. Cambie el nombre de la clase predeterminada del proyecto CalculatorViewToContractAddInSideAdapter.

  6. En el archivo de clase, agregue referencias de espacio de nombres a System.AddIn.Pipeline.

  7. En el archivo de clases, agregue referencias de espacio de nombres a los segmentos adyacentes: CalcAddInViews y CalculatorContracts. (En Visual Basic, estas referencias de espacio de nombres son Calc1AddInView.CalcAddInViews y Calc1Contract.CalculatorContracts, a menos que haya desactivado los espacios de nombres predeterminados en sus proyectos de Visual Basic).

  8. Aplique el atributo AddInAdapterAttribute a la clase CalculatorViewToContractAddInSideAdapter para identificarla como el adaptador de conversión.

  9. Haga que la clase CalculatorViewToContractAddInSideAdapter herede ContractBase, que proporciona una implementación predeterminada de la interfaz IContract e implementa la interfaz del contrato de la canalización, ICalc1Contract.

  10. Agregue un constructor público que acepte ICalculator, almacénelo en la memoria caché en un campo privado y llame al constructor de clase base.

  11. Para implementar los miembros de ICalc1Contract, sólo necesita llamar a los miembros correspondientes de la instancia de ICalculator que se pasa al constructor y devolver los resultados. De este modo, la vista (ICalculator) se adapta al contrato (ICalc1Contract).

    En el código siguiente se muestra el adaptador de conversión completado.

    Imports System.AddIn.Pipeline
    Imports Calc1AddInView.CalcAddInViews
    Imports Calc1Contract.CalculatorContracts
    
    Namespace CalcAddInSideAdapters
    
        ' The AddInAdapterAttribute identifes this class as the add-in-side 
        ' adapter pipeline segment.
        <AddInAdapter()> _
        Public Class CalculatorViewToContractAddInSideAdapter
            Inherits ContractBase
            Implements ICalc1Contract
    
            Private _view As ICalculator
    
            Public Sub New(ByVal view As ICalculator)
                MyBase.New()
                _view = view
            End Sub
    
            Public Function Add(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Add
                Return _view.Add(a, b)
            End Function
    
            Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Subtract
                Return _view.Subtract(a, b)
            End Function
    
            Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Multiply
                Return _view.Multiply(a, b)
            End Function
    
            Public Function Divide(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Divide
                Return _view.Divide(a, b)
            End Function
    
        End Class
    End Namespace
    
    using System.AddIn.Pipeline;
    using CalcAddInViews;
    using CalculatorContracts;
    
    namespace CalcAddInSideAdapters 
    {
        // The AddInAdapterAttribute identifes this class as the add-in-side adapter
        // pipeline segment.
        [AddInAdapter()]
        public class CalculatorViewToContractAddInSideAdapter :
            ContractBase, ICalc1Contract 
        {
            private ICalculator _view;
    
            public CalculatorViewToContractAddInSideAdapter(ICalculator view) 
            {
                _view = view;
            }
    
            public virtual double Add(double a, double b) 
            {
                return _view.Add(a, b);
            }
    
            public virtual double Subtract(double a, double b) 
            {
                return _view.Subtract(a, b);
            }
    
            public virtual double Multiply(double a, double b) 
            {
                return _view.Multiply(a, b);
            }
    
            public virtual double Divide(double a, double b) 
            {
                return _view.Divide(a, b);
            }
        }
    }
    
  12. De manera opcional, compile la solución de Visual Studio.

Crear el adaptador del host

Este adaptador del host se compone de un adaptador de contrato a vista. Este segmento adapta el contrato a la vista de host del complemento.

En esta canalización, el complemento proporciona un servicio al host y los tipos fluyen del complemento al host. Dado que ningún tipo fluye del host al complemento, no es necesario incluir un adaptador de vista a contrato.

Si desea implementar la administración de la duración, utilice un objeto ContractHandle para asociar un token de duración al contrato. Debe mantener una referencia a este identificador para que la administración de la duración funcione. Una vez que se aplica el token, no es necesario utilizar programación adicional porque el sistema del complemento puede desechar los objetos cuando no se utilizan y hacer que estén disponibles para la recolección de elementos no utilizados. Para obtener más información, vea Administración de la duración.

Para crear el adaptador del host

  1. Agregue un nuevo proyecto denominado Calc1HostSideAdapter a la solución CalculatorV1. Utilice como base la plantilla Biblioteca de clases.

  2. En el Explorador de soluciones, agregue referencias de los siguientes ensamblados al proyecto Calc1HostSideAdapter:

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. Agregue referencias a los proyectos en los segmentos adyacentes:

    Calc1Contract

    Calc1HVA

  4. Seleccione la referencia de cada proyecto y en Propiedades establezca Copia local en False. En Visual Basic, use la ficha Referencias de Propiedades del proyecto para establecer Copia local en False en las dos referencias del proyecto.

  5. Cambie el nombre de la clase predeterminada del proyecto por CalculatorContractToViewHostSideAdapter.

  6. En el archivo de clase, agregue referencias de espacio de nombres a System.AddIn.Pipeline.

  7. En el archivo de clases, agregue referencias de espacio de nombres a los segmentos adyacentes: CalcHVAs y CalculatorContracts. (En Visual Basic, estas referencias de espacio de nombres son Calc1HVA.CalcHVAs y Calc1Contract.CalculatorContracts, a menos que haya desactivado los espacios de nombres predeterminados en sus proyectos de Visual Basic).

  8. Aplique el atributo HostAdapterAttribute a la clase CalculatorContractToViewHostSideAdapter para identificarla como el segmento del adaptador del host.

  9. Haga que la clase CalculatorContractToViewHostSideAdapter herede la interfaz que representa la vista de host del complemento: Calc1HVAs.ICalculator (Calc1HVA.CalcHVAs.ICalculator en Visual Basic).

  10. Agregue un constructor público que acepte el tipo de contrato de la canalización, ICalc1Contract. El constructor debe almacenar en memoria caché la referencia del contrato. También debe crear y almacenar en caché un nuevo objeto ContractHandle del contrato para administrar la duración del complemento.

    Nota importanteImportante

    El objeto ContractHandle resulta crítico para la administración de la duración.Si no puede mantener una referencia al objeto ContractHandle, la recolección de elementos no utilizados lo reclamará y la canalización se cerrará cuando el programa no se lo espere.Esto puede dar lugar a errores difíciles de diagnosticar, como AppDomainUnloadedException.El cierre es una etapa normal del proceso de canalización, por lo que no hay ninguna forma de que el código de administración de la duración detecte que esta condición es un error.

  11. Para implementar los miembros de ICalculator, sólo necesita llamar a los miembros correspondientes de la instancia de ICalc1Contract que se pasa al constructor y devolver los resultados. De este modo, el contrato (ICalc1Contract) se adapta a la vista (ICalculator).

    En el código siguiente se muestra el adaptador del host completado.

    Imports System.AddIn.Pipeline
    Imports Calc1Contract.CalculatorContracts
    Imports Calc1HVA.CalcHVAs
    
    Namespace CalcHostSideAdapters
    
        ' The HostAdapterAttribute identifes this class as the host-side adapter
        ' pipeline segment.
        <HostAdapterAttribute()> _
        Public Class CalculatorContractToViewHostSideAdapter
            Implements ICalculator
    
            Private _contract As ICalc1Contract
            Private _handle As System.AddIn.Pipeline.ContractHandle
    
            Public Sub New(ByVal contract As ICalc1Contract)
                    MyBase.New()
                _contract = contract
                _handle = New ContractHandle(contract)
            End Sub
    
            Public Function Add(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Add
                Return _contract.Add(a, b)
            End Function
    
            Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Subtract
                Return _contract.Subtract(a, b)
            End Function
    
            Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Multiply
                Return _contract.Multiply(a, b)
            End Function
    
            Public Function Divide(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Divide
                Return _contract.Divide(a, b)
            End Function
    
        End Class
    
    End Namespace
    
    using System.AddIn.Pipeline;
    using CalcHVAs;
    using CalculatorContracts;
    
    namespace CalcHostSideAdapters 
    {
        // The HostAdapterAttribute identifes this class as the host-side adapter
        // pipeline segment.
        [HostAdapterAttribute()]
        public class CalculatorContractToViewHostSideAdapter : ICalculator 
        {
            private ICalc1Contract _contract;
            private System.AddIn.Pipeline.ContractHandle _handle;
    
            public CalculatorContractToViewHostSideAdapter(ICalc1Contract contract) 
            {
                _contract = contract;
                _handle = new ContractHandle(contract);
            }
    
            public double Add(double a, double b) 
            {
                return _contract.Add(a, b);
            }
    
            public double Subtract(double a, double b) 
            {
                return _contract.Subtract(a, b);
            }
    
            public double Multiply(double a, double b) 
            {
                return _contract.Multiply(a, b);
            }
    
            public double Divide(double a, double b) 
            {
                return _contract.Divide(a, b);
            }
        }
    }
    
  12. De manera opcional, compile la solución de Visual Studio.

Crear el host

Una aplicación host interactúa con el complemento a través de la vista de host del complemento. Utiliza los métodos de detección y activación de complementos proporcionados por las clases AddInStore y AddInToken para realizar las operaciones siguientes:

  • Actualizar de nuevo la memoria caché de canalización y la información del complemento.

  • Buscar complementos del tipo de la vista de host, ICalculator, bajo el directorio raíz de la canalización especificado.

  • Preguntar al usuario si desea especificar qué complemento va a utilizar.

  • Activar el complemento seleccionado en un nuevo dominio de aplicación con un nivel de confianza de seguridad especificado.

  • Ejecutar el método RunCalculator personalizado, que llama a los métodos del complemento en función de las especificaciones de la vista de host del complemento.

Para crear el host

  1. Agregue un nuevo proyecto denominado Calc1Host a la solución CalculatorV1. Utilice como base la plantilla Aplicación de consola.

  2. En el Explorador de soluciones, agregue una referencia del ensamblado System.AddIn.dll al proyecto Calc1Host.

  3. Agregue una referencia de proyecto al proyecto Calc1HVA. Seleccione la referencia del proyecto y en Propiedades establezca Copia local en False. En Visual Basic, use la ficha Referencias de Propiedades del proyecto para establecer Copia local en False.

  4. Cambie el nombre del archivo de clase (módulo en Visual Basic) por MathHost1.

  5. En Visual Basic, utilice la ficha Aplicación del cuadro de diálogo Propiedades del proyecto para establecer Objeto de inicio en Sub Main.

  6. En el archivo de clase o módulo, agregue una referencia de espacio de nombres a System.AddIn.Hosting.

  7. En el archivo de clase o módulo, agregue una referencia de espacio de nombres a la vista de host del complemento: CalcHVAs. (En Visual Basic, esta referencia de espacio de nombres es Calc1HVA.CalcHVAs, a menos que haya desactivado los espacios de nombres predeterminados en sus proyectos de Visual Basic).

  8. En el Explorador de soluciones, seleccione la solución y en el menú Proyecto, elija Propiedades. En el cuadro de diálogo Páginas de propiedades de la solución, establezca Proyecto de inicio único para que sea este proyecto de aplicación host.

  9. En el archivo de clase o módulo, utilice el método AddInStore.Update para actualizar la memoria caché. Utilice el método AddInStore.FindAddIn para obtener una colección de tokens y utilice el método AddInToken.Activate para activar un complemento.

    En el código siguiente se muestra la aplicación host completada.

    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.AddIn.Hosting
    Imports Calc1HVA.CalcHVAs
    
    Namespace MathHost
    
        Module MathHost1
    
            Sub Main()
                ' Assume that the current directory is the application folder, 
                ' and that it contains the pipeline folder structure.
                Dim addInRoot As String = Environment.CurrentDirectory & "\Pipeline"
    
                ' Update the cache files of the pipeline segments and add-ins.
                Dim warnings() As String = AddInStore.Update(addInRoot)
                For Each warning As String In warnings
                    Console.WriteLine(warning)
                Next
    
                ' Search for add-ins of type ICalculator (the host view of the add-in).
                Dim tokens As System.Collections.ObjectModel.Collection(Of AddInToken) = _
                    AddInStore.FindAddIns(GetType(ICalculator), addinRoot)
    
                ' Ask the user which add-in they would like to use.
                Dim calcToken As AddInToken = ChooseCalculator(tokens)
    
                ' Activate the selected AddInToken in a new application domain 
                ' with the Internet trust level.
                Dim calc As ICalculator = _
                    calcToken.Activate(Of ICalculator)(AddInSecurityLevel.Internet)
    
                ' Run the add-in.
                RunCalculator(calc)
            End Sub
    
            Private Function ChooseCalculator(ByVal tokens As Collection(Of AddInToken)) _
                    As AddInToken
    
                If (tokens.Count = 0) Then
                    Console.WriteLine("No calculators are available")
                    Return Nothing
                End If
    
                Console.WriteLine("Available Calculators: ")
                ' Show the token properties for each token in the AddInToken collection
                ' (tokens), preceded by the add-in number in [] brackets.
                Dim tokNumber As Integer = 1
                For Each tok As AddInToken In tokens
                    Console.WriteLine(vbTab & "[{0}]: {1} - {2}" & _
                            vbLf & vbTab & "{3}" & _
                            vbLf & vbTab & "{4}" & _
                            vbLf & vbTab & "{5} - {6}", _
                            tokNumber.ToString, tok.Name, _
                            tok.AddInFullName, tok.AssemblyName, _
                            tok.Description, tok.Version, tok.Publisher)
                    tokNumber = tokNumber + 1
                Next
                Console.WriteLine("Which calculator do you want to use?")
                Dim line As String = Console.ReadLine
                Dim selection As Integer
                If Int32.TryParse(line, selection) Then
                    If (selection <= tokens.Count) Then
                        Return tokens((selection - 1))
                    End If
                End If
                Console.WriteLine("Invalid selection: {0}. Please choose again.", line)
                Return ChooseCalculator(tokens)
            End Function
    
            Private Sub RunCalculator(ByVal calc As ICalculator)
                If IsNothing(calc) Then
                    'No calculators were found, read a line and exit.
                    Console.ReadLine()
                End If
                Console.WriteLine("Available operations: +, -, *, /")
                Console.WriteLine("Request a calculation , such as: 2 + 2")
                Console.WriteLine("Type 'exit' to exit")
                Dim line As String = Console.ReadLine
    
                While Not line.Equals("exit")
                    ' The Parser class parses the user's input.
                    Try
                        Dim c As Parser = New Parser(line)
                        Select Case (c.action)
                            Case "+"
                                Console.WriteLine(calc.Add(c.a, c.b))
                            Case "-"
                                Console.WriteLine(calc.Subtract(c.a, c.b))
                            Case "*"
                                Console.WriteLine(calc.Multiply(c.a, c.b))
                            Case "/"
                                Console.WriteLine(calc.Divide(c.a, c.b))
                            Case Else
                                Console.WriteLine("{0} is an invalid command. Valid commands are +,-,*,/", c.action)
                        End Select
                    Catch Ex As System.Exception
                        Console.WriteLine("Invalid command: {0}. Commands must be formated: [number] [operation] [number]", line)
                    End Try
                    line = Console.ReadLine
    
                End While
            End Sub
        End Module
    
        Class Parser
    
            Public partA As Double
            Public partB As Double
            Public action As String
    
            Friend Sub New(ByVal line As String)
                MyBase.New()
                Dim parts() As String = line.Split(" ")
                partA = Double.Parse(parts(0))
                action = parts(1)
                partB = Double.Parse(parts(2))
            End Sub
    
            Public ReadOnly Property A() As Double
                Get
                    Return partA
                End Get
            End Property
    
            Public ReadOnly Property B() As Double
                Get
                    Return partB
                End Get
            End Property
    
            Public ReadOnly Property CalcAction() As String
                Get
                    Return Action
                End Get
            End Property
        End Class
    
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.AddIn.Hosting;
    using CalcHVAs;
    
    namespace MathHost
    {
        class Program
        {
            static void Main()
            {
                // Assume that the current directory is the application folder, 
                // and that it contains the pipeline folder structure.
                String addInRoot = Environment.CurrentDirectory + "\\Pipeline";
    
                // Update the cache files of the pipeline segments and add-ins.
                string[] warnings = AddInStore.Update(addInRoot);
                foreach (string warning in warnings)
                {
                    Console.WriteLine(warning);
                }
    
                // Search for add-ins of type ICalculator (the host view of the add-in).
                Collection<AddInToken> tokens = 
                    AddInStore.FindAddIns(typeof(ICalculator), addInRoot);
    
                // Ask the user which add-in they would like to use.
                AddInToken calcToken = ChooseCalculator(tokens);
    
                // Activate the selected AddInToken in a new application domain 
                // with the Internet trust level.
                ICalculator calc = 
                    calcToken.Activate<ICalculator>(AddInSecurityLevel.Internet);
    
                // Run the add-in.
                RunCalculator(calc);
            }
    
            private static AddInToken ChooseCalculator(Collection<AddInToken> tokens)
            {
                if (tokens.Count == 0)
                {
                    Console.WriteLine("No calculators are available");
                    return null;
                }
                Console.WriteLine("Available Calculators: ");
                // Show the token properties for each token in the AddInToken collection 
                // (tokens), preceded by the add-in number in [] brackets.
                int tokNumber = 1;
                foreach (AddInToken tok in tokens)
                {
                    Console.WriteLine(String.Format("\t[{0}]: {1} - {2}\n\t{3}\n\t\t {4}\n\t\t {5} - {6}",
                        tokNumber.ToString(),
                        tok.Name,
                        tok.AddInFullName,
                        tok.AssemblyName,
                        tok.Description,
                        tok.Version,
                        tok.Publisher));
                    tokNumber++;
                }
                Console.WriteLine("Which calculator do you want to use?");
                String line = Console.ReadLine();
                int selection;
                if (Int32.TryParse(line, out selection))
                {
                    if (selection <= tokens.Count)
                    {
                        return tokens[selection - 1];
                    }
                }
                Console.WriteLine("Invalid selection: {0}. Please choose again.", line);
                return ChooseCalculator(tokens);
            }
    
            private static void RunCalculator(ICalculator calc)
            {
    
                if (calc == null)
                {
                    //No calculators were found; read a line and exit.
                    Console.ReadLine();
                }
                Console.WriteLine("Available operations: +, -, *, /");
                Console.WriteLine("Request a calculation , such as: 2 + 2");
                Console.WriteLine("Type \"exit\" to exit");
                String line = Console.ReadLine();
                while (!line.Equals("exit"))
                {
                    // The Parser class parses the user's input.
                    try
                    {
                        Parser c = new Parser(line);
                        switch (c.Action)
                        {
                            case "+":
                                Console.WriteLine(calc.Add(c.A, c.B));
                                break;
                            case "-":
                                Console.WriteLine(calc.Subtract(c.A, c.B));
                                break;
                            case "*":
                                Console.WriteLine(calc.Multiply(c.A, c.B));
                                break;
                            case "/":
                                Console.WriteLine(calc.Divide(c.A, c.B));
                                break;
                            default:
                                Console.WriteLine("{0} is an invalid command. Valid commands are +,-,*,/", c.Action);
                                break;
                        }
                    }
                    catch
                    {
                        Console.WriteLine("Invalid command: {0}. Commands must be formated: [number] [operation] [number]", line);
                    }
    
                    line = Console.ReadLine();
                }
            }
        }
    
        internal class Parser
        {
            double a;
            double b;
            string action;
    
            internal Parser(string line)
            {
                string[] parts = line.Split(' ');
                a = double.Parse(parts[0]);
                action = parts[1];
                b = double.Parse(parts[2]);
            }
    
            public double A
            {
                get { return a; }
            }
    
            public double B
            {
                get { return b; }
            }
    
            public string Action
            {
                get { return action; }
            }
        }
    }
    
    NotaNota

    En este código se presupone que la estructura de carpetas de la canalización se encuentra en la carpeta de la aplicación.Si, por el contrario, se encuentra en otra ubicación, cambie la línea de código en la que se establece la variable addInRoot para que la variable contenga la ruta de acceso a la estructura de directorios de la canalización.

    El código utiliza un método ChooseCalculator para hacer una lista de los tokens y solicitar al usuario que elija un complemento. El método RunCalculator solicita al usuario que escriba expresiones matemáticas simples, analiza las expresiones utilizando la clase Parser y muestra los resultados devueltos por el complemento.

  10. De manera opcional, compile la solución de Visual Studio.

Crear el complemento

Un complemento implementa los métodos especificados por la vista de complemento. Este complemento implementa las operaciones Add, Subtract, Multiply y Divide y devuelve los resultados al host.

Para crear el complemento

  1. Agregue un nuevo proyecto denominado AddInCalcV1 a la solución CalculatorV1. Utilice como base la plantilla Biblioteca de clases.

  2. En el Explorador de soluciones, agregue una referencia del ensamblado System.AddIn.dll al proyecto.

  3. Agregue una referencia al proyecto Calc1AddInView. Seleccione la referencia del proyecto y en Propiedades, establezca Copia local en False. En Visual Basic, use la ficha Referencias de Propiedades del proyecto para establecer Copia local en False en la referencia del proyecto.

  4. Cambie el nombre de la clase a AddInCalcV1.

  5. En el archivo de clase, agregue una referencia de espacio de nombres a System.AddIn y el segmento de la vista de complemento: CalcAddInViews (Calc1AddInView.CalcAddInViews en Visual Basic).

  6. Aplique el atributo AddInAttribute a la clase AddInCalcV1 para identificar la clase como un complemento.

  7. Haga que la clase AddInCalcV1 implemente la interfaz que representa la vista de complemento: CalcAddInViews.ICalculator (Calc1AddInView.CalcAddInViews.ICalculator en Visual Basic).

  8. Para implementar los miembros de ICalculator, devuelva los resultados de los cálculos pertinentes.

    En el código siguiente se muestra el complemento completado.

    Imports System.AddIn
    Imports Calc1AddInView.CalcAddInViews
    
    Namespace CalcAddIns
    
        ' The AddInAttribute identifies this pipeline segment as an add-in.
        <AddIn("Calculator AddIn", Version:="1.0.0.0")> _
        Public Class AddInCalcV1
            Implements ICalculator
    
            Public Function Add(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Add
                Return (a + b)
            End Function
    
            Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Subtract
                Return (a - b)
            End Function
    
            Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Multiply
                Return (a * b)
            End Function
    
            Public Function Divide(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Divide
                Return (a / b)
            End Function
        End Class
    
    End Namespace
    
    using System.Collections.Generic;
    using System.AddIn;
    using CalcAddInViews;
    
    namespace CalcAddIns
    {
        // The AddInAttribute identifies this pipeline segment as an add-in.
        [AddIn("Calculator AddIn",Version="1.0.0.0")]
        public class AddInCalcV1 : ICalculator
        {
            public double Add(double a, double b)
            {
                return a + b;
            }
    
            public double Subtract(double a, double b)
            {
                return a - b;
            }
    
            public double Multiply(double a, double b)
            {
                return a * b;
            }
    
            public double Divide(double a, double b)
            {
                return a / b;
            }
        }
    }
    
  9. De manera opcional, compile la solución de Visual Studio.

Implementar la canalización

Ya está listo para compilar e implementar los segmentos de los complementos en la estructura de directorios de canalización requerida.

Para implementar los segmentos en la canalización

  1. En cada proyecto de la solución, utilice la ficha Generar de Propiedades del proyecto (la ficha Compilar en Visual Basic) para establecer el valor de Ruta de acceso de los resultados (Ruta de acceso de los resultados de la compilación en Visual Basic). Si, por ejemplo, denominara a su carpeta de aplicación MyApp, sus proyectos se compilarían en las carpetas siguientes:

    Proyecto

    Ruta de acceso

    AddInCalcV1

    MyApp\Pipeline\AddIns\CalcV1

    Calc1AddInSideAdapter

    MyApp\Pipeline\AddInSideAdapters

    Calc1AddInView

    MyApp\Pipeline\AddInViews

    Calc1Contract

    MyApp\Pipeline\Contracts

    Calc1Host

    MyApp

    Calc1HostSideAdapter

    MyApp\Pipeline\HostSideAdapters

    Calc1HVA

    MyApp

    NotaNota

    Si decidió poner la estructura de carpetas de la canalización en una ubicación distinta a la carpeta de la aplicación, deberá modificar las rutas de acceso que aparecen en la tabla como corresponda.Vea los comentarios sobre los requisitos de los directorios de la canalización en Requisitos del desarrollo de canalizaciones.

  2. Compile la solución de Visual Studio.

  3. Compruebe los directorios de la canalización y la aplicación para asegurarse de que los ensamblados se copiaron en los directorios correctos y de que no se instaló ninguna copia adicional de los ensamblados en carpetas equivocadas.

    NotaNota

    Si no cambió Copia local a False en la referencia Calc1AddInView del proyecto AddInCalcV1, los problemas contextuales del programa de carga impedirán que se pueda encontrar el complemento.

    Para obtener información acerca de cómo se realiza la implementación en la canalización, vea Requisitos del desarrollo de canalizaciones.

Ejecutar la aplicación host

Ya está listo para ejecutar el host e interactuar con el complemento.

Para ejecutar la aplicación host

  1. En el símbolo del sistema, vaya al directorio de la aplicación y ejecute la aplicación host, Calc1Host.exe.

  2. El host busca todos los complementos disponibles de su tipo y le solicita que seleccione un complemento. Escriba 1 para el único complemento disponible.

  3. Escriba una ecuación para la calculadora, como 2 + 2. Debe dejar espacios entre los números y el operador.

  4. Escriba exit y presione la tecla Entrar para cerrar la aplicación.

Vea también

Tareas

Tutorial: Habilitar la compatibilidad con versiones anteriores al cambiar el host

Tutorial: Pasar colecciones entre hosts y complementos

Conceptos

Requisitos del desarrollo de canalizaciones

Contratos, vistas y adaptadores

Desarrollo de canalizaciones