Per visualizzare l'articolo in inglese, selezionare la casella di controllo Inglese. È possibile anche visualizzare il testo inglese in una finestra popup posizionando il puntatore del mouse sopra il testo.
Traduzione
Inglese
Informazioni
L'argomento richiesto è visualizzato di seguito, ma non è incluso in questa libreria.

Procedura dettagliata: passaggio di raccolte tra host e componenti aggiuntivi

In questa procedura dettagliata viene descritto come creare una pipeline che passa una raccolta di oggetti personalizzati tra un componente aggiuntivo e un host. Poiché i tipi nella raccolta 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 una raccolta 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 una raccolta di libri; il componente aggiuntivo riduce del 20% il prezzo di tutti i libri di informatica e rimuove tutti i libri di orrore dalla raccolta. 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.

Nota Nota

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 versioni Community Technology Preview di strumenti di compilazione di pipeline per componenti aggiuntivi, vedere il sito relativo al framework di componenti aggiuntivi ed estensibilità gestita in CodePlex (la pagina potrebbe essere in inglese).

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

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.

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.

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 una raccolta 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.

    
    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.

    
    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.

    
    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.

    
    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.

    
    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();
        }
    }
    
    
    

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 una raccolta. 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 importante Importante

    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 implementa il contratto 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 una raccolta 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 una raccolta 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 una raccolta IList<T> in una raccolta IListContract<T>, in modo da consentire il passaggio della raccolta 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 GetSourceContractinternal (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.

    
    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 GetSourceViewinternal (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.

    
    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.

    
    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.

    
    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);
            }
        }
    }
    }
    
    
    

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 una raccolta. 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 importante Importante

    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 una raccolta di oggetti BookInfo al componente aggiuntivo. Il componente aggiuntivo esegue l'implementazione del metodo ProcessBooks in questa raccolta.

    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 una raccolta 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 una raccolta IList<T> in una raccolta IListContract<T>, in modo da consentire il passaggio della raccolta 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 GetSourceContractinternal (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.

    
    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 GetSourceViewinternal (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.

    
    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.

    
    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.

    
    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);
            }
        }
    }
    }
    
    
    

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 una raccolta 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 una raccolta di oggetti BookInfo. Questo metodo crea la raccolta 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.

    Nota Nota

    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.

    
    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.

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 una raccolta di oggetti BookInfo che vengono passati dall'host:

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

  • Vengono rimossi dalla raccolta 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.

    
    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;
        }
    }
    
    }
    
    
    

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)

    Nota Nota

    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.

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.

Mostra: