Procedura dettagliata: passaggio di insiemi tra host e componenti aggiuntivi

In questa procedura dettagliata viene descritto come creare una pipeline che passa un insieme di oggetti personalizzati tra un componente aggiuntivo e un host. Poiché i tipi nell'insieme non sono serializzabili, è necessario aggiungere ulteriori classi per la definizione di adattatori visualizzazione-contratto e contratto-visualizzazione ai segmenti di adattatore, in modo da consentire al flusso di tipi di superare il limite di isolamento.

In questo scenario il componente aggiuntivo aggiorna un insieme di oggetti libro per l'host. Ogni oggetto libro contiene metodi che consentono di ottenere e impostare il titolo del libro, l'editore, il prezzo e altri dati.

A scopo esemplificativo, l'host crea un insieme di libri; il componente aggiuntivo riduce del 20% il prezzo di tutti i libri di informatica e rimuove tutti i libri di orrore dall'insieme. Il componente aggiuntivo crea quindi un nuovo oggetto libro per il libro di maggior successo e lo passa all'host come singolo oggetto.

In questa procedura dettagliata vengono illustrate le attività seguenti:

  • Creazione di una soluzione di Visual Studio.

  • Creazione della struttura di directory della pipeline.

  • Creazione dei contratti e delle visualizzazioni per gli oggetti da passare nelle due direzioni attraverso il limite di isolamento.

  • Creazione degli adattatori sul lato componente aggiuntivo e sul lato host richiesti per consentire agli oggetti il passaggio attraverso il limite di isolamento.

  • Creazione dell'host.

  • Creazione del componente aggiuntivo.

  • Distribuzione della pipeline.

  • Esecuzione dell'applicazione host.

NotaNota

Parte del codice mostrato in questa procedura dettagliata contiene riferimenti a spazi dei nomi estranei.I passaggi della procedura dettagliata riflettono accuratamente i riferimenti richiesti in Visual Studio.

Per ulteriori esempi di codice e anteprime di tecnologie di clienti riguardanti strumenti di compilazione di pipeline per componenti aggiuntivi, vedere Managed Extensibility and Add-In Framework on CodePlex (informazioni in lingua inglese).

Prerequisiti

Per completare la procedura dettagliata, è necessario disporre dei componenti seguenti:

Creazione di una soluzione di Visual Studio

Per contenere i progetti dei segmenti di pipeline, utilizzare una soluzione di Visual Studio.

Per creare la soluzione della pipeline

  1. In Visual Studio creare un nuovo progetto denominato LibraryContracts, basandolo sul modello Libreria di classi.

  2. Assegnare alla soluzione il nome BooksPipeline.

Creazione della struttura di directory della pipeline

Il modello del componente aggiuntivo richiede che gli assembly dei segmenti di pipeline siano inseriti in una struttura di directory specificata.

Per creare la struttura di directory della pipeline

  • Creare la struttura di cartelle seguente nel computer in uso. È possibile inserirla in qualsiasi percorso, anche all'interno delle cartelle della soluzione di Visual Studio.

    Pipeline
      AddIns
        BooksAddIn
      AddInSideAdapters
      AddInViews
      Contracts
      HostSideAdapters
    

    Tutti i nomi delle cartelle devono essere specificati esattamente come indicato, fatta eccezione per il nome della cartella radice e i nomi delle cartelle dei singoli componenti aggiuntivi. In questo esempio vengono utilizzati Pipeline come nome della cartella radice e BooksAddIn come nome della cartella del componente aggiuntivo.

    NotaNota

    Per motivi di praticità, nella procedura dettagliata l'applicazione host viene posizionata nella cartella radice della pipeline.Nel passaggio appropriato della procedura dettagliata viene illustrato come modificare il codice se l'applicazione è in un percorso diverso.

    Per ulteriori informazioni sulla struttura di cartelle della pipeline, vedere Requisiti di sviluppo delle pipeline.

Creazione del contratto e delle visualizzazioni

Nel segmento di contratto di questa pipeline vengono definite due interfacce:

  • Interfaccia IBookInfoContract.

    Questa interfaccia contiene i metodi, ad esempio Author, con le informazioni relative a un libro.

  • Interfaccia ILibraryManagerContract.

    Questa interfaccia contiene il metodo ProcessBooks utilizzato dal componente aggiuntivo per elaborare un insieme di libri. Ogni libro rappresenta un contratto IBookInfoContract. Nell'interfaccia è inoltre incluso il metodo GetBestSeller utilizzato dal componente aggiuntivo per fornire all'host un oggetto libro che rappresenta il libro di maggior successo.

Per creare il contratto

  1. Nella soluzione di Visual Studio denominata BooksPipeline aprire il progetto LibraryContracts.

  2. In Visual Basic, aprire Proprietà per il progetto LibraryContracts e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice. Per impostazione predefinita, Spazio dei nomi radice è impostato sul nome del progetto.

  3. In Esplora soluzioni aggiungere riferimenti ai seguenti assembly per il progetto.

    System.AddIn.Contract.dll

    System.AddIn.dll

  4. Nel file di classe aggiungere riferimenti agli spazi dei nomi System.AddIn.Contract e System.AddIn.Pipeline.

  5. Nel file di classe, sostituire la dichiarazione della classe predefinita con due interfacce:

    • L'interfaccia ILibraryManagerContract viene utilizzata per attivare il componente aggiuntivo, pertanto deve disporre dell'attributo AddInContractAttribute.

    • L'interfaccia IBookInfoContract rappresenta un oggetto passato tra l'host e il componente aggiuntivo, pertanto non richiede l'attributo.

    Entrambe le interfacce devono ereditare l'interfaccia IContract.

  6. Utilizzare il codice seguente per aggiungere le interfacce IBookInfoContract e ILibraryManagerContract.

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.AddIn.Pipeline
    Imports System.AddIn.Contract
    Namespace Library
    <AddInContract> _
    Public Interface ILibraryManagerContract
    Inherits IContract
        ' Pass a collection of books,
        ' of type IBookInfoContract
        ' to the add-in for processing.
        Sub ProcessBooks(ByVal books As IListContract(Of IBookInfoContract))
    
        ' Get a IBookInfoContract object
        ' from the add-in of the
        ' the best selling book.
        Function GetBestSeller() As IBookInfoContract
    
        ' This method has has arbitrary
        ' uses and shows how you can
        ' mix serializable and custom types.
        Function Data(ByVal txt As String) As String
    End Interface
    
    ' Contains infomration about a book.
    Public Interface IBookInfoContract
    Inherits IContract
        Function ID() As String
        Function Author() As String
        Function Title() As String
        Function Genre() As String
        Function Price() As String
        Function Publish_Date() As String
        Function Description() As String
    End Interface
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.AddIn.Pipeline;
    using System.AddIn.Contract;
    namespace Library
    {
        [AddInContract]
        public interface ILibraryManagerContract : IContract
        {
            // Pass a collection of books,
            // of type IBookInfoContract
            // to the add-in for processing.
            void ProcessBooks(IListContract<IBookInfoContract> books);
    
            // Get a IBookInfoContract object
            // from the add-in of the
            // the best selling book.
            IBookInfoContract GetBestSeller();
    
            // This method has has arbitrary
            // uses and shows how you can
            // mix serializable and custom types.
            string Data(string txt);
        }
    
        // Contains infomration about a book.
        public interface IBookInfoContract : IContract
        {
            string ID();
            string Author();
            string Title();
            string Genre();
            string Price();
            string Publish_Date();
            string Description();
        }
    }
    

Poiché la visualizzazione del componente aggiuntivo e la visualizzazione host condividono lo stesso codice, è possibile crearle con facilità contemporaneamente. Tali visualizzazioni differiscono per un solo fattore: la visualizzazione del componente aggiuntivo che viene utilizzata per attivare questo segmento della pipeline richiede l'attributo AddInBaseAttribute, mentre la visualizzazione host non richiede attributi.

La visualizzazione del componente aggiuntivo per questa pipeline contiene due classi astratte. La classe BookInfo fornisce la visualizzazione per l'interfaccia IBookInfoContract, mentre la classe LibraryManager fornisce la visualizzazione per l'interfaccia ILibraryManagerContract.

Per creare la visualizzazione del componente aggiuntivo

  1. Aggiungere un nuovo progetto denominato AddInViews alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.

  2. In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.

  3. In Esplora soluzioni aggiungere un riferimento a System.AddIn.dll per il progetto AddInViews.

  4. Rinominare la classe predefinita LibraryManager del progetto e rendere la classe abstract (MustInherit in Visual Basic).

  5. Nel file di classe aggiungere un riferimento allo spazio dei nomi System.AddIn.Pipeline.

  6. La classe LibraryManager viene utilizzata per attivare la pipeline, pertanto è necessario applicare l'attributo AddInBaseAttribute.

  7. Utilizzare il codice seguente per completare la classe astratta LibraryManager.

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsBase
    ' The AddInBaseAttribute
    ' identifes this pipeline
    ' segment as an add-in view.
    <AddInBase> _
    Public MustInherit Class LibraryManager
        Public MustOverride Sub ProcessBooks(ByVal books As IList(Of BookInfo))
        Public MustOverride Function GetBestSeller() As BookInfo
    
        Public MustOverride Function Data(ByVal txt As String) As String
    End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.AddIn.Pipeline;
    namespace LibraryContractsBase
    {
    // The AddInBaseAttribute
    // identifes this pipeline
    // segment as an add-in view.
    [AddInBase]
        public abstract class LibraryManager
        {
            public abstract void ProcessBooks(IList<BookInfo> books);
            public abstract BookInfo GetBestSeller();
    
            public abstract string Data(string txt);
        }
    }
    
  8. Aggiungere una classe abstract (classeMustInherit in Visual Basic) al progetto e denominarla BookInfo. La classe BookInfo rappresenta un oggetto passato tra l'host e il componente aggiuntivo. Questa classe non viene utilizzata per attivare la pipeline, pertanto non richiede attributi.

  9. Utilizzare il codice seguente per completare la classe astratta BookInfo.

    
    Imports Microsoft.VisualBasic
    Imports System
    Namespace LibraryContractsBase
    
    Public MustInherit Class BookInfo
    
        Public MustOverride Function ID() As String
        Public MustOverride Function Author() As String
        Public MustOverride Function Title() As String
        Public MustOverride Function Genre() As String
        Public MustOverride Function Price() As String
        Public MustOverride Function Publish_Date() As String
        Public MustOverride Function Description() As String
    End Class
    End Namespace
    
    using System;
    namespace LibraryContractsBase {
    
        public abstract class BookInfo {
    
            public abstract string ID();
            public abstract string Author();
            public abstract string Title();
            public abstract string Genre();
            public abstract string Price();
            public abstract string Publish_Date();
            public abstract string Description();
        }
    }
    

Per creare la visualizzazione host

  1. Aggiungere un nuovo progetto denominato HostViews alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.

  2. In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.

  3. Rinominare la classe predefinita LibraryManager del progetto e rendere la classe abstract (MustInherit in Visual Basic).

  4. Utilizzare il codice seguente per completare la classe astratta LibraryManager.

    
    Imports Microsoft.VisualBasic
    Imports System.Collections.Generic
    Namespace LibraryContractsHAV
    
    Public MustInherit Class LibraryManager
    
    Public MustOverride Sub ProcessBooks(ByVal books As System.Collections.Generic.IList(Of BookInfo))
    Public MustOverride Function GetBestSeller() As BookInfo
    
    Public MustOverride Function Data(ByVal txt As String) As String
    End Class
    End Namespace
    
    using System.Collections.Generic;
    namespace LibraryContractsHAV {
    
    public abstract class LibraryManager
    {
    
        public abstract void ProcessBooks(System.Collections.Generic.IList<BookInfo> books);
        public abstract BookInfo GetBestSeller();
    
        public abstract string Data(string txt);
    }
    }
    
  5. Aggiungere una classe abstract (classeMustInherit in Visual Basic) al progetto e denominarla BookInfo.

  6. Utilizzare il codice seguente per completare la classe astratta BookInfo.

    
    Imports Microsoft.VisualBasic
    Imports System
    Namespace LibraryContractsHAV
        Public MustInherit Class BookInfo
    
            Public MustOverride Function ID() As String
            Public MustOverride Function Author() As String
            Public MustOverride Function Title() As String
            Public MustOverride Function Genre() As String
            Public MustOverride Function Price() As String
            Public MustOverride Function Publish_Date() As String
            Public MustOverride Function Description() As String
        End Class
    End Namespace
    
    namespace LibraryContractsHAV
    {
        public abstract class BookInfo
        {
    
            public abstract string ID();
            public abstract string Author();
            public abstract string Title();
            public abstract string Genre();
            public abstract string Price();
            public abstract string Publish_Date();
            public abstract string Description();
        }
    }
    

Creazione dell'adattatore sul lato componente aggiuntivo

L'assembly dell'adattatore sul lato componente aggiuntivo per questa pipeline contiene quattro classi di adattatore:

  • BookInfoContractToViewAddInAdapter

    Questo adattatore viene chiamato quando l'host passa un oggetto BookInfo al componente aggiuntivo, sia da solo o come parte di un insieme. Questa classe converte il contratto dell'oggetto BookInfo in una visualizzazione. La classe eredita dalla visualizzazione del componente aggiuntivo e implementa i metodi astratti chiamando il contratto passato al costruttore della classe.

    Poiché il costruttore di questo adattatore accetta un contratto, è possibile applicare un oggetto ContractHandle al contratto per implementare la gestione della durata.

    Nota importanteImportante

    L'oggetto ContractHandle è di importanza fondamentale nella gestione della durata.Se non si riesce a mantenere un riferimento all'oggetto ContractHandle, quest'ultimo verrà recuperato dalla Garbage Collection e la pipeline verrà interrotta in un momento non previsto dal programma.Ciò può comportare errori difficili da diagnosticare, ad esempio AppDomainUnloadedException.L'arresto è una fase normale del ciclo di vita di una pipeline. Pertanto, non esiste alcun modo in cui il codice di gestione della durata sia in grado di rilevare questa condizione come un errore.

  • BookInfoViewToContractAddInAdapter

    Questo adattatore viene chiamato quando il componente aggiuntivo passa un oggetto BookInfo all'host. Questa classe converte la visualizzazione del componente aggiuntivo dell'oggetto BookInfo in un contratto. La classe eredita dal contratto e lo implementa chiamando la visualizzazione del componente aggiuntivo passata al costruttore della classe. Viene effettuato il marshalling di questo adattatore all'host come contratto.

  • LibraryManagerViewToContractAddInAdapter

    Si tratta del tipo restituito all'host dalla chiamata per attivare il componente aggiuntivo. Questo tipo viene chiamato quando l'host chiama il componente aggiuntivo, inclusa la chiamata che passa un insieme di oggetti host (IList<BookInfo>) al componente aggiuntivo. Questa classe converte il contratto ILibraryManagerContract nella visualizzazione host LibraryManager. La classe eredita dalla visualizzazione host e implementa il contratto chiamando la visualizzazione che viene passata al relativo costruttore.

    Poiché è necessario effettuare il marshalling di un insieme di tipi personalizzati, ovvero gli oggetti BookInfo, oltre il limite di isolamento, questo adattatore utilizza la classe CollectionAdapters. Questa classe fornisce i metodi per convertire un insieme IList<T> in un insieme IListContract<T>, in modo da consentire il passaggio dell'insieme oltre il limite di isolamento all'altro lato della pipeline.

  • BookInfoAddInAdapter

    I metodi static (metodi Shared in Visual Basic) di questo adattatore vengono chiamati dalla classe LibraryManagerViewToContractAddInAdapter per adattare un contratto o una visualizzazione o per restituire un contratto o una visualizzazione esistente. In questo modo si evita la creazione di un adattatore aggiuntivo quando un oggetto effettua un round trip tra l'host e il componente aggiuntivo.

