Share via


チュートリアル : アドインとホスト間でのコレクションの受け渡し

このチュートリアルでは、アドインとホスト間でカスタム オブジェクトのコレクションを受け渡すパイプラインを作成する方法を説明します。 コレクション内の型はシリアル化できないため、型のフローが分離境界を越えられるように、ビューからコントラクトへのアダプターおよびコントラクトからビューへのアダプターをアダプター セグメントに追加する必要があります。

このシナリオでは、ホストに対して書籍のオブジェクトのコレクションを更新します。 それぞれの書籍オブジェクトには、書籍のタイトル、版元、価格などのデータを取得し設定するためのメソッドが含まれています。

例として、ホストで書籍のコレクションを作成します。アドインを使用して、コンピューター関連の全書籍の価格を 20% 値下げし、すべてのホラー小説をコレクションから削除します。 次に、アドインを使用してベストセラー書籍を表す書籍オブジェクトを新たに作成し、それを単一のオブジェクトとしてホストに渡します。

このチュートリアルでは、次の作業について説明します。

  • Visual Studio ソリューションの作成

  • パイプライン ディレクトリ構造の作成

  • 分離境界を越えて渡される必要があるオブジェクトのコントラクトとビューの作成

  • 分離境界を越えてオブジェクトを渡すのに必要なアドイン側アダプターとホスト側アダプターの作成

  • ホストの作成

  • アドインの作成

  • パイプラインの配置

  • ホスト アプリケーションの実行

メモメモ

このチュートリアルに示されているコードによっては、余分な名前空間参照が含まれています。チュートリアルの手順は、Visual Studio で必要な参照を正確に反映しています。

CodePlex の「Managed Extensibility and Add-In Framework」サイトには、その他のサンプル コードや、アドイン パイプラインのビルドに使用するツールのカスタマー テクノロジ プレビューが掲載されています。

必須コンポーネント

このチュートリアルを実行するには、次のコンポーネントが必要です。

Visual Studio ソリューションの作成

Visual Studio のソリューションを使用して、パイプライン セグメントのプロジェクトを格納します。

パイプライン ソリューションを作成するには

  1. Visual Studio で、LibraryContracts という名前の新規プロジェクトを作成します。 それにクラス ライブラリ テンプレートを適用します。

  2. ソリューションに "BooksPipeline" という名前を付けます。

パイプライン ディレクトリ構造の作成

アドイン モデルでは、指定したディレクトリ構造内にパイプライン セグメント アセンブリが配置される必要があります。

パイプライン ディレクトリ構造を作成するには

  • コンピューター上に、次のフォルダー構造を作成します。 これは、Visual Studio ソリューションのフォルダー内を含め、任意の場所に配置できます。

    Pipeline
      AddIns
        BooksAddIn
      AddInSideAdapters
      AddInViews
      Contracts
      HostSideAdapters
    

    フォルダー名はここに示したとおりに正確に指定する必要がありますが、ルート フォルダーの名前と個々のアドイン フォルダーの名前は例外です。 この例では、ルート フォルダー名を Pipeline とし、アドイン フォルダー名を BooksAddIn としています。

    メモメモ

    チュートリアルでは、便宜上、ホスト アプリケーションをパイプラインのルート フォルダーに配置しています。アプリケーションが別の場所にある場合は、チュートリアルの該当の手順で、コードを変更する方法について説明します。

    パイプライン フォルダー構造の詳細については、「パイプライン開発の必要条件」を参照してください。

コントラクトとビューの生成

このパイプラインのコントラクト セグメントで、2 つのインターフェイスが定義されます。

  • IBookInfoContract インターフェイスです。

    このインターフェイスには、Author など、書籍に関する情報を含むメソッドが含まれています。

  • ILibraryManagerContract インターフェイスです。

    このインターフェイスには、書籍のコレクションを処理するためにアドインで使用される ProcessBooks メソッドが含まれています。 それぞれの書籍が IBookInfoContract コントラクトを表します。 さらに、このインターフェイスにはベストセラー書籍を表す書籍オブジェクトをホストに渡すためにアドインで使用される GetBestSeller メソッドも含まれています。

コントラクトを作成するには

  1. BooksPipeline という名前の Visual Studio ソリューションで、LibraryContracts プロジェクトを開きます。

  2. Visual Basic で、LibraryContracts の [プロパティ] を開き、[アプリケーション] タブを使用して、[ルート名前空間] に指定されている既定値を削除します。 既定では、[ルート名前空間] にはプロジェクト名が設定されています。

  3. ソリューション エクスプローラーで、プロジェクトに次のアセンブリへの参照を追加します。

    Sytem.AddIn.Contract.dll

    System.AddIn.dll

  4. クラス ファイルに、System.AddIn.Contract 名前空間と System.AddIn.Pipeline 名前空間への参照を追加します。

  5. クラス ファイル内の既定のクラス宣言を 2 つのインターフェイスに置き換えます。

    • ILibraryManagerContract インターフェイスはアドインをアクティブ化するときに使用されるため、AddInContractAttribute 属性が必要です。

    • IBookInfoContract インターフェイスは、ホストとアドイン間で渡されるオブジェクトを表すため、属性は必要ありません。

    両方のインターフェイスとも、IContract インターフェイスを継承する必要があります。

  6. 次のコードを使用して、IBookInfoContract インターフェイスと 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();
        }
    }
    

アドイン ビューとホスト ビューは、コードが同じであるため、ビューを同時に簡単に作成できます。 この 2 つのビューの相違点は、パイプラインのこのセグメントをアクティブ化するときに使用するアドイン ビューには AddInBaseAttribute 属性が必要ですが、ホスト ビューには属性が必要ないということのみです。

このパイプラインのアドイン ビューには、2 つの抽象クラスが含まれています。 BookInfo クラスは IBookInfoContract インターフェイスのビューを提供し、LibraryManager クラスは ILibraryManagerContract インターフェイスのビューを提供します。

アドイン ビューを作成するには

  1. BooksPipeline ソリューションに AddInViews という名前の新規プロジェクトを追加します。 それにクラス ライブラリ テンプレートを適用します。

  2. Visual Basic で、プロジェクトの [プロパティ] を開き、[アプリケーション] タブを使用して、[ルート名前空間] に指定されている既定値を削除します。

  3. ソリューション エクスプローラーで、AddInViews プロジェクトに System.AddIn.dll への参照を追加します。

  4. プロジェクトの既定のクラス名を LibraryManager に変更し、クラスを abstract (Visual Basic では MustInherit) にします。

  5. クラス ファイルで、System.AddIn.Pipeline 名前空間への参照を追加します。

  6. LibraryManager クラスはパイプラインをアクティブ化するときに使用されるため、AddInBaseAttribute 属性を適用する必要があります。

  7. 次のコードを使用して、LibraryManager 抽象クラスを完了します。

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsBase
    ' The AddInBaseAttribute
    ' identifes this pipeline
    ' segment as an add-in view.
    <AddInBase> _
    Public MustInherit Class LibraryManager
        Public MustOverride Sub ProcessBooks(ByVal books As IList(Of BookInfo))
        Public MustOverride Function GetBestSeller() As BookInfo
    
        Public MustOverride Function Data(ByVal txt As String) As String
    End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.AddIn.Pipeline;
    namespace LibraryContractsBase
    {
    // The AddInBaseAttribute
    // identifes this pipeline
    // segment as an add-in view.
    [AddInBase]
        public abstract class LibraryManager
        {
            public abstract void ProcessBooks(IList<BookInfo> books);
            public abstract BookInfo GetBestSeller();
    
            public abstract string Data(string txt);
        }
    }
    
  8. abstract クラス (Visual Basic では MustInherit) をプロジェクトに追加し、BookInfo という名前を付けます。 BookInfo クラスは、ホストとアドイン間で渡されるオブジェクトを表します。 このクラスを使用してパイプラインをアクティブ化することはないため、属性は必要ありません。

  9. 次のコードを使用して、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();
        }
    }
    

ホスト ビューを作成するには

  1. BooksPipeline ソリューションに HostViews という名前の新規プロジェクトを追加します。 それにクラス ライブラリ テンプレートを適用します。

  2. Visual Basic で、プロジェクトの [プロパティ] を開き、[アプリケーション] タブを使用して、[ルート名前空間] に指定されている既定値を削除します。

  3. プロジェクトの既定のクラス名を LibraryManager に変更し、クラスを abstract (Visual Basic では MustInherit) にします。

  4. 次のコードを使用して、LibraryManager 抽象クラスを完了します。

    
    Imports Microsoft.VisualBasic
    Imports System.Collections.Generic
    Namespace LibraryContractsHAV
    
    Public MustInherit Class LibraryManager
    
    Public MustOverride Sub ProcessBooks(ByVal books As System.Collections.Generic.IList(Of BookInfo))
    Public MustOverride Function GetBestSeller() As BookInfo
    
    Public MustOverride Function Data(ByVal txt As String) As String
    End Class
    End Namespace
    
    using System.Collections.Generic;
    namespace LibraryContractsHAV {
    
    public abstract class LibraryManager
    {
    
        public abstract void ProcessBooks(System.Collections.Generic.IList<BookInfo> books);
        public abstract BookInfo GetBestSeller();
    
        public abstract string Data(string txt);
    }
    }
    
  5. abstract クラス (Visual Basic では MustInherit) をプロジェクトに追加し、BookInfo という名前を付けます。

  6. 次のコードを使用して、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();
        }
    }
    

アドイン側アダプターの作成

このパイプラインのアドイン側アダプター アセンブリには、4 つの抽象クラスが含まれています。

  • BookInfoContractToViewAddInAdapter

    ホストからアドインに BookInfo オブジェクトが渡されるとき、このアドインが単独で、またはコレクションの一部として呼び出されます。 このクラスにより、BookInfo オブジェクトのコントラクトがビューに変換されます。 このクラスはアドイン ビューを継承し、クラスのコンストラクターに渡されるコントラクトを呼び出すことによって、ビューの抽象メソッドを実装します。

    このアダプターのコンストラクターはコントラクトを受け取ります。そのため、ContractHandle オブジェクトをコントラクトに適用して有効期間管理を実装できるようになります。

    重要 :重要

    有効期間の管理には、ContractHandle が重要です。ContractHandle オブジェクトへの参照を保持していないと、ガベージ コレクションによってオブジェクトが再利用され、プログラムで予期していないタイミングでパイプラインがシャットダウンすることになります。これは、AppDomainUnloadedException のような診断が困難なエラーの原因となる可能性があります。シャットダウンはパイプラインの正常な段階の 1 つであるため、有効期間を管理するコードでこの状態をエラーとして検出する方法はありません。

  • BookInfoViewToContractAddInAdapter

    アドインからホストに BookInfo オブジェクトが渡されるとき、このアダプターが呼び出されます。 このクラスにより、BookInfo オブジェクトのアドイン ビューがコントラクトに変換されます。 このクラスはコントラクトを継承し、クラスのコンストラクターに渡されるアドインを呼び出すことによって、コントラクトを実装します。 このアダプターはコントラクトとしてホストにマーシャリングされます。

  • LibraryManagerViewToContractAddInAdapter

    これは、アドインをアクティブにする呼び出しによってホストに返される型です。 ホスト オブジェクトのコレクション (IList<BookInfo>) をアドインに渡す呼び出しなどで、ホストがアドインを呼び出すときに、この型が呼び出されます。 このクラスにより、ILibraryManagerContract コントラクトが LibraryManager ホスト ビューに変換されます。 このクラスはホスト ビューを継承し、コンストラクターに渡されるビューを呼び出すことで、コントラクトを実装します。

    カスタム型のコレクションである BookInfo オブジェクトは、分離境界を越えてマーシャリングする必要があるため、このアダプターでは CollectionAdapters クラスが使用されます。 このクラスには、IList<T> コレクションを IListContract<T> コレクションに変換するメソッドがあります。これによって、分離境界を越えてコレクションをパイプラインの反対側に渡すことができます。

  • BookInfoAddInAdapter

    このアダプターの static メソッド (Visual Basic では Shared メソッド) は、LibraryManagerViewToContractAddInAdapter クラスによって呼び出されて、コントラクトまたはビューを適応するか、または、既存のコントラクトまたはビューを返します。 このため、オブジェクトがホストとアドイン間でラウンド トリップを行う場合に、追加のアダプターを作成しなくて済みます。

アドイン側アダプターを作成するには

  1. BooksPipeline ソリューションに AddInSideAdapters という名前の新規プロジェクトを追加します。 それにクラス ライブラリ テンプレートを適用します。

  2. Visual Basic で、プロジェクトの [プロパティ] を開き、[アプリケーション] タブを使用して、[ルート名前空間] に指定されている既定値を削除します。

  3. ソリューション エクスプローラーで、次のアセンブリへの参照を AddInSideAdapters プロジェクトに追加します。

    System.AddIn.dll

    System.AddIn.Contract.dll

  4. ソリューション エクスプローラーで、次のプロジェクトへの参照を AddInSideAdapters プロジェクトに追加します。

    AddInViews

    LibraryContracts

    参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、これらの参照の [プロパティ][ローカルにコピーする][False] に設定します。 このチュートリアルの後の手順の「パイプラインの配置」で説明するように、アセンブリはパイプライン ディレクトリ構造に配置されます。

  5. クラス ファイルに BookInfoContractToViewAddInAdapter という名前を付けます。

  6. クラス ファイルで、System.AddIn.Pipeline 名前空間への参照を追加します。

  7. 次のコードを使用して、BookInfoContractToViewAddInAdapter クラスを追加します。 このクラスを使用してパイプラインをアクティブ化することはないため、属性は必要ありません。 BookInfoAddInAdapter クラスで internal (Visual Basic では Friend) GetSourceContract メソッドを使用することにより、オブジェクトがホストとアドイン間でラウンド トリップを行う場合に、追加のアダプターを作成しなくて済みます。

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsAddInAdapters
    
    Public Class BookInfoContractToViewAddInAdapter
        Inherits LibraryContractsBase.BookInfo
        Private _contract As Library.IBookInfoContract
        Private _handle As System.AddIn.Pipeline.ContractHandle
        Public Sub New(ByVal contract As Library.IBookInfoContract)
            _contract = contract
            _handle = New ContractHandle(contract)
        End Sub
    
        Public Overrides Function ID() As String
            Return _contract.ID()
        End Function
        Public Overrides Function Author() As String
            Return _contract.Author()
        End Function
        Public Overrides Function Title() As String
            Return _contract.Title()
        End Function
        Public Overrides Function Genre() As String
            Return _contract.Genre()
        End Function
        Public Overrides Function Price() As String
            Return _contract.Price()
        End Function
        Public Overrides Function Publish_Date() As String
            Return _contract.Publish_Date()
        End Function
        Public Overrides Function Description() As String
            Return _contract.Description()
        End Function
    
        Friend Function GetSourceContract() As Library.IBookInfoContract
            Return _contract
        End Function
    End Class
    End Namespace
    
    using System;
    using System.AddIn.Pipeline;
    namespace LibraryContractsAddInAdapters 
    {
    
    public class BookInfoContractToViewAddInAdapter : LibraryContractsBase.BookInfo 
    {
        private Library.IBookInfoContract _contract;
        private System.AddIn.Pipeline.ContractHandle _handle;
        public BookInfoContractToViewAddInAdapter(Library.IBookInfoContract contract) 
        {
            _contract = contract;
            _handle = new ContractHandle(contract);
        }
    
        public override string ID()
        {
            return _contract.ID();
        }
        public override string Author()
        {
            return _contract.Author();
        }
        public override string Title()
        {
            return _contract.Title();
        }
        public override string Genre()
        {
            return _contract.Genre();
        }
        public override string Price()
        {
            return _contract.Price();
        }
        public override string Publish_Date()
        {
            return _contract.Publish_Date();
        }
        public override string Description()
        {
            return _contract.Description();
        }
    
        internal Library.IBookInfoContract GetSourceContract() {
            return _contract;
        }
    }
    }
    
  8. 次のコードを使用して、AddInSideAdapters プロジェクトに BookInfoViewToContractAddInAdapter クラスを追加します。 このクラスを使用してパイプラインをアクティブ化することはないため、属性は必要ありません。 BookInfoAddInAdapter クラスで internal (Visual Basic では Friend) GetSourceView メソッドを使用することにより、オブジェクトがホストとアドイン間でラウンド トリップを行う場合に、追加のアダプターを作成しなくて済みます。

    
    Imports Microsoft.VisualBasic
    Imports System
    
    Namespace LibraryContractsAddInAdapters
    Public Class BookInfoViewToContractAddInAdapter
        Inherits System.AddIn.Pipeline.ContractBase
        Implements Library.IBookInfoContract
        Private _view As LibraryContractsBase.BookInfo
        Public Sub New(ByVal view As LibraryContractsBase.BookInfo)
            _view = view
        End Sub
        Public Overridable Function ID() As String Implements Library.IBookInfoContract.ID
            Return _view.ID()
        End Function
        Public Overridable Function Author() As String Implements Library.IBookInfoContract.Author
            Return _view.Author()
        End Function
        Public Overridable Function Title() As String Implements Library.IBookInfoContract.Title
            Return _view.Title()
        End Function
        Public Overridable Function Genre() As String Implements Library.IBookInfoContract.Genre
            Return _view.Genre()
        End Function
        Public Overridable Function Price() As String Implements Library.IBookInfoContract.Price
            Return _view.Price()
        End Function
        Public Overridable Function Publish_Date() As String Implements Library.IBookInfoContract.Publish_Date
            Return _view.Publish_Date()
        End Function
        Public Overridable Function Description() As String Implements Library.IBookInfoContract.Description
            Return _view.Description()
        End Function
    
        Friend Function GetSourceView() As LibraryContractsBase.BookInfo
            Return _view
        End Function
    End Class
    End Namespace
    
    using System;
    
    namespace LibraryContractsAddInAdapters 
    {
    public class BookInfoViewToContractAddInAdapter : System.AddIn.Pipeline.ContractBase, Library.IBookInfoContract 
    {
        private LibraryContractsBase.BookInfo _view;
        public BookInfoViewToContractAddInAdapter(LibraryContractsBase.BookInfo view) 
        {
            _view = view;
        }
        public virtual string ID()
        {
            return _view.ID();
        }
        public virtual string Author()
        {
            return _view.Author();
        }
        public virtual string Title()
        {
            return _view.Title();
        }
        public virtual string Genre()
        {
            return _view.Genre();
        }
        public virtual string Price()
        {
            return _view.Price();
        }
        public virtual string Publish_Date()
        {
            return _view.Publish_Date();
        }
        public virtual string Description()
        {
            return _view.Description();
        }
    
        internal LibraryContractsBase.BookInfo GetSourceView() {
            return _view;
        }
    }
    }
    
  9. 次のコードを使用して、AddInSideAdapters プロジェクトに LibraryManagerViewToContractAddInAdapter クラスを追加します。 このクラスを使用してパイプラインをアクティブ化するため、このクラスには AddInAdapterAttribute 属性が必要です。

    ProcessBooks メソッドは、分離境界を越えて書籍の一覧を渡す方法を示します。 CollectionAdapters.ToIList メソッドを使用して一覧を変換します。 一覧内のオブジェクトを変換するには、BookInfoAddInAdapter クラスで提供されるアダプター メソッドのデリゲートを渡します。

    GetBestSeller メソッドは、分離境界を越えて 1 つの BookInfo オブジェクトを渡す方法を示します。

    
    Imports Microsoft.VisualBasic
    Imports System.AddIn.Pipeline
    Imports System.AddIn.Contract
    Imports System.Collections.Generic
    Namespace LibraryContractsAddInAdapters
    ' The AddInAdapterAttribute
    ' identifes this pipeline
    ' segment as an add-in-side adapter.
    <AddInAdapter> _
    Public Class LibraryManagerViewToContractAddInAdapter
        Inherits System.AddIn.Pipeline.ContractBase
        Implements Library.ILibraryManagerContract
        Private _view As LibraryContractsBase.LibraryManager
        Public Sub New(ByVal view As LibraryContractsBase.LibraryManager)
            _view = view
        End Sub
        Public Overridable Sub ProcessBooks(ByVal books As IListContract(Of Library.IBookInfoContract)) Implements Library.ILibraryManagerContract.ProcessBooks
            _view.ProcessBooks(CollectionAdapters.ToIList(Of Library.IBookInfoContract, _
            LibraryContractsBase.BookInfo)(books, _
            AddressOf LibraryContractsAddInAdapters.BookInfoAddInAdapter.ContractToViewAdapter, _
            AddressOf LibraryContractsAddInAdapters.BookInfoAddInAdapter.ViewToContractAdapter))
        End Sub
        Public Overridable Function GetBestSeller() As Library.IBookInfoContract Implements Library.ILibraryManagerContract.GetBestSeller
            Return BookInfoAddInAdapter.ViewToContractAdapter(_view.GetBestSeller())
        End Function
    
        Public Overridable Function Data(ByVal txt As String) As String Implements Library.ILibraryManagerContract.Data
            Dim rtxt As String = _view.Data(txt)
            Return rtxt
        End Function
    
        Friend Function GetSourceView() As LibraryContractsBase.LibraryManager
            Return _view
        End Function
    End Class
    End Namespace
    
    using System.IO;
    using System.AddIn.Pipeline;
    using System.AddIn.Contract;
    using System.Collections.Generic;
    namespace LibraryContractsAddInAdapters
    {
    // The AddInAdapterAttribute
    // identifes this pipeline
    // segment as an add-in-side adapter.
    [AddInAdapter]
    public class LibraryManagerViewToContractAddInAdapter :
    System.AddIn.Pipeline.ContractBase, Library.ILibraryManagerContract
    {
        private LibraryContractsBase.LibraryManager _view;
        public LibraryManagerViewToContractAddInAdapter(LibraryContractsBase.LibraryManager view)
        {
            _view = view;
        }
        public virtual void ProcessBooks(IListContract<Library.IBookInfoContract> books)
        {
            _view.ProcessBooks(CollectionAdapters.ToIList<Library.IBookInfoContract,
                LibraryContractsBase.BookInfo>(books,
                LibraryContractsAddInAdapters.BookInfoAddInAdapter.ContractToViewAdapter,
                LibraryContractsAddInAdapters.BookInfoAddInAdapter.ViewToContractAdapter));
        }
        public virtual Library.IBookInfoContract GetBestSeller()
        {
            return BookInfoAddInAdapter.ViewToContractAdapter(_view.GetBestSeller());
        }
    
        public virtual string Data(string txt)
        {
            string rtxt = _view.Data(txt);
            return rtxt;
        }
    
        internal LibraryContractsBase.LibraryManager GetSourceView()
        {
            return _view;
        }
    }
    }
    
  10. 次のコードを使用して、AddInSideAdapters プロジェクトに BookInfoAddInAdapter クラスを追加します。 クラスには、ContractToViewAdapter および ViewToContractAdapter という、2 つの static メソッド (Visual Basic では Shared メソッド) が含まれています。 メソッドは、他のアダプター クラスによってのみ使用されるため、internal (Visual Basic では Friend) です。 これらのメソッドの目的は、オブジェクトがホストとアドイン間のいずれかの方向でラウンド トリップを行う場合に、余分なアダプターの作成を回避することです。 これらのメソッドは、分離境界を越えてオブジェクトを渡すアダプターに対して提供する必要があります。

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

