Procedura dettagliata: passaggio di insiemi tra host e componenti aggiuntivi
Aggiornamento: Luglio 2008
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.
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 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 questa procedura dettagliata, è necessario disporre dei seguenti componenti:
Visual Studio.
Il file di esempio books.xml che può essere copiato da Sample XML File (books.xml).
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
In Visual Studio creare un nuovo progetto denominato LibraryContracts, basandolo sul modello Libreria di classi.
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.
Nota: 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
Nella soluzione di Visual Studio denominata BooksPipeline aprire il progetto LibraryContracts.
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.
In Esplora soluzioni aggiungere riferimenti ai seguenti assembly per il progetto.
System.AddIn.Contract.dll
System.AddIn.dll
Nel file di classe aggiungere riferimenti agli spazi dei nomi System.AddIn.Contract e System.AddIn.Pipeline.
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.
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
Aggiungere un nuovo progetto denominato AddInViews alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.
In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.
In Esplora soluzioni aggiungere un riferimento a System.AddIn.dll per il progetto AddInViews.
Rinominare la classe predefinita LibraryManager del progetto e rendere la classe abstract (MustInherit in Visual Basic).
Nel file di classe aggiungere un riferimento allo spazio dei nomi System.AddIn.Pipeline.
La classe LibraryManager viene utilizzata per attivare la pipeline, pertanto è necessario applicare l'attributo AddInBaseAttribute.
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); } }
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.
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
Aggiungere un nuovo progetto denominato HostViews alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.
In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.
Rinominare la classe predefinita LibraryManager del progetto e rendere la classe abstract (MustInherit in Visual Basic).
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); } }
Aggiungere una classe abstract (classeMustInherit in Visual Basic) al progetto e denominarla BookInfo.
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 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 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
Aggiungere un nuovo progetto denominato AddInSideAdapters alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.
In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.
In Esplora soluzioni aggiungere riferimenti ai seguenti assembly per il progetto AddInSideAdapters.
System.AddIn.dll
System.AddIn.Contract.dll
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.
Denominare il file di classe BookInfoContractToViewAddInAdapter.
Nel file di classe aggiungere un riferimento allo spazio dei nomi System.AddIn.Pipeline.
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.
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; } } }
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.
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; } } }
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; } } }
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 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 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
Aggiungere un nuovo progetto denominato HostSideAdapters alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.
In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.
In Esplora soluzioni aggiungere riferimenti ai seguenti assembly per il progetto HostSideAdapters.
System.AddIn.dll
System.AddIn.Contract.dll
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.
Nel file di classe aggiungere un riferimento allo spazio dei nomi System.AddIn.Pipeline.
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.
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; } } }
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.
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; } } }
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; } } }
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
Aggiungere un nuovo progetto denominato BookStore alla soluzione BooksPipeline, basandolo sul modello Applicazione console.
In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.
In Esplora soluzioni aggiungere un riferimento all'assembly System.AddIn.dll per il progetto BookStore.
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.
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.
Nel file di classe aggiungere riferimenti agli spazi dei nomi System.AddIn.Pipeline e per il segmento di visualizzazione host.
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.
Utilizzare il codice seguente per l'applicazione host.
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.
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
Aggiungere un nuovo file XML al progetto BookStore. Nella finestra di dialogo Aggiungi nuovo elemento, denominare il file books.xml.
Sostituire il contenuto predefinito di books.xml con il codice XML incluso in Sample XML File (books.xml).
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
Aggiungere un nuovo progetto denominato BooksAddin alla soluzione BooksPipeline, basandolo sul modello Libreria di classi.
In Visual Basic, aprire Proprietà per il progetto e utilizzare la scheda Applicazione per eliminare il valore predefinito fornito per Spazio dei nomi radice.
In Esplora soluzioni aggiungere un riferimento all'assembly System.AddIn.dll per il progetto BooksAddin.
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.
Nel file di classe aggiungere riferimenti agli spazi dei nomi System.AddIn e per il segmento di visualizzazione del componente aggiuntivo.
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
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.
Progetto
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: 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.
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
Al prompt dei comandi passare alla directory radice della pipeline ed eseguire l'applicazione host. In questo esempio l'applicazione host è BookStore.exe.
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.
Premere un tasto qualsiasi per chiudere l'applicazione.
Vedere anche
Attività
Procedura dettagliata: creazione di un'applicazione estendibile
Concetti
Requisiti di sviluppo delle pipeline
Contratti, visualizzazioni e adattatori
Cronologia delle modifiche
Date |
History |
Motivo |
---|---|---|
Luglio 2008 |
Errori corretti nel testo. Aggiunta una nota sul mantenimento di un riferimento al contratto. |
Commenti e suggerimenti dei clienti. |