Per creare l'adattatore sul lato componente aggiuntivo

  1. Aggiungere un nuovo progetto denominato AddInSideAdapters alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.

  2. In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.

  3. In Esplora soluzioni aggiungere riferimenti ai seguenti assembly per il progetto AddInSideAdapters.

    System.AddIn.dll

    System.AddIn.Contract.dll

  4. In Esplora soluzioni aggiungere riferimenti ai seguenti progetti per il progetto AddInSideAdapters.

    AddInViews

    LibraryContracts

    Nel riferimento Proprietà impostare Copia localmente su False per questi riferimenti, per impedire la copia nella cartella di compilazione locale degli assembly cui viene fatto riferimento. Gli assembly saranno situati nella struttura della directory della pipeline, come descritto nella procedura "Distribuzione della pipeline" più avanti in questa procedura dettagliata.

  5. Denominare il file di classe BookInfoContractToViewAddInAdapter.

  6. Nel file di classe aggiungere un riferimento allo spazio dei nomi System.AddIn.Pipeline.

  7. Utilizzare il codice seguente per aggiungere la classe BookInfoContractToViewAddInAdapter. La classe non richiede attributi perché non viene utilizzata per attivare la pipeline. Il metodo GetSourceContract internal (Friend in Visual Basic) viene utilizzato dalla classe BookInfoAddInAdapter per evitare di creare un adattatore aggiuntivo quando un oggetto effettua un round trip tra l'host e il componente aggiuntivo.

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsAddInAdapters
    
    Public Class BookInfoContractToViewAddInAdapter
        Inherits LibraryContractsBase.BookInfo
        Private _contract As Library.IBookInfoContract
        Private _handle As System.AddIn.Pipeline.ContractHandle
        Public Sub New(ByVal contract As Library.IBookInfoContract)
            _contract = contract
            _handle = New ContractHandle(contract)
        End Sub
    
        Public Overrides Function ID() As String
            Return _contract.ID()
        End Function
        Public Overrides Function Author() As String
            Return _contract.Author()
        End Function
        Public Overrides Function Title() As String
            Return _contract.Title()
        End Function
        Public Overrides Function Genre() As String
            Return _contract.Genre()
        End Function
        Public Overrides Function Price() As String
            Return _contract.Price()
        End Function
        Public Overrides Function Publish_Date() As String
            Return _contract.Publish_Date()
        End Function
        Public Overrides Function Description() As String
            Return _contract.Description()
        End Function
    
        Friend Function GetSourceContract() As Library.IBookInfoContract
            Return _contract
        End Function
    End Class
    End Namespace
    
    using System;
    using System.AddIn.Pipeline;
    namespace LibraryContractsAddInAdapters 
    {
    
    public class BookInfoContractToViewAddInAdapter : LibraryContractsBase.BookInfo 
    {
        private Library.IBookInfoContract _contract;
        private System.AddIn.Pipeline.ContractHandle _handle;
        public BookInfoContractToViewAddInAdapter(Library.IBookInfoContract contract) 
        {
            _contract = contract;
            _handle = new ContractHandle(contract);
        }
    
        public override string ID()
        {
            return _contract.ID();
        }
        public override string Author()
        {
            return _contract.Author();
        }
        public override string Title()
        {
            return _contract.Title();
        }
        public override string Genre()
        {
            return _contract.Genre();
        }
        public override string Price()
        {
            return _contract.Price();
        }
        public override string Publish_Date()
        {
            return _contract.Publish_Date();
        }
        public override string Description()
        {
            return _contract.Description();
        }
    
        internal Library.IBookInfoContract GetSourceContract() {
            return _contract;
        }
    }
    }
    
  8. Utilizzare il codice seguente per aggiungere la classe BookInfoViewToContractAddInAdapter al progetto AddInSideAdapters. La classe non richiede attributi perché non viene utilizzata per attivare la pipeline. Il metodo GetSourceView internal (Friend in Visual Basic) viene utilizzato dalla classe BookInfoAddInAdapter per evitare di creare un adattatore aggiuntivo quando un oggetto effettua un round trip tra l'host e il componente aggiuntivo.

    
    Imports Microsoft.VisualBasic
    Imports System
    
    Namespace LibraryContractsAddInAdapters
    Public Class BookInfoViewToContractAddInAdapter
        Inherits System.AddIn.Pipeline.ContractBase
        Implements Library.IBookInfoContract
        Private _view As LibraryContractsBase.BookInfo
        Public Sub New(ByVal view As LibraryContractsBase.BookInfo)
            _view = view
        End Sub
        Public Overridable Function ID() As String Implements Library.IBookInfoContract.ID
            Return _view.ID()
        End Function
        Public Overridable Function Author() As String Implements Library.IBookInfoContract.Author
            Return _view.Author()
        End Function
        Public Overridable Function Title() As String Implements Library.IBookInfoContract.Title
            Return _view.Title()
        End Function
        Public Overridable Function Genre() As String Implements Library.IBookInfoContract.Genre
            Return _view.Genre()
        End Function
        Public Overridable Function Price() As String Implements Library.IBookInfoContract.Price
            Return _view.Price()
        End Function
        Public Overridable Function Publish_Date() As String Implements Library.IBookInfoContract.Publish_Date
            Return _view.Publish_Date()
        End Function
        Public Overridable Function Description() As String Implements Library.IBookInfoContract.Description
            Return _view.Description()
        End Function
    
        Friend Function GetSourceView() As LibraryContractsBase.BookInfo
            Return _view
        End Function
    End Class
    End Namespace
    
    using System;
    
    namespace LibraryContractsAddInAdapters 
    {
    public class BookInfoViewToContractAddInAdapter : System.AddIn.Pipeline.ContractBase, Library.IBookInfoContract 
    {
        private LibraryContractsBase.BookInfo _view;
        public BookInfoViewToContractAddInAdapter(LibraryContractsBase.BookInfo view) 
        {
            _view = view;
        }
        public virtual string ID()
        {
            return _view.ID();
        }
        public virtual string Author()
        {
            return _view.Author();
        }
        public virtual string Title()
        {
            return _view.Title();
        }
        public virtual string Genre()
        {
            return _view.Genre();
        }
        public virtual string Price()
        {
            return _view.Price();
        }
        public virtual string Publish_Date()
        {
            return _view.Publish_Date();
        }
        public virtual string Description()
        {
            return _view.Description();
        }
    
        internal LibraryContractsBase.BookInfo GetSourceView() {
            return _view;
        }
    }
    }
    
  9. Utilizzare il codice seguente per aggiungere la classe LibraryManagerViewToContractAddInAdapter al progetto AddInSideAdapters. Questa classe richiede l'attributo AddInAdapterAttribute perché viene utilizzata per attivare la pipeline.

    Il metodo ProcessBooks mostra come passare un elenco di libri attraverso il limite di isolamento. Utilizza il metodo CollectionAdapters.ToIList per convertire l'elenco. Per convertire gli oggetti nell'elenco passa i delegati dei metodi dell'adattatore forniti dalla classe BookInfoAddInAdapter.

    Il metodo GetBestSeller mostra come passare un singolo oggetto BookInfo attraverso il limite di isolamento.

    
    Imports Microsoft.VisualBasic
    Imports System.AddIn.Pipeline
    Imports System.AddIn.Contract
    Imports System.Collections.Generic
    Namespace LibraryContractsAddInAdapters
    ' The AddInAdapterAttribute
    ' identifes this pipeline
    ' segment as an add-in-side adapter.
    <AddInAdapter> _
    Public Class LibraryManagerViewToContractAddInAdapter
        Inherits System.AddIn.Pipeline.ContractBase
        Implements Library.ILibraryManagerContract
        Private _view As LibraryContractsBase.LibraryManager
        Public Sub New(ByVal view As LibraryContractsBase.LibraryManager)
            _view = view
        End Sub
        Public Overridable Sub ProcessBooks(ByVal books As IListContract(Of Library.IBookInfoContract)) Implements Library.ILibraryManagerContract.ProcessBooks
            _view.ProcessBooks(CollectionAdapters.ToIList(Of Library.IBookInfoContract, _
            LibraryContractsBase.BookInfo)(books, _
            AddressOf LibraryContractsAddInAdapters.BookInfoAddInAdapter.ContractToViewAdapter, _
            AddressOf LibraryContractsAddInAdapters.BookInfoAddInAdapter.ViewToContractAdapter))
        End Sub
        Public Overridable Function GetBestSeller() As Library.IBookInfoContract Implements Library.ILibraryManagerContract.GetBestSeller
            Return BookInfoAddInAdapter.ViewToContractAdapter(_view.GetBestSeller())
        End Function
    
        Public Overridable Function Data(ByVal txt As String) As String Implements Library.ILibraryManagerContract.Data
            Dim rtxt As String = _view.Data(txt)
            Return rtxt
        End Function
    
        Friend Function GetSourceView() As LibraryContractsBase.LibraryManager
            Return _view
        End Function
    End Class
    End Namespace
    
    using System.IO;
    using System.AddIn.Pipeline;
    using System.AddIn.Contract;
    using System.Collections.Generic;
    namespace LibraryContractsAddInAdapters
    {
    // The AddInAdapterAttribute
    // identifes this pipeline
    // segment as an add-in-side adapter.
    [AddInAdapter]
    public class LibraryManagerViewToContractAddInAdapter :
    System.AddIn.Pipeline.ContractBase, Library.ILibraryManagerContract
    {
        private LibraryContractsBase.LibraryManager _view;
        public LibraryManagerViewToContractAddInAdapter(LibraryContractsBase.LibraryManager view)
        {
            _view = view;
        }
        public virtual void ProcessBooks(IListContract<Library.IBookInfoContract> books)
        {
            _view.ProcessBooks(CollectionAdapters.ToIList<Library.IBookInfoContract,
                LibraryContractsBase.BookInfo>(books,
                LibraryContractsAddInAdapters.BookInfoAddInAdapter.ContractToViewAdapter,
                LibraryContractsAddInAdapters.BookInfoAddInAdapter.ViewToContractAdapter));
        }
        public virtual Library.IBookInfoContract GetBestSeller()
        {
            return BookInfoAddInAdapter.ViewToContractAdapter(_view.GetBestSeller());
        }
    
        public virtual string Data(string txt)
        {
            string rtxt = _view.Data(txt);
            return rtxt;
        }
    
        internal LibraryContractsBase.LibraryManager GetSourceView()
        {
            return _view;
        }
    }
    }
    
  10. Utilizzare il codice seguente per aggiungere la classe BookInfoAddInAdapter al progetto AddInSideAdapters. La classe contiene due metodi static (metodi Shared in Visual Basic): ContractToViewAdapter e ViewToContractAdapter. I metodi sono internal (Friend in Visual Basic) perché sono utilizzati solo dalle altre classi dell'adattatore. Lo scopo di tali metodi è evitare la creazione di un adattatore aggiuntivo quando un oggetto effettua un round trip tra l'host e il componente aggiuntivo nell'una o nell'altra direzione. Questi metodi devono essere forniti per adattatori che passano oggetti attraverso il limite di isolamento.

    
    Imports Microsoft.VisualBasic
    Imports System
    Namespace LibraryContractsAddInAdapters
    
    Public Class BookInfoAddInAdapter
      Friend Shared Function ContractToViewAdapter(ByVal contract As Library.IBookInfoContract) As LibraryContractsBase.BookInfo
        If (Not System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(contract)) AndAlso _
            CType(contract, Object).GetType().Equals(GetType(BookInfoViewToContractAddInAdapter)) Then
            Return (CType(contract, BookInfoViewToContractAddInAdapter)).GetSourceView()
        Else
            Return New BookInfoContractToViewAddInAdapter(contract)
        End If
    
      End Function
    
    Friend Shared Function ViewToContractAdapter(ByVal view As LibraryContractsBase.BookInfo) As Library.IBookInfoContract
        If (Not System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(view)) AndAlso _
            view.GetType().Equals(GetType(BookInfoContractToViewAddInAdapter)) Then
            Return (CType(view, BookInfoContractToViewAddInAdapter)).GetSourceContract()
        Else
            Return New BookInfoViewToContractAddInAdapter(view)
        End If
    End Function
    End Class
    End Namespace
    
    using System;
    namespace LibraryContractsAddInAdapters {
    
    public class BookInfoAddInAdapter
    {
        internal static LibraryContractsBase.BookInfo ContractToViewAdapter(Library.IBookInfoContract contract)
        {
            if (!System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(contract) &&
                (contract.GetType().Equals(typeof(BookInfoViewToContractAddInAdapter))))
            {
                return ((BookInfoViewToContractAddInAdapter)(contract)).GetSourceView();
            }
            else {
                return new BookInfoContractToViewAddInAdapter(contract);
            }
    
        }
    
        internal static Library.IBookInfoContract ViewToContractAdapter(LibraryContractsBase.BookInfo view)
        {
            if (!System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(view) &&
                (view.GetType().Equals(typeof(BookInfoContractToViewAddInAdapter))))
            {
                return ((BookInfoContractToViewAddInAdapter)(view)).GetSourceContract();
            }
            else {
                return new BookInfoViewToContractAddInAdapter(view);
            }
        }
    }
    }
    

Creazione dell'adattatore sul lato host

L'assembly dell'adattatore sul lato host per questa pipeline contiene quattro classi di adattatore:

  • BookInfoContractToViewHostAdapter

    Questo adattatore viene chiamato quando il componente aggiuntivo passa un oggetto BookInfo all'host, sia da solo o come parte di un insieme. Questa classe converte il contratto dell'oggetto BookInfo in una visualizzazione. La classe eredita dalla visualizzazione host e implementa i metodi astratti chiamando il contratto passato al costruttore della classe.

    Poiché il costruttore di questo adattatore accetta un contratto per il relativo costruttore, è possibile applicare un oggetto ContractHandle al contratto per implementare la gestione della durata.

    Nota importanteImportante

    L'oggetto ContractHandle è di importanza fondamentale nella gestione della durata.Se non si riesce a mantenere un riferimento all'oggetto ContractHandle, quest'ultimo verrà recuperato dalla Garbage Collection e la pipeline verrà interrotta in un momento non previsto dal programma.Ciò può comportare errori difficili da diagnosticare, ad esempio AppDomainUnloadedException.L'arresto è una fase normale del ciclo di vita di una pipeline. Pertanto, non esiste alcun modo in cui il codice di gestione della durata sia in grado di rilevare questa condizione come un errore.

  • BookInfoViewToContractHostAdapter

    Questo adattatore viene chiamato quando l'host passa un oggetto BookInfo al componente aggiuntivo. Questa classe converte la visualizzazione host dell'oggetto BookInfo in un contratto. La classe eredita dal contratto e implementa il contratto chiamando la visualizzazione del componente aggiuntivo passata al costruttore della classe. Viene effettuato il marshalling di questo adattatore al componente aggiuntivo come contratto.

  • LibraryManagerContractToViewHostAdapter

    Questo adattatore viene chiamato quando l'host passa un insieme di oggetti BookInfo al componente aggiuntivo. Il componente aggiuntivo esegue l'implementazione del metodo ProcessBooks in questo insieme.

    Questa classe converte la visualizzazione host dell'oggetto LibraryManager in un contratto. Eredita dal contratto e lo implementa chiamando la visualizzazione host che viene passata al costruttore della classe.

    Poiché è necessario effettuare il marshalling di un insieme di tipi personalizzati, ovvero gli oggetti BookInfo, oltre il limite di isolamento, questo adattatore utilizza la classe CollectionAdapters. Questa classe fornisce i metodi per convertire un insieme IList<T> in un insieme IListContract<T>, in modo da consentire il passaggio dell'insieme oltre il limite di isolamento all'altro lato della pipeline.

  • BookInfoHostAdapter

    Questo adattatore viene chiamato dalla classe LibraryManagerViewToContractHostAdapter per restituire qualsiasi contratto o visualizzazione esistente ai fini dell'adattamento, anziché creare nuove istanze per la chiamata. In questo modo si evita la creazione di un adattatore aggiuntivo quando un oggetto effettua un round trip tra l'host e il componente aggiuntivo nell'una o nell'altra direzione.

Per creare l'adattatore sul lato host

  1. Aggiungere un nuovo progetto denominato HostSideAdapters alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.

  2. In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.

  3. In Esplora soluzioni aggiungere riferimenti ai seguenti assembly per il progetto HostSideAdapters.

    System.AddIn.dll

    System.AddIn.Contract.dll

  4. In Esplora soluzioni aggiungere riferimenti ai seguenti progetti per il progetto HostSideAdapters.

    HostViews

    LibraryContracts

    Nel riferimento Proprietà impostare Copia localmente su False per questi riferimenti, per impedire la copia nella cartella di compilazione locale degli assembly cui viene fatto riferimento.

  5. Nel file di classe aggiungere un riferimento allo spazio dei nomi System.AddIn.Pipeline.

  6. Utilizzare il codice seguente per aggiungere la classe BookInfoContractToViewHostAdapter. La classe non richiede attributi perché non viene utilizzata per attivare la pipeline. Il metodo GetSourceContract internal (Friend in Visual Basic) viene utilizzato dalla classe BookInfoAddInAdapter per evitare di creare un adattatore aggiuntivo quando un oggetto effettua un round trip tra l'host e il componente aggiuntivo.

    
    Imports Microsoft.VisualBasic
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsHostAdapters
    Public Class BookInfoContractToViewHostAdapter
        Inherits LibraryContractsHAV.BookInfo
        Private _contract As Library.IBookInfoContract
    
        Private _handle As ContractHandle
    
        Public Sub New(ByVal contract As Library.IBookInfoContract)
            _contract = contract
            _handle = New ContractHandle(contract)
        End Sub
    
        Public Overrides Function ID() As String
            Return _contract.ID()
        End Function
        Public Overrides Function Author() As String
            Return _contract.Author()
        End Function
        Public Overrides Function Title() As String
            Return _contract.Title()
        End Function
        Public Overrides Function Genre() As String
            Return _contract.Genre()
        End Function
        Public Overrides Function Price() As String
            Return _contract.Price()
        End Function
        Public Overrides Function Publish_Date() As String
            Return _contract.Publish_Date()
        End Function
        Public Overrides Function Description() As String
            Return _contract.Description()
        End Function
    
    
        Friend Function GetSourceContract() As Library.IBookInfoContract
            Return _contract
        End Function
    End Class
    End Namespace
    
    using System.AddIn.Pipeline;
    namespace LibraryContractsHostAdapters
    {
        public class BookInfoContractToViewHostAdapter : LibraryContractsHAV.BookInfo
        {
            private Library.IBookInfoContract _contract;
    
            private ContractHandle _handle;
    
            public BookInfoContractToViewHostAdapter(Library.IBookInfoContract contract)
            {
                _contract = contract;
                _handle = new ContractHandle(contract);
            }
    
            public override string ID()
            {
                return _contract.ID();
            }
            public override string Author()
            {
                return _contract.Author();
            }
            public override string Title()
            {
                return _contract.Title();
            }
            public override string Genre()
            {
                return _contract.Genre();
            }
            public override string Price()
            {
                return _contract.Price();
            }
            public override string Publish_Date()
            {
                return _contract.Publish_Date();
            }
            public override string Description()
            {
                return _contract.Description();
            }
    
    
            internal Library.IBookInfoContract GetSourceContract() {
                return _contract;
            }
        }
    }
    
  7. Utilizzare il codice seguente per aggiungere la classe BookInfoViewToContractHostAdapter al progetto HostSideAdapters. La classe non richiede attributi perché non viene utilizzata per attivare la pipeline. Il metodo GetSourceView internal (Friend in Visual Basic) viene utilizzato dalla classe BookInfoAddInAdapter per evitare di creare un adattatore aggiuntivo quando un oggetto effettua un round trip tra l'host e il componente aggiuntivo.

    
    Imports Microsoft.VisualBasic
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsHostAdapters
    Public Class BookInfoViewToContractHostAdapter
        Inherits ContractBase
        Implements Library.IBookInfoContract
        Private _view As LibraryContractsHAV.BookInfo
    
        Public Sub New(ByVal view As LibraryContractsHAV.BookInfo)
            _view = view
        End Sub
    
        Public Overridable Function ID() As String Implements Library.IBookInfoContract.ID
            Return _view.ID()
        End Function
        Public Overridable Function Author() As String Implements Library.IBookInfoContract.Author
            Return _view.Author()
        End Function
        Public Overridable Function Title() As String Implements Library.IBookInfoContract.Title
            Return _view.Title()
        End Function
        Public Overridable Function Genre() As String Implements Library.IBookInfoContract.Genre
            Return _view.Genre()
        End Function
        Public Overridable Function Price() As String Implements Library.IBookInfoContract.Price
            Return _view.Price()
        End Function
        Public Overridable Function Publish_Date() As String Implements Library.IBookInfoContract.Publish_Date
            Return _view.Publish_Date()
        End Function
        Public Overridable Function Description() As String Implements Library.IBookInfoContract.Description
            Return _view.Description()
        End Function
        Friend Function GetSourceView() As LibraryContractsHAV.BookInfo
            Return _view
        End Function
    End Class
    End Namespace
    
    using System.AddIn.Pipeline;
    namespace LibraryContractsHostAdapters
    {
    public class BookInfoViewToContractHostAdapter : ContractBase, Library.IBookInfoContract
    {
        private LibraryContractsHAV.BookInfo _view;
    
        public BookInfoViewToContractHostAdapter(LibraryContractsHAV.BookInfo view)
        {
            _view = view;
        }
    
        public virtual string ID()
        {
            return _view.ID();
        }
        public virtual string Author()
        {
            return _view.Author();
        }
        public virtual string Title()
        {
            return _view.Title();
        }
        public virtual string Genre()
        {
            return _view.Genre();
        }
        public virtual string Price()
        {
            return _view.Price();
        }
        public virtual string Publish_Date()
        {
            return _view.Publish_Date();
        }
        public virtual string Description()
        {
            return _view.Description();
        }
        internal LibraryContractsHAV.BookInfo GetSourceView()
        {
            return _view;
        }
    }
    }
    
  8. Utilizzare il codice seguente per aggiungere LibraryManagerContractToViewHostAdapter al progetto HostSideAdapters. Questa classe richiede l'attributo HostAdapterAttribute perché viene utilizzata per attivare la pipeline.

    Il metodo ProcessBooks mostra come passare un elenco di libri attraverso il limite di isolamento. Utilizza il metodo CollectionAdapters.ToIListContract per convertire l'elenco. Per convertire gli oggetti nell'elenco passa i delegati dei metodi dell'adattatore forniti dalla classe BookInfoHostAdapter.

    Il metodo GetBestSeller mostra come passare un singolo oggetto BookInfo attraverso il limite di isolamento.

    
    Imports Microsoft.VisualBasic
    Imports System.Collections.Generic
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsHostAdapters
        <HostAdapterAttribute()> _
        Public Class LibraryManagerContractToViewHostAdapter
            Inherits LibraryContractsHAV.LibraryManager
    
            Private _contract As Library.ILibraryManagerContract
            Private _handle As System.AddIn.Pipeline.ContractHandle
    
            Public Sub New(ByVal contract As Library.ILibraryManagerContract)
                _contract = contract
                _handle = New System.AddIn.Pipeline.ContractHandle(contract)
            End Sub
    
            Public Overrides Sub ProcessBooks(ByVal books As IList(Of LibraryContractsHAV.BookInfo))
                _contract.ProcessBooks(CollectionAdapters.ToIListContract(Of LibraryContractsHAV.BookInfo, _
                Library.IBookInfoContract)(books, _
                AddressOf LibraryContractsHostAdapters.BookInfoHostAdapter.ViewToContractAdapter, _
                AddressOf LibraryContractsHostAdapters.BookInfoHostAdapter.ContractToViewAdapter))
            End Sub
    
            Public Overrides Function GetBestSeller() As LibraryContractsHAV.BookInfo
                Return BookInfoHostAdapter.ContractToViewAdapter(_contract.GetBestSeller())
            End Function
    
            Friend Function GetSourceContract() As Library.ILibraryManagerContract
                Return _contract
            End Function
            Public Overrides Function Data(ByVal txt As String) As String
                Dim rtxt As String = _contract.Data(txt)
                Return rtxt
            End Function
        End Class
    End Namespace
    
    using System.Collections.Generic;
    using System.AddIn.Pipeline;
    namespace LibraryContractsHostAdapters
    {
    [HostAdapterAttribute()]
    public class LibraryManagerContractToViewHostAdapter : LibraryContractsHAV.LibraryManager
    {
    
        private Library.ILibraryManagerContract _contract;
        private System.AddIn.Pipeline.ContractHandle _handle;
    
        public LibraryManagerContractToViewHostAdapter(Library.ILibraryManagerContract contract)
        {
            _contract = contract;
            _handle = new System.AddIn.Pipeline.ContractHandle(contract);
        }
    
        public override void ProcessBooks(IList<LibraryContractsHAV.BookInfo> books) {
            _contract.ProcessBooks(CollectionAdapters.ToIListContract<LibraryContractsHAV.BookInfo,
                Library.IBookInfoContract>(books,
                LibraryContractsHostAdapters.BookInfoHostAdapter.ViewToContractAdapter,
                LibraryContractsHostAdapters.BookInfoHostAdapter.ContractToViewAdapter));
        }
    
        public override LibraryContractsHAV.BookInfo GetBestSeller()
        {
            return BookInfoHostAdapter.ContractToViewAdapter(_contract.GetBestSeller());
        }
    
        internal Library.ILibraryManagerContract GetSourceContract()
        {
            return _contract;
        }
        public override string Data(string txt)
        {
            string rtxt = _contract.Data(txt);
            return rtxt;
        }
    }
    }
    
  9. Utilizzare il codice seguente per aggiungere la classe BookInfoHostAdapter al progetto HostSideAdapters. La classe contiene due metodi static (metodi Shared in Visual Basic): ContractToViewAdapter e ViewToContractAdapter. I metodi sono internal (Friend in Visual Basic) perché sono utilizzati solo dalle altre classi dell'adattatore. Lo scopo di tali metodi è evitare la creazione di un adattatore aggiuntivo quando un oggetto effettua un round trip tra l'host e il componente aggiuntivo nell'una o nell'altra direzione. Questi metodi devono essere forniti per adattatori che passano oggetti attraverso il limite di isolamento.

    
    Imports Microsoft.VisualBasic
    Imports System
    Namespace LibraryContractsHostAdapters
    Public Class BookInfoHostAdapter
    
    Friend Shared Function ContractToViewAdapter(ByVal contract As Library.IBookInfoContract) As LibraryContractsHAV.BookInfo
        If Not System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(contract) AndAlso _
            CType(contract, Object).GetType().Equals(GetType(BookInfoViewToContractHostAdapter)) Then
            Return (CType(contract, BookInfoViewToContractHostAdapter)).GetSourceView()
        Else
            Return New BookInfoContractToViewHostAdapter(contract)
        End If
    End Function
    
    Friend Shared Function ViewToContractAdapter(ByVal view As LibraryContractsHAV.BookInfo) As Library.IBookInfoContract
        If Not System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(view) AndAlso _
            view.GetType().Equals(GetType(BookInfoContractToViewHostAdapter)) Then
            Return (CType(view, BookInfoContractToViewHostAdapter)).GetSourceContract()
        Else
            Return New BookInfoViewToContractHostAdapter(view)
        End If
    End Function
    End Class
    End Namespace
    
    using System;
    namespace LibraryContractsHostAdapters
    {
    public class BookInfoHostAdapter
    {
    
        internal static LibraryContractsHAV.BookInfo ContractToViewAdapter(Library.IBookInfoContract contract)
        {
            if (!System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(contract) &&
                (contract.GetType().Equals(typeof(BookInfoViewToContractHostAdapter))))
            {
                return ((BookInfoViewToContractHostAdapter)(contract)).GetSourceView();
    
            }
            else {
                return new BookInfoContractToViewHostAdapter(contract);
            }
        }
    
        internal static Library.IBookInfoContract ViewToContractAdapter(LibraryContractsHAV.BookInfo view)
        {
            if (!System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(view) &&
                (view.GetType().Equals(typeof(BookInfoContractToViewHostAdapter))))
            {
                return ((BookInfoContractToViewHostAdapter)(view)).GetSourceContract();
            }
            else {
                return new BookInfoViewToContractHostAdapter(view);
            }
        }
    }
    }
    

Creazione dell'host