ホスト側アダプターの作成

このパイプラインのこのホスト側アダプター アセンブリには、4 つの抽象クラスが含まれています。

  • BookInfoContractToViewHostAdapter

    アドインからホストに BookInfo オブジェクトが渡されるとき、このアダプターが単独で、またはコレクションの一部として呼び出されます。 このクラスにより、BookInfo オブジェクトのコントラクトがビューに変換されます。 このクラスはホスト ビューを継承し、クラスのコンストラクターに渡されるコントラクトを呼び出すことによって、ビューの抽象メソッドを実装します。

    このアダプターのコンストラクターは、そのコンストラクター用のコントラクトを受け取ります。そのため、ContractHandle オブジェクトをコントラクトに適用して有効期間管理を実装できるようになります。

    重要 :重要

    有効期間の管理には、ContractHandle が重要です。ContractHandle オブジェクトへの参照を保持していないと、ガベージ コレクションによってオブジェクトが再利用され、プログラムで予期していないタイミングでパイプラインがシャットダウンすることになります。これは、AppDomainUnloadedException のような診断が困難なエラーの原因となる可能性があります。シャットダウンはパイプラインの正常な段階の 1 つであるため、有効期間を管理するコードでこの状態をエラーとして検出する方法はありません。

  • BookInfoViewToContractHostAdapter

    ホストからアドインに BookInfo オブジェクトが渡されるとき、このアダプターが呼び出されます。 このクラスにより、BookInfo オブジェクトのホスト ビューがコントラクトに変換されます。 このクラスはコントラクトを継承し、クラスのコンストラクターに渡されるアドインを呼び出すことによって、コントラクトを実装します。 このアダプターはコントラクトとしてアドインにマーシャリングされます。

  • LibraryManagerContractToViewHostAdapter

    このアダプターは、ホストからアドインに BookInfo オブジェクトのコレクションが渡されるときに呼び出されます。 このアドインで、このコレクションへの ProcessBooks メソッドの実装が実行されます。

    このクラスにより、LibraryManager オブジェクトのホスト ビューがコントラクトに変換されます。 コントラクトを継承し、クラスのコンストラクターに渡されるホスト ビューを呼び出すことで、コントラクトを実装します。

    カスタム型のコレクションである BookInfo オブジェクトは、分離境界を越えてマーシャリングする必要があるため、このアダプターでは CollectionAdapters クラスが使用されます。 このクラスには、IList<T> コレクションを IListContract<T> コレクションに変換するメソッドがあります。これによって、分離境界を越えてコレクションをパイプラインの反対側に渡すことができます。

  • BookInfoHostAdapter

    このアダプターは、呼び出しで新しいインスタンスを作成するのではなく、LibraryManagerViewToContractHostAdapter クラスによって呼び出すことで、変換で使用される既存のコントラクトやビューをすべて返します。 このため、オブジェクトがホストとアドイン間のいずれかの方向でラウンド トリップを行う場合に、余分なアダプターを作成しなくて済みます。

