Procédure pas à pas : passage de collections entre des hôtes et des compléments
Cette procédure pas à pas décrit comment créer un pipeline qui passe une collection d'objets personnalisés entre un complément et un hôte. Étant donné que les types de la collection ne sont pas sérialisables, des classes supplémentaires définissant des adaptateurs de vue en contrat et de contrat en vue doivent être ajoutées aux segments d'adaptateur pour que le flux de types puisse franchir la limite d'isolation.
Dans ce scénario, le complément met à jour une collection d'objets book (livre) pour l'hôte. Chaque objet book contient des méthodes qui obtiennent et définissent le titre du livre, l'éditeur, le prix et d'autres données.
Comme exemple, l'hôte crée une collection de livres ; le complément diminue de 20 % le prix de tous les livres informatiques et supprime tous les livres d'horreur de la collection. Le complément crée ensuite un objet book pour le livre le mieux vendu et le passe à l'hôte comme un objet unique.
Cette procédure pas à pas décrit les tâches suivantes :
Création d'une solution Visual Studio.
Création de la structure de répertoires du pipeline.
Création des contrats et vues pour les objets qui doivent être passés dans un sens et dans l'autre à travers la limite d'isolation.
Création des adaptateurs côté complément et côté hôte requis pour passer les objets à travers la limite d'isolation.
Création de l'hôte.
Création du complément.
Déploiement du pipeline.
Exécution de l'application hôte.
Remarque |
---|
Une partie du code indiqué dans cette procédure pas à pas contient des références à des espace de noms superflues.Les étapes de la procédure reflètent correctement les références requises en Visual Studio. |
Vous trouverez des exemples de code supplémentaires, ainsi que des présentations technologiques destinées aux clients des outils de génération de pipelines de compléments, sur le site Managed Extensibility and Add-In Framework (en anglais) de CodePlex.
Composants requis
Pour exécuter cette procédure pas à pas, vous devez disposer des composants suivants :
Visual Studio.
le fichier d'exemple books.xml, qui peut être copié à partir de Sample XML File (books.xml).
Création d'une solution Visual Studio
Utilisez une solution dans Visual Studio pour contenir les projets de vos segments de pipeline.
Pour créer la solution de pipeline
Dans Visual Studio, créez un projet nommé LibraryContracts. Basez-le sur le modèle Bibliothèque de classes.
Nommez la solution BooksPipeline.
Création de la structure de répertoires du pipeline
Le modèle de complément requiert que les assemblys du segment de pipeline soient placés dans une structure de répertoires spécifiée.
Pour créer la structure de répertoires du pipeline
Créez la structure de dossier suivante sur votre ordinateur. Vous pouvez la localiser n'importe où, y compris dans les dossiers de votre solution Visual Studio.
Pipeline AddIns BooksAddIn AddInSideAdapters AddInViews Contracts HostSideAdapters
Tous les noms de dossier doivent être spécifiés exactement comme indiqué ici, à l'exception du nom de dossier racine et des noms de dossiers de complément individuels. Cet exemple utilise Pipeline comme nom de dossier racine et BooksAddIn comme nom de dossier de complément.
Remarque Pour des raisons de commodité, la procédure pas à pas place l'application hôte dans le dossier racine de pipeline.À l'étape appropriée, la procédure pas à pas explique comment modifier le code si l'application est à un emplacement différent.
Pour plus d'informations sur la structure des dossiers du pipeline, consultez Spécifications du développement de pipelines.
Création du contrat et des vues
Le segment de contrat pour ce pipeline définit deux interfaces :
Interface IBookInfoContract.
Cette interface contient les méthodes, telles que Author, qui contiennent des informations sur un livre.
Interface ILibraryManagerContract.
Cette interface contient la méthode ProcessBooks que le complément utilise pour traiter une collection de livres. Chaque livre représente un contrat IBookInfoContract. L'interface contient également la méthode GetBestSeller que le complément utilise pour fournir à l'hôte un objet book représentant le livre le mieux vendu.
Pour créer le contrat
Dans la solution Visual Studio nommée BooksPipeline, ouvrez le projet LibraryContracts.
En Visual Basic, ouvrez Propriétés pour le projet LibraryContracts et utilisez l'onglet Application pour supprimer la valeur par défaut fournie pour Espace de noms racine. Par défaut, Espace de noms racine a pour valeur le nom du projet.
Dans l'Explorateur de solutions, ajoutez au projet des références aux assemblys suivants :
Sytem.AddIn.Contract.dll
System.AddIn.dll
Dans le fichier de classe, ajoutez des références aux espaces de noms System.AddIn.Contract et System.AddIn.Pipeline.
Dans le fichier de classe, remplacez la déclaration de classe par défaut par deux interfaces :
L'interface ILibraryManagerContract étant utilisée pour activer le complément, elle doit avoir l'attribut AddInContractAttribute.
L'interface IBookInfoContract représentant un objet passé entre l'hôte et le complément, elle ne requiert pas d'attribut.
Les deux interfaces doivent hériter de l'interface IContract.
Utilisez le code suivant pour ajouter les interfaces IBookInfoContract et 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(); } }
Étant donné que la vue de complément et la vue hôte ont le même code, vous pouvez facilement créer ces vues en même temps. Elles diffèrent par un seul facteur : la vue de complément qui est utilisée pour activer ce segment du pipeline requiert l'attribut AddInBaseAttribute ; la vue hôte ne requiert pas d'attributs.
La vue de complément pour ce pipeline contient deux classes abstraites. La classe BookInfo fournit la vue pour l'interface IBookInfoContract et la classe LibraryManager fournit la vue pour l'interface ILibraryManagerContract.
Pour créer la vue de complément
Ajoutez un nouveau projet nommé AddInViews à la solution BooksPipeline. Basez-le sur le modèle Bibliothèque de classes.
En Visual Basic, ouvrez Propriétés pour le projet et utilisez l'onglet Application pour supprimer la valeur par défaut fournie pour Espace de noms racine.
Dans l'Explorateur de solutions, ajoutez au projet AddInViews une référence à System.AddIn.dll.
Renommez la classe par défaut du projet LibraryManager et définissez la classe comme abstract (MustInherit en Visual Basic).
Dans le fichier de classe, ajoutez une référence à l'espace de noms System.AddIn.Pipeline.
La classe LibraryManager étant utilisée pour activer le pipeline, vous pouvez appliquer l'attribut AddInBaseAttribute.
Utilisez le code suivant pour terminer la classe LibraryManager abstraite.
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); } }
Ajoutez une classe abstract (classe MustInherit en Visual Basic) au projet et nommez-la BookInfo. La classe BookInfo représente un objet passé entre l'hôte et le complément. Cette classe n'est pas utilisée pour activer le pipeline, elle ne requiert donc pas d'attributs.
Utilisez le code suivant pour terminer la classe BookInfo abstraite.
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(); } }
Pour créer la vue hôte
Ajoutez un nouveau projet nommé HostViews à la solution BooksPipeline. Basez-le sur le modèle Bibliothèque de classes.
En Visual Basic, ouvrez Propriétés pour le projet et utilisez l'onglet Application pour supprimer la valeur par défaut fournie pour Espace de noms racine.
Renommez la classe par défaut du projet LibraryManager et définissez la classe comme abstract (MustInherit en Visual Basic).
Utilisez le code suivant pour terminer la classe LibraryManager abstraite.
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); } }
Ajoutez une classe abstract (classe MustInherit en Visual Basic) au projet et nommez-la BookInfo.
Utilisez le code suivant pour terminer la classe BookInfo abstraite.
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(); } }
Création de l'adaptateur côté complément
L'assembly d'adaptateur côté complément pour ce pipeline contient quatre classes d'adaptateur :
BookInfoContractToViewAddInAdapter
Cet adaptateur est appelé lorsque l'hôte passe un objet BookInfo au complément, soit tout seul soit dans le cadre d'une collection. Cette classe convertit le contrat de l'objet BookInfo en vue. La classe hérite de la vue de complément et implémente les méthodes abstraites de la vue en appelant le contrat passé au constructeur de la classe.
Le constructeur de cet adaptateur prend un contrat afin qu'un objet ContractHandle puisse être appliqué au contrat pour implémenter la gestion de la durée de vie.
Important ContractHandle est critique pour la gestion de la durée de vie.Si vous ne parvenez pas à conserver une référence à l'objet ContractHandle, le garbage collection la récupérera, et le pipeline s'arrêtera quand le programme ne s'y attend pas.Cela peut provoquer des erreurs difficiles à diagnostiquer, telles que AppDomainUnloadedException.L'arrêt est une étape normale dans la vie d'un pipeline ; il est donc impossible pour le code de gestion de la durée de vie de détecter que cette condition est une erreur.
BookInfoViewToContractAddInAdapter
Cet adaptateur est appelé lorsque le complément passe un objet BookInfo à l'hôte. Cette classe convertit la vue de complément de l'objet BookInfo en contrat. La classe hérite du contrat et implémente le contrat en appelant la vue de complément passée au constructeur de la classe. Cet adaptateur est marshalé vers l'hôte en tant que contrat.
LibraryManagerViewToContractAddInAdapter
Il s'agit du type qui est retourné à l'hôte à partir de son appel pour activer le complément. Ce type est appelé lorsque l'hôte appelle le complément, notamment l'appel qui passe une collection d'objets hôtes (IList<BookInfo>) au complément. Cette classe convertit le contrat ILibraryManagerContract en vue hôte LibraryManager. Cette classe hérite de la vue hôte et implémente le contrat en appelant la vue passée à son constructeur.
Étant donné qu'une collection de types personnalisés, les objets BookInfo, doit être marshalée à travers la limite d'isolation, cet adaptateur utilise la classe CollectionAdapters. Cette classe fournit des méthodes pour convertir une collection IList<T> en une collection IListContract<T>, ce qui permet à la collection de passer à travers la limite d'isolation pour atteindre l'autre côté du pipeline.
BookInfoAddInAdapter
Les méthodes static (méthodesShared en Visual Basic) de cet adaptateur sont appelées par la classe LibraryManagerViewToContractAddInAdapter pour adapter un contrat ou une vue, ou retourner un contrat ou une vue existants. Cela empêche la création d'un adaptateur supplémentaire lorsqu'un objet effectue un aller-retour entre l'hôte et le complément.
Pour créer l'adaptateur côté complément
Ajoutez un nouveau projet nommé AddInSideAdapters à la solution BooksPipeline. Basez-le sur le modèle Bibliothèque de classes.
En Visual Basic, ouvrez Propriétés pour le projet et utilisez l'onglet Application pour supprimer la valeur par défaut fournie pour Espace de noms racine.
Dans l'Explorateur de solutions, ajoutez au projet AddInSideAdapters des références aux assemblys suivants :
System.AddIn.dll
System.AddIn.Contract.dll
Dans l'Explorateur de solutions, ajoutez au projet AddInSideAdapters des références aux projets suivants :
AddInViews
LibraryContracts
Dans la référence Propriétés, affectez la valeur False à Copie locale pour ces références, afin d'empêcher que les assemblys référencés soient copiés dans le dossier de génération local. Les assemblys se trouvent dans le structure de répertoires du pipeline, comme décrit un peu loin dans la section « Déployer la procédure Pipeline » de cette procédure.
Nommez le fichier de classe BookInfoContractToViewAddInAdapter.
Dans le fichier de classe, ajoutez une référence à l'espace de noms System.AddIn.Pipeline.
Utilisez le code suivant pour ajouter la classe BookInfoContractToViewAddInAdapter. La classe ne requiert pas d'attribut, car elle n'est pas utilisée pour activer le pipeline. La méthode GetSourceContract internal (Friend en Visual Basic) est utilisée par la classe BookInfoAddInAdapter pour éviter de créer un adaptateur supplémentaire lorsqu'un objet effectue un aller-retour entre l'hôte et le complément.
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; } } }
Utilisez le code suivant pour ajouter la classe BookInfoViewToContractAddInAdapter au projet AddInSideAdapters. La classe ne requiert pas d'attribut, car elle n'est pas utilisée pour activer le pipeline. La méthode GetSourceView internal (Friend en Visual Basic) est utilisée par la classe BookInfoAddInAdapter pour éviter de créer un adaptateur supplémentaire lorsqu'un objet effectue un aller-retour entre l'hôte et le complément.
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; } } }
Utilisez le code suivant pour ajouter la classe LibraryManagerViewToContractAddInAdapter au projet AddInSideAdapters. Cette classe requiert l'attribut AddInAdapterAttribute, car elle est utilisée pour activer le pipeline.
La méthode ProcessBooks indique comment passer une liste de livres à travers la limite d'isolation. Elle utilise la méthode CollectionAdapters.ToIList pour convertir la liste. Pour convertir les objets de la liste, elle passe des délégués pour les méthodes d'adaptateur fournies par la classe BookInfoAddInAdapter.
La méthode GetBestSeller indique comment passer un objet BookInfo unique à travers la limite d'isolation.
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; } } }
Utilisez le code suivant pour ajouter la classe BookInfoAddInAdapter au projet AddInSideAdapters. La classe contient deux méthodes static (méthodes Shared en Visual Basic) : ContractToViewAdapter et ViewToContractAdapter. Les méthodes sont internal (Friend en Visual Basic) parce qu'elles sont utilisées uniquement par les autres classes d'adaptateur. Le but de ces méthodes est d'éviter de créer un adaptateur supplémentaire lorsqu'un objet effectue un aller-retour dans l'une ou l'autre direction entre l'hôte et le complément. Ces méthodes doivent être fournies pour les adaptateurs qui passent des objets à travers la limite d'isolation.
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); } } } }
Création de l'adaptateur côté hôte
L'assembly d'adaptateur côté hôte pour ce pipeline contient quatre classes d'adaptateur :
BookInfoContractToViewHostAdapter
Cet adaptateur est appelé lorsque le complément passe un objet BookInfo à l'hôte, soit tout seul soit dans le cadre d'une collection. Cette classe convertit le contrat de l'objet BookInfo en vue. La classe hérite de la vue hôte et implémente les méthodes abstraites de la vue en appelant le contrat passé au constructeur de la classe.
Le constructeur de cet adaptateur prend un contrat pour son constructeur afin qu'un objet ContractHandle puisse être appliqué au contrat pour implémenter la gestion de la durée de vie.
Important ContractHandle est critique pour la gestion de la durée de vie.Si vous ne parvenez pas à conserver une référence à l'objet ContractHandle, le garbage collection la récupérera, et le pipeline s'arrêtera quand le programme ne s'y attend pas.Cela peut provoquer des erreurs difficiles à diagnostiquer, telles que AppDomainUnloadedException.L'arrêt est une étape normale dans la vie d'un pipeline ; il est donc impossible pour le code de gestion de la durée de vie de détecter que cette condition est une erreur.
BookInfoViewToContractHostAdapter
Cet adaptateur est appelé lorsque l'hôte passe un objet BookInfo au complément. Cette classe convertit la vue hôte de l'objet BookInfo en contrat. La classe hérite du contrat et implémente le contrat en appelant la vue de complément passée au constructeur de la classe. Cet adaptateur est marshalé vers le complément en tant que contrat.
LibraryManagerContractToViewHostAdapter
Cet adaptateur est appelé lorsque l'hôte passe une collection d'objets BookInfo au complément. Le complément effectue son implémentation de la méthode ProcessBooks sur cette collection.
Cette classe convertit la vue hôte de l'objet LibraryManager en contrat. Elle hérite du contrat et implémente le contrat en appelant la vue hôte passée au constructeur de la classe.
Étant donné qu'une collection de types personnalisés, les objets BookInfo, doit être marshalée à travers la limite d'isolation, cet adaptateur utilise la classe CollectionAdapters. Cette classe fournit des méthodes pour convertir une collection IList<T> en une collection IListContract<T>, ce qui permet à la collection de passer à travers la limite d'isolation pour atteindre l'autre côté du pipeline.
BookInfoHostAdapter
Cet adaptateur est appelé par la classe LibraryManagerViewToContractHostAdapter pour retourner tous les contrats ou vues existants pour l'adaptation au lieu de créer des instances pour l'appel. Cela empêche la création d'un adaptateur supplémentaire lorsqu'un objet effectue un aller-retour dans l'une ou l'autre direction entre l'hôte et le complément.
Pour créer l'adaptateur côté hôte
Ajoutez un nouveau projet nommé HostSideAdapters à la solution BooksPipeline. Basez-le sur le modèle Bibliothèque de classes.
En Visual Basic, ouvrez Propriétés pour le projet et utilisez l'onglet Application pour supprimer la valeur par défaut fournie pour Espace de noms racine.
Dans l'Explorateur de solutions, ajoutez au projet HostSideAdapters des références aux assemblys suivants :
System.AddIn.dll
System.AddIn.Contract.dll
Dans l'Explorateur de solutions, ajoutez au projet HostSideAdapters des références aux projets suivants :
HostViews
LibraryContracts
Dans la référence Propriétés, affectez la valeur False à Copie locale pour ces références, afin d'empêcher que les assemblys référencés soient copiés dans le dossier de génération local.
Dans le fichier de classe, ajoutez une référence à l'espace de noms System.AddIn.Pipeline.
Utilisez le code suivant pour ajouter la classe BookInfoContractToViewHostAdapter. La classe ne requiert pas d'attribut, car elle n'est pas utilisée pour activer le pipeline. La méthode GetSourceContract internal (Friend en Visual Basic) est utilisée par la classe BookInfoAddInAdapter pour éviter de créer un adaptateur supplémentaire lorsqu'un objet effectue un aller-retour entre l'hôte et le complément.
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; } } }
Utilisez le code suivant pour ajouter BookInfoViewToContractHostAdapter au projet HostSideAdapters. La classe ne requiert pas d'attribut, car elle n'est pas utilisée pour activer le pipeline. La méthode GetSourceView internal (Friend en Visual Basic) est utilisée par la classe BookInfoAddInAdapter pour éviter de créer un adaptateur supplémentaire lorsqu'un objet effectue un aller-retour entre l'hôte et le complément.
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; } } }
Utilisez le code suivant pour ajouter LibraryManagerContractToViewHostAdapter au projet HostSideAdapters. Cette classe requiert l'attribut HostAdapterAttribute, car elle est utilisée pour activer le pipeline.
La méthode ProcessBooks indique comment passer une liste de livres à travers la limite d'isolation. Elle utilise la méthode CollectionAdapters.ToIListContract pour convertir la liste. Pour convertir les objets de la liste, elle passe des délégués pour les méthodes d'adaptateur fournies par la classe BookInfoHostAdapter.
La méthode GetBestSeller indique comment passer un objet BookInfo unique à travers la limite d'isolation.
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; } } }
Utilisez le code suivant pour ajouter la classe BookInfoHostAdapter au projet HostSideAdapters. La classe contient deux méthodes static (méthodes Shared en Visual Basic) : ContractToViewAdapter et ViewToContractAdapter. Les méthodes sont internal (Friend en Visual Basic) parce qu'elles sont utilisées uniquement par les autres classes d'adaptateur. Le but de ces méthodes est d'éviter de créer un adaptateur supplémentaire lorsqu'un objet effectue un aller-retour dans l'une ou l'autre direction entre l'hôte et le complément. Ces méthodes doivent être fournies pour les adaptateurs qui passent des objets à travers la limite d'isolation.
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); } } } }
Création de l'hôte
Une application hôte interagit avec le complément via la vue hôte. Elle utilise les méthodes d'activation et de découverte de complément fournies par les classes AddInStore et AddInToken pour effectuer les opérations suivantes :
Régénérer le cache du pipeline et les informations de complément.
Rechercher des compléments de type LibraryManager sous le répertoire racine du pipeline spécifié.
Inviter l'utilisateur à sélectionner le complément à utiliser. Dans cet exemple, un seul complément est disponible.
Activer le complément sélectionné dans un nouveau domaine d'application avec un niveau de confiance de sécurité spécifié.
Appeler la méthode ProcessBooks pour passer une collection d'objets BookInfo au complément. Le complément appelle son implémentation de la méthode ProcessBooks et procède à des opérations telles que la réduction de 20 % du prix des livres d'informatique.
Appelle la méthode GetBestSeller que le complément utilise pour retourner un objet BookInfo avec des informations sur le livre le mieux vendu.
Appelle la méthode Data pour obtenir le taux de TVA actuel à partir du complément. Cette méthode prend et retourne une chaîne qui constitue un type référence sérialisable sealed. Par conséquent, la méthode peut passer, via la limite d'isolation, de l'autre côté du pipeline sans utiliser d'adaptateurs de vue en contrat ou de contrat en vue.
L'hôte dispose d'une méthode CreateBooks qui crée une collection d'objets BookInfo. Cette méthode crée la collection en utilisant le fichier d'exemple books.xml qui est disponible à partir de Sample XML File (books.xml).
Pour créer l'hôte
Ajoutez un nouveau projet nommé BookStore à la solution BooksPipeline. Basez-le sur le modèle Application console.
En Visual Basic, ouvrez Propriétés pour le projet et utilisez l'onglet Application pour supprimer la valeur par défaut fournie pour Espace de noms racine.
Dans l'Explorateur de solutions, ajoutez au projet BookStore une référence à l'assembly System.AddIn.dll.
Ajoutez une référence de projet au projet HostViews. Dans la référence Propriétés, affectez la valeur False à Copie locale pour cette référence, afin d'empêcher que l'assembly référencé soit copié dans le dossier de génération local.
En Visual Basic, modifiez le module en une classe :
Excluez le module par défaut du projet, puis ajoutez une classe nommée Program.
Remplacez le mot-clé Public par le mot-clé Friend.
Ajoutez une procédure Shared Sub Main() à la classe.
Utilisez l'onglet Application de la boîte de dialogue Propriétés du projet pour affecter à Objet de démarrage la valeur Sub Main.
Dans le fichier de classe, ajoutez des références à System.AddIn.Pipeline et aux espaces de noms du segment de la vue hôte.
Dans l'Explorateur de solutions, sélectionnez la solution puis, dans le menu Projet, sélectionnez Propriétés. Dans la boîte de dialogue Pages de propriétés de Solution, définissez le Projet de démarrage unique comme projet d'application hôte.
Utilisez le code suivant pour l'application hôte.
Remarque Dans le code, modifiez l'emplacement à partir duquel le fichier books.xml est chargé en "books.xml",, afin que le fichier soit chargé à partir du dossier d'application.Si vous souhaitez placer l'application dans un emplacement autre que le dossier Pipeline, modifiez la ligne de code qui définit la variable addInRoot, afin que la variable contienne le chemin d'accès à votre structure de répertoires du 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; } } }
Pour créer le fichier de données books.xml
Ajoutez un nouveau fichier XML au projet BookStore. Dans la boîte de dialogue Ajouter un nouvel élément, nommez le fichier books.xml.
Remplacez le contenu par défaut de books.xml par le XML provenant de Sample XML File (books.xml).
Dans l'Explorateur de solutions, sélectionnez books.xml, et dans Propriétés, affectez à Copier dans le répertoire de sortie la valeur Toujours copier.
Création du complément
Un complément implémente les méthodes spécifiées par la vue de complément. Ce complément implémente la méthode ProcessBooks. La méthode exécute les opérations suivantes sur une collection d'objets BookInfo que l'hôte lui passe :
Diminue de 20 % le prix de tous les livres informatiques.
Supprime tous les livres d'horreur de la collection.
Ce complément implémente également la méthode GetBestSeller en passant un objet BookInfo qui décrit le livre le mieux vendu à l'hôte.
Pour créer le complément
Ajoutez un nouveau projet nommé BooksAddin à la solution BooksPipeline. Basez-le sur le modèle Bibliothèque de classes.
En Visual Basic, ouvrez Propriétés pour le projet et utilisez l'onglet Application pour supprimer la valeur par défaut fournie pour Espace de noms racine.
Dans l'Explorateur de solutions, ajoutez au projet BooksAddin une référence à l'assembly System.AddIn.dll.
Ajoutez une référence de projet au projet AddInViews. Dans la référence Propriétés, affectez la valeur False à Copie locale pour cette référence, afin d'empêcher que l'assembly référencé soit copié dans le dossier de génération local.
Dans le fichier de classe, ajoutez des références à System.AddIn et aux espaces de noms du segment de la vue de complément.
Utilisez le code suivant pour l'application de complément.
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; } } }
Déploiement du pipeline
Vous êtes maintenant prêt à générer et déployer les segments de complément vers la structure de répertoires du pipeline requise.
Pour déployer les segments vers le pipeline
Pour chaque projet dans la solution, utilisez l'onglet Génération de Propriétés du projet (onglet Compiler en Visual Basic) pour définir la valeur du Chemin de sortie (Chemin de sortie de la génération en Visual Basic), comme indiqué dans le tableau suivant.
Projet
Chemin d'accès
BooksAddIn
Pipeline\AddIns\CalcV1
AddInSideAdapters
Pipeline\AddInSideAdapters
AddInViews
Pipeline\AddInViews
LibraryContracts
Pipeline\Contracts
BookStore
Pipeline (ou votre propre répertoire de l'application)
HostSideAdapters
Pipeline\HostSideAdapters
HostViews
Pipeline (ou votre propre répertoire de l'application)
Remarque Si vous avez décidé de mettre votre application dans un emplacement autre que le dossier Pipeline, veillez à modifier le code hôte qui spécifie l'emplacement du répertoire racine du pipeline.
Générez la solution Visual Studio.
Pour plus d'informations sur le déploiement vers le pipeline, consultez Spécifications du développement de pipelines.
Exécution de l'application hôte
Vous êtes maintenant prêt à exécuter l'hôte et à interagir avec le complément.
Pour exécuter l'application hôte
À l'invite de commandes, accédez au répertoire racine du pipeline et exécutez l'application hôte. Dans cet exemple, l'application hôte est BookStore.exe.
L'hôte recherche tous les compléments disponibles de son type et vous invite à sélectionner un complément. Entrez 1 pour le seul complément disponible.
L'hôte active le complément et l'utilise pour effectuer plusieurs opérations dans la liste de livres.
Appuyez sur n'importe quelle touche pour fermer l'application.
Voir aussi
Tâches
Procédure pas à pas : création d'une application extensible
Procédure pas à pas : activation de la compatibilité descendante lorsque votre hôte change