Un'applicazione host interagisce con il componente aggiuntivo tramite la visualizzazione host. Utilizza i metodi di individuazione e attivazione del componente aggiuntivo forniti dalle classi AddInStore e AddInToken per eseguire le operazioni seguenti:

  • Ricompilare la cache di informazioni sulla pipeline e sui componenti aggiuntivi.

  • Cercare i componenti aggiuntivi di tipo LibraryManager nella directory radice della pipeline specificata.

  • Richiedere all'utente di selezionare il componente aggiuntivo da utilizzare. In questo esempio è disponibile un solo componente aggiuntivo.

  • Attivare il componente aggiuntivo selezionato in un nuovo dominio applicazione con un livello di attendibilità della sicurezza specificato.

  • Chiamare il metodo ProcessBooks per passare un insieme di oggetti BookInfo al componente aggiuntivo. Il componente aggiuntivo chiama la relativa implementazione del metodo ProcessBooks ed esegue funzioni quale l'applicazione di uno sconto del 20% per i libri di informatica.

  • Chiamare il metodo GetBestSeller utilizzato dal componente aggiuntivo per restituire un oggetto BookInfo con le informazioni sul libro di maggior successo.

  • Chiamare il metodo Data per ottenere l'aliquota IVA corrente dal componente aggiuntivo. Questo metodo accetta e restituisce una stringa che corrisponde a un tipo di riferimento sealed, serializzabile. Di conseguenza il metodo può essere passato oltre limite di isolamento all'altro lato della pipeline senza utilizzare un adattatore visualizzazione-contratto o contratto-visualizzazione.

L'host dispone di un metodo CreateBooks che crea un insieme di oggetti BookInfo. Questo metodo crea l'insieme utilizzando il file books.xml di esempio che è disponibile in Sample XML File (books.xml).

Per creare l'host

  1. Aggiungere un nuovo progetto denominato BookStore alla soluzione BooksPipeline, basandolo sul modello Applicazione console.

  2. In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.

  3. In Esplora soluzioni aggiungere un riferimento all'assembly System.AddIn.dll per il progetto BookStore.

  4. Aggiungere un riferimento di progetto al progetto HostViews. Nel riferimento Proprietà impostare Copia localmente su False per il riferimento, per impedire la copia nella cartella di compilazione locale dell'assembly cui viene fatto riferimento.

  5. In Visual Basic, modificare il modulo in classe:

    • Escludere il modulo predefinito dal progetto, quindi aggiungere una classe denominata Program.

    • Sostituire la parola chiave Public con Friend.

    • Aggiungere una procedura Shared Sub Main() alla classe.

    • Utilizzare la scheda Applicazione della finestra di dialogo Proprietà progetti per impostare Oggetto di avvio su Sub Main.

  6. Nel file di classe aggiungere riferimenti agli spazi dei nomi System.AddIn.Pipeline e per il segmento di visualizzazione host.

  7. In Esplora soluzioni selezionare la soluzione, quindi scegliere Proprietà dal menu Progetto. Nella finestra di dialogo Pagine delle proprietà di Soluzione impostare Progetto di avvio singolo in modo che venga utilizzato come progetto di questa applicazione host.

  8. Utilizzare il codice seguente per l'applicazione host.

    NotaNota

    Nel codice, modificare il percorso dal quale il file books.xml viene caricato in "books.xml", in modo che il file venga caricato dalla cartella dell'applicazione.Se si desidera posizionare l'applicazione in un percorso diverso da quello della cartella Pipeline, modificare la riga di codice che imposta la variabile addInRoot, in modo che la variabile contenga il percorso della struttura di directory della pipeline.

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Text
    Imports LibraryContractsHAV
    Imports System.AddIn.Hosting
    Imports System.Xml
    
    
    Namespace ListAdaptersHost
    Friend Class Program
    Shared Sub Main(ByVal args As String())
    
        ' In this example, the pipeline root is the current directory.
        Dim pipeRoot As String = Environment.CurrentDirectory
    
        ' Rebuild the cache of pipeline and add-in information.
        Dim warnings As String() = AddInStore.Update(pipeRoot)
        If warnings.Length > 0 Then
            For Each one As String In warnings
                Console.WriteLine(one)
            Next one
        End If
    
        ' Find add-ins of type LibraryManager under the specified pipeline root directory.
        Dim tokens As Collection(Of AddInToken) = AddInStore.FindAddIns(GetType(LibraryManager), pipeRoot)
        ' Determine which add-in to use.
        Dim selectedToken As AddInToken = ChooseAddIn(tokens)
    
        ' Activate the selected AddInToken in a new
        ' application domain with a specified security trust level.
        Dim manager As LibraryManager = selectedToken.Activate(Of LibraryManager)(AddInSecurityLevel.FullTrust)
    
        ' Create a collection of books.
        Dim books As IList(Of BookInfo) = CreateBooks()
    
        ' Show the collection count.
        Console.WriteLine("Number of books:  {0}",books.Count.ToString())
    
        ' Have the add-in process the books.
        ' The add-in will discount computer books by $20
        ' and list their before and after prices. It
        ' will also remove all horror books.
        manager.ProcessBooks(books)
    
        ' List the genre of each book. There
        ' should be no horror books.
        For Each bk As BookInfo In books
            Console.WriteLine(bk.Genre())
        Next bk
    
        Console.WriteLine("Number of books: {0}", books.Count.ToString())
    
        Console.WriteLine()
        ' Have the add-in pass a BookInfo object
        ' of the best selling book.
        Dim bestBook As BookInfo = manager.GetBestSeller()
        Console.WriteLine("Best seller is {0} by {1}", bestBook.Title(), bestBook.Author())
    
        ' Have the add-in show the sales tax rate.
        manager.Data("sales tax")
    
        Dim ctrl As AddInController = AddInController.GetAddInController(manager)
        ctrl.Shutdown()
        Console.WriteLine("Press any key to exit.")
        Console.ReadLine()
    End Sub
    
    
    
    Private Shared Function ChooseAddIn(ByVal tokens As Collection(Of AddInToken)) As AddInToken
        If tokens.Count = 0 Then
            Console.WriteLine("No add-ins of this type are available")
            Return Nothing
        End If
        Console.WriteLine("{0} Available add-in(s):",tokens.Count.ToString())
        For i As Integer = 0 To tokens.Count - 1
            ' Show AddInToken properties.
            Console.WriteLine("[{0}] - {1}, Publisher: {2}, Version: {3}, Description: {4}", (i + 1).ToString(), tokens(i).Name, tokens(i).Publisher, tokens(i).Version, tokens(i).Description)
        Next i
        Console.WriteLine("Select add-in by number:")
        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 ChooseAddIn(tokens)
    End Function
    
    
    Friend Shared Function CreateBooks() As IList(Of BookInfo)
        Dim books As List(Of BookInfo) = New List(Of BookInfo)()
    
        Dim ParamId As String = ""
        Dim ParamAuthor As String = ""
        Dim ParamTitle As String = ""
        Dim ParamGenre As String = ""
        Dim ParamPrice As String = ""
        Dim ParamPublish_Date As String = ""
        Dim ParamDescription As String = ""
    
        Dim xDoc As XmlDocument = New XmlDocument()
        xDoc.Load("c:\Books.xml")
    
         Dim xRoot As XmlNode = xDoc.DocumentElement
         If xRoot.Name = "catalog" Then
            Dim bklist As XmlNodeList = xRoot.ChildNodes
            For Each bk As XmlNode In bklist
                ParamId = bk.Attributes(0).Value
                Dim dataItems As XmlNodeList = bk.ChildNodes
                Dim items As Integer = dataItems.Count
                For Each di As XmlNode In dataItems
                    Select Case di.Name
                        Case "author"
                            ParamAuthor = di.InnerText
                        Case "title"
                            ParamTitle = di.InnerText
                        Case "genre"
                            ParamGenre = di.InnerText
                         Case "price"
                            ParamPrice = di.InnerText
                         Case "publish_date"
                            ParamAuthor = di.InnerText
                         Case "description"
                            ParamDescription = di.InnerText
                          Case Else
                    End Select
    
                Next di
                books.Add(New MyBookInfo(ParamId, ParamAuthor, ParamTitle, ParamGenre, ParamPrice, ParamPublish_Date, ParamDescription))
            Next bk
    
         End If
        Return books
    End Function
    
    
    End Class
    
    Friend Class MyBookInfo
        Inherits BookInfo
        Private _id As String
        Private _author As String
        Private _title As String
        Private _genre As String
        Private _price As String
        Private _publish_date As String
        Private _description As String
    
        Public Sub New(ByVal id As String, ByVal author As String, ByVal title As String, ByVal genre As String, ByVal price As String, ByVal publish_date As String, ByVal description As String)
            _id = id
            _author = author
            _title = title
            _genre = genre
            _price = price
            _publish_date = publish_date
            _description = description
        End Sub
    
        Public Overrides Function ID() As String
            Return _id
        End Function
    
        Public Overrides Function Title() As String
            Return _title
        End Function
    
        Public Overrides Function Author() As String
            Return _author
        End Function
    
         Public Overrides Function Genre() As String
            Return _genre
         End Function
        Public Overrides Function Price() As String
            Return _price
        End Function
        Public Overrides Function Publish_Date() As String
            Return _publish_date
        End Function
        Public Overrides Function Description() As String
            Return _description
        End Function
    End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Text;
    using LibraryContractsHAV;
    using System.AddIn.Hosting;
    using System.Xml;
    
    
    namespace ListAdaptersHost
    {
    class Program
    {
    static void Main(string[] args)
    {
    
        // In this example, the pipeline root is the current directory.
        String pipeRoot = Environment.CurrentDirectory;
    
        // Rebuild the cache of pipeline and add-in information.
        string[] warnings = AddInStore.Update(pipeRoot);
        if (warnings.Length > 0)
        {
            foreach (string one in warnings)
            {
                Console.WriteLine(one);
            }
        }
    
        // Find add-ins of type LibraryManager under the specified pipeline root directory.
        Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(LibraryManager), pipeRoot);
        // Determine which add-in to use.
        AddInToken selectedToken = ChooseAddIn(tokens);
    
        // Activate the selected AddInToken in a new
        // application domain with a specified security trust level.
        LibraryManager manager = selectedToken.Activate<LibraryManager>(AddInSecurityLevel.FullTrust);
    
        // Create a collection of books.
        IList<BookInfo> books = CreateBooks();
    
        // Show the collection count.
        Console.WriteLine("Number of books:  {0}",books.Count.ToString());
    
        // Have the add-in process the books.
        // The add-in will discount computer books by $20
        // and list their before and after prices. It
        // will also remove all horror books.
        manager.ProcessBooks(books);
    
        // List the genre of each book. There
        // should be no horror books.
        foreach (BookInfo bk in books)
        {
            Console.WriteLine(bk.Genre());
        }
    
        Console.WriteLine("Number of books: {0}", books.Count.ToString());
    
        Console.WriteLine();
        // Have the add-in pass a BookInfo object
        // of the best selling book.
        BookInfo bestBook = manager.GetBestSeller();
        Console.WriteLine("Best seller is {0} by {1}", bestBook.Title(), bestBook.Author());
    
        // Have the add-in show the sales tax rate.
        manager.Data("sales tax");
    
        AddInController ctrl = AddInController.GetAddInController(manager);
        ctrl.Shutdown();
        Console.WriteLine("Press any key to exit.");
        Console.ReadLine();
    }
    
    
    
    private static AddInToken ChooseAddIn(Collection<AddInToken> tokens)
    {
        if (tokens.Count == 0)
        {
            Console.WriteLine("No add-ins of this type are available");
            return null;
        }
        Console.WriteLine("{0} Available add-in(s):",tokens.Count.ToString());
        for (int i = 0; i < tokens.Count; i++)
        {
            // Show AddInToken properties.
            Console.WriteLine("[{0}] - {1}, Publisher: {2}, Version: {3}, Description: {4}",
                (i + 1).ToString(), tokens[i].Name, tokens[i].Publisher,
                tokens[i].Version, tokens[i].Description);
        }
        Console.WriteLine("Select add-in by number:");
        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 ChooseAddIn(tokens);
    }
    
    
    internal static IList<BookInfo> CreateBooks()
    {
        List<BookInfo> books = new List<BookInfo>();
    
        string ParamId = "";
        string ParamAuthor = "";
        string ParamTitle = "";
        string ParamGenre = "";
        string ParamPrice = "";
        string ParamPublish_Date = "";
        string ParamDescription = "";
    
        XmlDocument xDoc = new XmlDocument();
        xDoc.Load(@"c:\Books.xml");
    
         XmlNode xRoot = xDoc.DocumentElement;
         if (xRoot.Name == "catalog")
        {
            XmlNodeList bklist = xRoot.ChildNodes;
            foreach (XmlNode bk in bklist)
            {
                ParamId = bk.Attributes[0].Value;
                XmlNodeList dataItems = bk.ChildNodes;
                int items = dataItems.Count;
                foreach (XmlNode di in dataItems)
                {
                    switch (di.Name)
                    {
                        case "author":
                            ParamAuthor = di.InnerText;
                            break;
                        case "title":
                            ParamTitle = di.InnerText;
                            break;
                        case "genre":
                            ParamGenre = di.InnerText;
                            break;
                         case "price":
                            ParamPrice = di.InnerText;
                            break;
                         case "publish_date":
                            ParamAuthor = di.InnerText;
                            break;
                         case "description":
                            ParamDescription = di.InnerText;
                            break;
                          default:
                            break;
                    }
    
                }
                books.Add(new MyBookInfo(ParamId, ParamAuthor, ParamTitle, ParamGenre,
                                ParamPrice, ParamPublish_Date, ParamDescription));
            }
    
        }
        return books;
    }
    
    
    }
    
    class MyBookInfo : BookInfo
    {
        private string _id;
        private string _author;
        private string _title;
        private string _genre;
        private string _price;
        private string _publish_date;
        private string _description;
    
        public MyBookInfo(string id, string author, string title,
                            string genre, string price,
                            string publish_date, string description)
        {
            _id = id;
            _author = author;
            _title = title;
            _genre = genre;
            _price = price;
            _publish_date = publish_date;
            _description = description;
        }
    
        public override string ID()
        {
            return _id;
        }
    
        public override string Title()
        {
            return _title;
        }
    
        public override string Author()
        {
            return _author;
        }
    
         public override string Genre()
        {
            return _genre;
        }
        public override string Price()
        {
            return _price;
        }
        public override string Publish_Date()
        {
            return _publish_date;
        }
        public override string Description()
        {
            return _description;
        }
    }
    }
    