ホスト側アダプターを作成するには

  1. BooksPipeline ソリューションに HostSideAdapters という名前の新規プロジェクトを追加します。 それにクラス ライブラリ テンプレートを適用します。

  2. Visual Basic で、プロジェクトの [プロパティ] を開き、[アプリケーション] タブを使用して、[ルート名前空間] に指定されている既定値を削除します。

  3. ソリューション エクスプローラーで、次のアセンブリへの参照を HostSideAdapters プロジェクトに追加します。

    System.AddIn.dll

    System.AddIn.Contract.dll

  4. ソリューション エクスプローラーで、次のプロジェクトへの参照を HostSideAdapters プロジェクトに追加します。

    HostViews

    LibraryContracts

    参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、これらの参照の [プロパティ][ローカルにコピーする][False] に設定します。

  5. クラス ファイルで、System.AddIn.Pipeline 名前空間への参照を追加します。

  6. 次のコードを使用して、BookInfoContractToViewHostAdapter クラスを追加します。 このクラスを使用してパイプラインをアクティブ化することはないため、属性は必要ありません。 BookInfoAddInAdapter クラスで internal (Visual Basic では Friend) GetSourceContract メソッドを使用することにより、オブジェクトがホストとアドイン間でラウンド トリップを行う場合に、余分なアダプターを作成しなくて済みます。

    
    Imports Microsoft.VisualBasic
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsHostAdapters
    Public Class BookInfoContractToViewHostAdapter
        Inherits LibraryContractsHAV.BookInfo
        Private _contract As Library.IBookInfoContract
    
        Private _handle As ContractHandle
    
        Public Sub New(ByVal contract As Library.IBookInfoContract)
            _contract = contract
            _handle = New ContractHandle(contract)
        End Sub
    
        Public Overrides Function ID() As String
            Return _contract.ID()
        End Function
        Public Overrides Function Author() As String
            Return _contract.Author()
        End Function
        Public Overrides Function Title() As String
            Return _contract.Title()
        End Function
        Public Overrides Function Genre() As String
            Return _contract.Genre()
        End Function
        Public Overrides Function Price() As String
            Return _contract.Price()
        End Function
        Public Overrides Function Publish_Date() As String
            Return _contract.Publish_Date()
        End Function
        Public Overrides Function Description() As String
            Return _contract.Description()
        End Function
    
    
        Friend Function GetSourceContract() As Library.IBookInfoContract
            Return _contract
        End Function
    End Class
    End Namespace
    
    using System.AddIn.Pipeline;
    namespace LibraryContractsHostAdapters
    {
        public class BookInfoContractToViewHostAdapter : LibraryContractsHAV.BookInfo
        {
            private Library.IBookInfoContract _contract;
    
            private ContractHandle _handle;
    
            public BookInfoContractToViewHostAdapter(Library.IBookInfoContract contract)
            {
                _contract = contract;
                _handle = new ContractHandle(contract);
            }
    
            public override string ID()
            {
                return _contract.ID();
            }
            public override string Author()
            {
                return _contract.Author();
            }
            public override string Title()
            {
                return _contract.Title();
            }
            public override string Genre()
            {
                return _contract.Genre();
            }
            public override string Price()
            {
                return _contract.Price();
            }
            public override string Publish_Date()
            {
                return _contract.Publish_Date();
            }
            public override string Description()
            {
                return _contract.Description();
            }
    
    
            internal Library.IBookInfoContract GetSourceContract() {
                return _contract;
            }
        }
    }
    
  7. 次のコードを使用して、HostSideAdapters プロジェクトに BookInfoViewToContractHostAdapter を追加します。 このクラスを使用してパイプラインをアクティブ化することはないため、属性は必要ありません。 BookInfoAddInAdapter クラスで internal (Visual Basic では Friend) GetSourceView メソッドを使用することにより、オブジェクトがホストとアドイン間でラウンド トリップを行う場合に、余分なアダプターを作成しなくて済みます。

    
    Imports Microsoft.VisualBasic
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsHostAdapters
    Public Class BookInfoViewToContractHostAdapter
        Inherits ContractBase
        Implements Library.IBookInfoContract
        Private _view As LibraryContractsHAV.BookInfo
    
        Public Sub New(ByVal view As LibraryContractsHAV.BookInfo)
            _view = view
        End Sub
    
        Public Overridable Function ID() As String Implements Library.IBookInfoContract.ID
            Return _view.ID()
        End Function
        Public Overridable Function Author() As String Implements Library.IBookInfoContract.Author
            Return _view.Author()
        End Function
        Public Overridable Function Title() As String Implements Library.IBookInfoContract.Title
            Return _view.Title()
        End Function
        Public Overridable Function Genre() As String Implements Library.IBookInfoContract.Genre
            Return _view.Genre()
        End Function
        Public Overridable Function Price() As String Implements Library.IBookInfoContract.Price
            Return _view.Price()
        End Function
        Public Overridable Function Publish_Date() As String Implements Library.IBookInfoContract.Publish_Date
            Return _view.Publish_Date()
        End Function
        Public Overridable Function Description() As String Implements Library.IBookInfoContract.Description
            Return _view.Description()
        End Function
        Friend Function GetSourceView() As LibraryContractsHAV.BookInfo
            Return _view
        End Function
    End Class
    End Namespace
    
    using System.AddIn.Pipeline;
    namespace LibraryContractsHostAdapters
    {
    public class BookInfoViewToContractHostAdapter : ContractBase, Library.IBookInfoContract
    {
        private LibraryContractsHAV.BookInfo _view;
    
        public BookInfoViewToContractHostAdapter(LibraryContractsHAV.BookInfo view)
        {
            _view = view;
        }
    
        public virtual string ID()
        {
            return _view.ID();
        }
        public virtual string Author()
        {
            return _view.Author();
        }
        public virtual string Title()
        {
            return _view.Title();
        }
        public virtual string Genre()
        {
            return _view.Genre();
        }
        public virtual string Price()
        {
            return _view.Price();
        }
        public virtual string Publish_Date()
        {
            return _view.Publish_Date();
        }
        public virtual string Description()
        {
            return _view.Description();
        }
        internal LibraryContractsHAV.BookInfo GetSourceView()
        {
            return _view;
        }
    }
    }
    
  8. 次のコードを使用して、HostSideAdapters プロジェクトに LibraryManagerContractToViewHostAdapter を追加します。 このクラスを使用してパイプラインをアクティブ化するため、このクラスには HostAdapterAttribute 属性が必要です。

    ProcessBooks メソッドは、分離境界を越えて書籍の一覧を渡す方法を示します。 CollectionAdapters.ToIListContract メソッドを使用して一覧を変換します。 一覧内のオブジェクトを変換するには、BookInfoHostAdapter クラスで提供されるアダプター メソッドのデリゲートを渡します。

    GetBestSeller メソッドは、分離境界を越えて 1 つの BookInfo オブジェクトを渡す方法を示します。

    
    Imports Microsoft.VisualBasic
    Imports System.Collections.Generic
    Imports System.AddIn.Pipeline
    Namespace LibraryContractsHostAdapters
        <HostAdapterAttribute()> _
        Public Class LibraryManagerContractToViewHostAdapter
            Inherits LibraryContractsHAV.LibraryManager
    
            Private _contract As Library.ILibraryManagerContract
            Private _handle As System.AddIn.Pipeline.ContractHandle
    
            Public Sub New(ByVal contract As Library.ILibraryManagerContract)
                _contract = contract
                _handle = New System.AddIn.Pipeline.ContractHandle(contract)
            End Sub
    
            Public Overrides Sub ProcessBooks(ByVal books As IList(Of LibraryContractsHAV.BookInfo))
                _contract.ProcessBooks(CollectionAdapters.ToIListContract(Of LibraryContractsHAV.BookInfo, _
                Library.IBookInfoContract)(books, _
                AddressOf LibraryContractsHostAdapters.BookInfoHostAdapter.ViewToContractAdapter, _
                AddressOf LibraryContractsHostAdapters.BookInfoHostAdapter.ContractToViewAdapter))
            End Sub
    
            Public Overrides Function GetBestSeller() As LibraryContractsHAV.BookInfo
                Return BookInfoHostAdapter.ContractToViewAdapter(_contract.GetBestSeller())
            End Function
    
            Friend Function GetSourceContract() As Library.ILibraryManagerContract
                Return _contract
            End Function
            Public Overrides Function Data(ByVal txt As String) As String
                Dim rtxt As String = _contract.Data(txt)
                Return rtxt
            End Function
        End Class
    End Namespace
    
    using System.Collections.Generic;
    using System.AddIn.Pipeline;
    namespace LibraryContractsHostAdapters
    {
    [HostAdapterAttribute()]
    public class LibraryManagerContractToViewHostAdapter : LibraryContractsHAV.LibraryManager
    {
    
        private Library.ILibraryManagerContract _contract;
        private System.AddIn.Pipeline.ContractHandle _handle;
    
        public LibraryManagerContractToViewHostAdapter(Library.ILibraryManagerContract contract)
        {
            _contract = contract;
            _handle = new System.AddIn.Pipeline.ContractHandle(contract);
        }
    
        public override void ProcessBooks(IList<LibraryContractsHAV.BookInfo> books) {
            _contract.ProcessBooks(CollectionAdapters.ToIListContract<LibraryContractsHAV.BookInfo,
                Library.IBookInfoContract>(books,
                LibraryContractsHostAdapters.BookInfoHostAdapter.ViewToContractAdapter,
                LibraryContractsHostAdapters.BookInfoHostAdapter.ContractToViewAdapter));
        }
    
        public override LibraryContractsHAV.BookInfo GetBestSeller()
        {
            return BookInfoHostAdapter.ContractToViewAdapter(_contract.GetBestSeller());
        }
    
        internal Library.ILibraryManagerContract GetSourceContract()
        {
            return _contract;
        }
        public override string Data(string txt)
        {
            string rtxt = _contract.Data(txt);
            return rtxt;
        }
    }
    }
    
  9. 次のコード例を使用して、HostSideAdapters プロジェクトに BookInfoHostAdapter クラスを追加します。 クラスには、ContractToViewAdapter および ViewToContractAdapter という、2 つの static メソッド (Visual Basic では Shared メソッド) が含まれています。 メソッドは、他のアダプター クラスによってのみ使用されるため、internal (Visual Basic では Friend) です。 これらのメソッドの目的は、オブジェクトがホストとアドイン間のいずれかの方向でラウンド トリップを行う場合に、余分なアダプターの作成を回避することです。 これらのメソッドは、分離境界を越えてオブジェクトを渡すアダプターに対して提供する必要があります。

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