Per creare il file di dati books.xml

  1. Aggiungere un nuovo file XML al progetto BookStore. Nella finestra di dialogo Aggiungi nuovo elemento, denominare il file books.xml.

  2. Sostituire il contenuto predefinito di books.xml con il codice XML incluso in Sample XML File (books.xml).

  3. In Esplora soluzioni, selezionare books.xml e in Proprietà impostare Copia nella directory di output su Copia sempre.

Creazione del componente aggiuntivo

Un componente aggiuntivo implementa i metodi specificati dalla visualizzazione del componente aggiuntivo. Questo componente aggiuntivo implementa il metodo ProcessBooks, che esegue le operazioni seguenti su un insieme di oggetti BookInfo che vengono passati dall'host:

  • Viene scontato del 20% il prezzo di tutti i libri di informatica.

  • Vengono rimossi dall'insieme tutti i libri di orrore.

Questo componente aggiuntivo implementa inoltre il metodo GetBestSeller passando all'host un oggetto BookInfo che descrive il libro di maggior successo.

Per creare il componente aggiuntivo

  1. Aggiungere un nuovo progetto denominato BooksAddin alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.

  2. In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.

  3. In Esplora soluzioni aggiungere un riferimento all'assembly System.AddIn.dll per il progetto BooksAddin.

  4. Aggiungere un riferimento di progetto al progetto AddInViews. Nel riferimento Proprietà impostare Copia localmente su False per il riferimento, per impedire la copia nella cartella di compilazione locale dell'assembly cui viene fatto riferimento.

  5. Nel file di classe aggiungere riferimenti agli spazi dei nomi System.AddIn e per il segmento di visualizzazione del componente aggiuntivo.

  6. Utilizzare il codice seguente per l'applicazione del componente aggiuntivo.

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports LibraryContractsBase
    Imports System.AddIn
    Imports System.IO
    
    Namespace SampleAddIn
    <AddIn("Books AddIn",Version:="1.0.0.0")> _
    Public Class BooksAddIn
        Inherits LibraryManager
        ' Calls methods that updates book data
        ' and removes books by genre.
        Public Overrides Sub ProcessBooks(ByVal books As IList(Of BookInfo))
            For i As Integer = 0 To books.Count - 1
                books(i) = UpdateBook(books(i))
            Next i
            RemoveGenre("horror", books)
        End Sub
    
        Public Overrides Function Data(ByVal txt As String) As String
            ' assumes txt = "sales tax"
            Dim rtxt As String = txt & "= 8.5%"
            Return rtxt
        End Function
    
        Friend Shared Function RemoveGenre(ByVal genre As String, ByVal books As IList(Of BookInfo)) As IList(Of BookInfo)
            ' Remove all horror books from the collection.
            Dim i As Integer = 0
            Do While i < books.Count
                If books(i).Genre().ToLower() = "horror" Then
                    books.RemoveAt(i)
                End If
                i += 1
            Loop
            Return books
        End Function
    
        ' Populate a BookInfo object with data
        ' about the best selling book.
        Public Overrides Function GetBestSeller() As BookInfo
            Dim ParamId As String = "bk999"
            Dim ParamAuthor As String = "Corets, Eva"
            Dim ParamTitle As String = "Cooking with Oberon"
            Dim ParamGenre As String = "Cooking"
            Dim ParamPrice As String = "7.95"
            Dim ParamPublish_Date As String = "2006-12-01"
            Dim ParamDescription As String = "Recipes for a post-apocalyptic society."
    
            Dim bestBook As MyBookInfo = New MyBookInfo(ParamId, ParamAuthor, ParamTitle, ParamGenre, ParamPrice, ParamPublish_Date, ParamDescription)
            Return bestBook
        End Function
    
        Friend Shared Function UpdateBook(ByVal bk As BookInfo) As BookInfo
            ' Discounts the price of all
            ' computer books by 20 percent.
            Dim ParamId As String = bk.ID()
            Dim ParamAuthor As String = bk.Author()
            Dim ParamTitle As String = bk.Title()
            Dim ParamGenre As String = bk.Genre()
            Dim ParamPrice As String = bk.Price()
            If ParamGenre.ToLower() = "computer" Then
                Dim oldprice As Double = Convert.ToDouble(ParamPrice)
                Dim newprice As Double = oldprice - (oldprice *.20)
                ParamPrice = newprice.ToString()
                If ParamPrice.IndexOf(".") = ParamPrice.Length - 4 Then
                    ParamPrice = ParamPrice.Substring(1, ParamPrice.Length - 1)
                End If
                Console.WriteLine("{0} - Old Price: {1}, New Price: {2}",ParamTitle,oldprice.ToString(),ParamPrice)
            End If
            Dim ParamPublish_Date As String = bk.Publish_Date()
            Dim ParamDescription As String = bk.Description()
    
            Dim bookUpdated As BookInfo = New MyBookInfo(ParamId, ParamAuthor, ParamTitle, ParamGenre, ParamPrice, ParamPublish_Date, ParamDescription)
    
            Return bookUpdated
    
        End Function
    
    End Class
    
    ' Creates a BookInfo object.
    Friend Class MyBookInfo
        Inherits BookInfo
        Private _id As String
        Private _author As String
        Private _title As String
        Private _genre As String
        Private _price As String
        Private _publish_date As String
        Private _description As String
    
        Public Sub New(ByVal id As String, ByVal author As String, ByVal title As String, ByVal genre As String, ByVal price As String, ByVal publish_date As String, ByVal description As String)
            _id = id
            _author = author
            _title = title
            _genre = genre
            _price = price
            _publish_date = publish_date
            _description = description
        End Sub
    
        Public Overrides Function ID() As String
            Return _id
        End Function
    
        Public Overrides Function Title() As String
            Return _title
        End Function
    
        Public Overrides Function Author() As String
            Return _author
        End Function
    
        Public Overrides Function Genre() As String
            Return _genre
        End Function
        Public Overrides Function Price() As String
            Return _price
        End Function
        Public Overrides Function Publish_Date() As String
            Return _publish_date
        End Function
        Public Overrides Function Description() As String
            Return _description
        End Function
    End Class
    
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using LibraryContractsBase;
    using System.AddIn;
    using System.IO;
    
    namespace BooksAddIn
    {
    [AddIn("Books AddIn",Description="Book Store Data",
           Publisher="Microsoft",Version="1.0.0.0")]
    
    public class BooksAddIn : LibraryManager
    {
        // Calls methods that updates book data
        // and removes books by their genre.
        public override void ProcessBooks(IList<BookInfo> books)
        {
            for (int i = 0; i < books.Count; i++)
            {
                books[i] = UpdateBook(books[i]);
            }
            RemoveGenre("horror", books);
        }
    
        public override string Data(string txt)
        {
            // assumes txt = "sales tax"
            string rtxt = txt + "= 8.5%";
            return rtxt;
        }
    
        internal static IList<BookInfo> RemoveGenre(string genre, IList<BookInfo> books)
        {
            // Remove all horror books from the collection.
            for (int i = 0; i < books.Count; i++)
            {
                if (books[i].Genre().ToLower() == "horror")
                    books.RemoveAt(i);
            }
            return books;
        }
    
        // Populate a BookInfo object with data
        // about the best selling book.
        public override BookInfo GetBestSeller()
        {
            string ParamId = "bk999";
            string ParamAuthor = "Corets, Eva";
            string ParamTitle = "Cooking with Oberon";
            string ParamGenre = "Cooking";
            string ParamPrice = "7.95";
            string ParamPublish_Date = "2006-12-01";
            string ParamDescription = "Recipes for a post-apocalyptic society.";
    
            MyBookInfo bestBook = new MyBookInfo(ParamId, ParamAuthor, ParamTitle, ParamGenre,
                                    ParamPrice, ParamPublish_Date, ParamDescription);
            return bestBook;
        }
    
        internal static BookInfo UpdateBook(BookInfo bk)
        {
            // Discounts the price of all
            // computer books by 20 percent.
            string ParamId = bk.ID();
            string ParamAuthor = bk.Author();
            string ParamTitle = bk.Title();
            string ParamGenre = bk.Genre();
            string ParamPrice = bk.Price();
            if (ParamGenre.ToLower() == "computer")
            {
                double oldprice = Convert.ToDouble(ParamPrice);
                double newprice = oldprice - (oldprice * .20);
                ParamPrice = newprice.ToString();
                if (ParamPrice.IndexOf(".") == ParamPrice.Length - 4)
                    ParamPrice = ParamPrice.Substring(1, ParamPrice.Length - 1);
                Console.WriteLine("{0} - Old Price: {1}, New Price: {2}",ParamTitle,oldprice.ToString(),ParamPrice);
            }
            string ParamPublish_Date = bk.Publish_Date();
            string ParamDescription = bk.Description();
    
            BookInfo bookUpdated = new MyBookInfo(ParamId, ParamAuthor, ParamTitle, ParamGenre,
                            ParamPrice, ParamPublish_Date, ParamDescription);
    
            return bookUpdated;
    
        }
    
    }
    
    // Creates a BookInfo object.
    class MyBookInfo : BookInfo
    {
        private string _id;
        private string _author;
        private string _title;
        private string _genre;
        private string _price;
        private string _publish_date;
        private string _description;
    
        public MyBookInfo(string id, string author, string title,
                            string genre, string price,
                            string publish_date, string description)
        {
            _id = id;
            _author = author;
            _title = title;
            _genre = genre;
            _price = price;
            _publish_date = publish_date;
            _description = description;
        }
    
        public override string ID()
        {
            return _id;
        }
    
        public override string Title()
        {
            return _title;
        }
    
        public override string Author()
        {
            return _author;
        }
    
        public override string Genre()
        {
            return _genre;
        }
        public override string Price()
        {
            return _price;
        }
        public override string Publish_Date()
        {
            return _publish_date;
        }
        public override string Description()
        {
            return _description;
        }
    }
    
    }
    