ホストの作成

ホスト アプリケーションは、ホスト ビューを利用してアドインと対話します。 AddInStore クラスと AddInToken クラスを利用したアドイン探索とアクティベーション メソッドを使って、次の処理を実行します。

  • パイプライン情報とアドイン情報のキャッシュをビルドし直す。

  • 指定されたパイプライン ルート ディレクトリで、LibraryManager 型のアドインを検索する。

  • 使用するアドインを選択するように促すメッセージを表示する。 このサンプルでは、使用できるアドインは 1 つのみです。

  • セキュリティ信頼レベルが指定された新しいアプリケーション ドメインで、選択されたアドインをアクティブにする。

  • ProcessBooks メソッドを呼び出して、BookInfo オブジェクトのコレクションをアドインに渡す。 アドインでは ProcessBooks メソッドの実装が呼び出され、たとえばコンピューター関連書籍を 20% 割り引くなどの機能を実行します。

  • ベストセラー書籍の情報を含む BookInfo オブジェクトを返すためにアドインで使用される GetBestSeller メソッドを呼び出す。

  • Data メソッドを呼び出し、アドインから現在の消費税率を取得する。 このメソッドは、シールされたシリアル化可能な参照型である文字列をやり取りします。 それにより、ビューからコントラクトへのアダプターやコントラクトからビューへのアダプターを使用することなく、分離境界を越えてこのメソッドをパイプラインの反対側に渡すことができます。

ホストには、BookInfo オブジェクトのコレクションを作成する CreateBooks メソッドがあります。 このメソッドにより、books.xml サンプル ファイルを使用したコレクションが作成されます。このファイルは、「Sample XML File (books.xml)」で入手できます。

ホストを作成するには

  1. BooksPipeline ソリューションに BookStore という名前の新規プロジェクトを追加します。 これにコンソール アプリケーション テンプレートを適用します。

  2. Visual Basic で、プロジェクトの [プロパティ] を開き、[アプリケーション] タブを使用して、[ルート名前空間] に指定されている既定値を削除します。

  3. ソリューション エクスプローラーで、BookStore プロジェクトに System.AddIn.dll アセンブリへの参照を追加します。

  4. HostViews プロジェクトへのプロジェクト参照を追加します。 参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、この参照の [プロパティ][ローカルにコピーする][False] に設定します。

  5. Visual Basic で、モジュールをクラスに変更します。

    • プロジェクトから既定のモジュールを除外し、Program という名前のクラスを追加します。

    • Public キーワードを Friend キーワードに置き換えます。

    • Shared Sub Main() プロシージャをクラスに追加します。

    • [プロジェクトのプロパティ] ダイアログ ボックスの [アプリケーション] タブを使用して、[スタートアップ オブジェクト][Sub Main] に設定します。

  6. クラス ファイルに、System.AddIn.Pipeline およびホスト ビュー セグメントの名前空間への参照を追加します。

  7. ソリューション エクスプローラーでソリューションを選択し、[プロジェクト] メニューの [プロパティ] をクリックします。 ソリューションの [プロパティ ページ] ダイアログ ボックスで、[シングル スタートアップ プロジェクト] をこのホスト アプリケーション プロジェクトに設定します。

  8. ホスト アプリケーションに、次のコードを使用します。

    メモメモ

    コード内で、books.xml ファイルの読み込み元の場所を "books.xml" に変更して、ファイルがアプリケーション フォルダーから読み込まれるようにします。アプリケーションを Pipeline フォルダー以外の場所に配置する場合は、addInRoot 変数を設定するコード行を変更して、パイプライン ディレクトリ構造へのパスを変数に設定します。

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