Distribuzione della pipeline

A questo punto è possibile procedere alla compilazione e distribuzione dei segmenti del componente aggiuntivo alla struttura di directory della pipeline richiesta.

Per distribuire i segmenti alla pipeline

  1. Per ogni progetto nella soluzione, utilizzare la scheda Compilazione di Proprietà progetto (la scheda Compilazione anche in Visual Basic) per impostare il valore di Percorso output (Percorso dell'output di compilazione in Visual Basic), come illustrato nella tabella seguente.

    Project

    Percorso

    BooksAddIn

    Pipeline\AddIns\CalcV1

    AddInSideAdapters

    Pipeline\AddInSideAdapters

    AddInViews

    Pipeline\AddInViews

    LibraryContracts

    Pipeline\Contracts

    BookStore

    Pipeline (o la directory dell'applicazione)

    HostSideAdapters

    Pipeline\HostSideAdapters

    HostViews

    Pipeline (o la directory dell'applicazione)

    NotaNota

    Se si è deciso di inserire l'applicazione in un percorso diverso da quello della cartella Pipeline, assicurarsi di modificare il codice dell'host che specifica il percorso della directory radice della pipeline.

  2. Compilare la soluzione di Visual Studio.

    Per ulteriori informazioni sulla distribuzione alla pipeline, vedere Requisiti di sviluppo delle pipeline.

Esecuzione dell'applicazione host

A questo punto è possibile eseguire l'host e interagire con il componente aggiuntivo.

Per eseguire l'applicazione host

  1. Al prompt dei comandi passare alla directory radice della pipeline ed eseguire l'applicazione host. In questo esempio l'applicazione host è BookStore.exe.

  2. L'host cerca tutti i componenti aggiuntivi disponibili del tipo specificato e chiede all'utente di selezionarne uno. Immettere 1 per il solo componente aggiuntivo disponibile.

    L'host attiva il componente aggiuntivo e lo utilizza per eseguire alcune operazioni sull'elenco di libri.

  3. Premere un tasto qualsiasi per chiudere l'applicazione.

Vedere anche

Attività

Procedura dettagliata: creazione di un'applicazione estendibile

Procedura dettagliata: abilitazione della compatibilità con le versioni precedenti in base alle modifiche dell'host

Concetti

Requisiti di sviluppo delle pipeline

Contratti, visualizzazioni e adattatori

Sviluppo pipeline