books.xml データ ファイルを作成するには

  1. 新しい XML ファイルを BookStore プロジェクトに追加します。 [新しい項目の追加] ダイアログ ボックスで、ファイルに books.xml という名前を付けます。

  2. books.xml の既定のコンテンツを、「Sample XML File (books.xml)」の XML に置き換えます。

  3. ソリューション エクスプローラーで books.xml を選択し、[プロパティ] で、[出力ディレクトリにコピー][常にコピーする] に設定します。

アドインの作成

アドインにより、アドイン ビューで指定されたメソッドを実装します。 このアドインにより、ProcessBooks メソッドが実装されます。 このメソッドでは、ホストが渡す BookInfo オブジェクトのコレクションに対して、次の処理を実行します。

  • コンピューター関連書籍の価格をすべて 20% 引きにする。

  • コレクションからホラー小説をすべて削除する。

さらに、このアドインではベストセラー書籍を指定する BookInfo オブジェクトをホストに渡すことで、GetBestSeller メソッドを実装します。

アドインを作成するには

  1. BooksPipeline ソリューションに BooksAddin という名前の新規プロジェクトを追加します。 それにクラス ライブラリ テンプレートを適用します。

  2. Visual Basic で、プロジェクトの [プロパティ] を開き、[アプリケーション] タブを使用して、[ルート名前空間] に指定されている既定値を削除します。

  3. ソリューション エクスプローラーで、BooksAddin プロジェクトに System.AddIn.dll アセンブリへの参照を追加します。

  4. AddInViews プロジェクトへのプロジェクト参照を追加します。 参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、この参照の [プロパティ][ローカルにコピーする][False] に設定します。

  5. クラス ファイルに、System.AddIn およびアドイン ビュー セグメントの名前空間への参照を追加します。

  6. アドイン アプリケーションに、次のコードを使用します。

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

パイプラインの配置

これで、アドイン セグメントを作成し、必要なパイプライン ディレクトリ構造内に配置する準備ができました。

セグメントをパイプラインに配置するには

  1. ソリューション内の各プロジェクトについて、[プロジェクトのプロパティ][ビルド] タブ (Visual Basic では [コンパイル] タブ) を使用して、次の表に示すように [出力パス] (Visual Basic では [ビルド出力パス]) の値を設定します。

    プロジェクト

    パス

    BooksAddIn

    Pipeline\AddIns\CalcV1

    AddInSideAdapters

    Pipeline\AddInSideAdapters

    AddInViews

    Pipeline\AddInViews

    LibraryContracts

    Pipeline\Contracts

    BookStore

    Pipeline (または各自のアプリケーション ディレクトリ)

    HostSideAdapters

    Pipeline\HostSideAdapters

    HostViews

    Pipeline (または各自のアプリケーション ディレクトリ)

    メモメモ

    アプリケーションを Pipeline フォルダー以外の場所に配置した場合は、パイプライン ルート ディレクトリの場所を指定するホスト コードを変更します。

  2. Visual Studio ソリューションをビルドします。

    パイプラインへの配置の詳細については、「パイプライン開発の必要条件」を参照してください。

ホスト アプリケーションの実行

これで、ホストを実行し、アドインと対話する準備が整いました。

ホスト アプリケーションを実行するには

  1. コマンド プロンプトで、パイプライン ルート ディレクトリに移動し、ホスト アプリケーションを実行します。 この例では、ホスト アプリケーションは BookStore.exe です。

  2. 対応する型のアドインがすべて検索され、アドインの選択を求めるメッセージが表示されます。 使用できるアドインは 1 つのみであるため、「1」を入力します。

    ホストはアドインをアクティブ化し、それを使用して書籍の一覧に対してさまざまな処理を実行します。

  3. 任意のキーを押してアプリケーションを閉じます。

参照

処理手順

チュートリアル : 拡張性のあるアプリケーションの作成

チュートリアル : ホスト変更時の下位互換性の確保

概念

パイプライン開発の必要条件

コントラクト、ビュー、およびアダプター

パイプラインの開発