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

このチュートリアルでは、「チュートリアル : 拡張性のあるアプリケーションの作成」で説明したパイプラインの Version 2 について説明します。 この Version 2 では、サポートされる算術演算をコンマ区切りの文字列としてホストに渡すことで、計算機能が強化されています。 ホストで演算を選択し、アドインに式を送信することで、計算を実行します。

パイプラインには新しいホストと新しいコントラクトが追加されます。 Version 1 のアドインが新しいホストとコントラクトに対応できるように、Version 1 で使用されたアドイン ビューと、古いアドイン ビューのデータを新しいコントラクトに変換するためのアドイン側アダプターが、パイプラインに用意されています。 以下の図に、この 2 つのアドインが同じホストで動作する方法を示します。

新バージョンのホスト、旧バージョンのアドイン

パイプライン シナリオ: 新しいホスト、古いアドイン。

このパイプラインについては、「アドイン パイプラインのシナリオ」も参照してください。

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

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

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

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

  • 新バージョンのアドインおよび Version 1 のアドインのアダプターから成るアドイン側アダプターの作成

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

  • ホストの作成

  • アドインの作成

  • パイプラインの配置

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

このチュートリアルでは、抽象基本クラスを使用してビューを定義する方法についても説明し、このようなビューがインターフェイスで定義されるビューと互換性があることを示します。 インターフェイスを使用することをお勧めします。

メモメモ

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

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

必須コンポーネント

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

  • Visual Studio

  • Version 1 のパイプライン。詳細については、「チュートリアル : 拡張性のあるアプリケーションの作成」を参照してください。 Version 2 では Version 1 で作成したパイプライン セグメントが使用されるため、このトピックの手順を実行する前に、Version 1 のパイプラインを作成して配置しておく必要があります。

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

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

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

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

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

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

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

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

  • CalcV2 フォルダーを「チュートリアル : 拡張性のあるアプリケーションの作成」で作成したパイプライン ディレクトリ構造に追加していない場合は、追加します。 CalcV2 フォルダーに、新バージョンのアドインが格納されます。

    Pipeline
      AddIns
        CalcV1
        CalcV2
      AddInSideAdapters
      AddInViews
      Contracts
      HostSideAdapters
    

    アプリケーション フォルダー内にパイプライン フォルダー構造を配置する必要はありません。チュートリアルでは、便宜上、そのようにしているだけです。 最初のチュートリアルでパイプライン フォルダー構造を別の場所に配置した場合は、このチュートリアルで同じパターンに従います。 パイプライン ディレクトリの必要条件の詳細については、「パイプライン開発の必要条件」を参照してください。

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

このパイプラインのコントラクト セグメントで ICalc2Contract インターフェイスを定義します。これには、次の 2 つのメソッドが含まれます。

  • GetAvailableOperations メソッド。

    このメソッドは、アドインでサポートされる算術演算の文字列をホストに返します。 Version 2 では 5 種類の演算がサポートされ、このメソッドは文字列 "+,-,*,/,**" を返します。ここで、"**" は Pow 演算を表します。

    アドイン ビューとホスト ビューでは、このメソッドは GetAvailableOperations ではなく Operations という名前になります。

    メソッド呼び出しをアダプターのプロパティに変換することで、メソッドをビューのプロパティとしてコントラクトに公開することができます。

  • Operate メソッド。

    ホストからこのメソッドを呼び出して、アドインが計算を実行して結果を返すための式を送信します。

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

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

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

    System.AddIn.Contract.dll

    System.AddIn.dll

  3. ソリューション エクスプローラーで、新しいクラス ライブラリ プロジェクトに追加された既定のクラスを除外します。

  4. インターフェイス テンプレートを使用して、プロジェクトに新しい項目を追加します。 [新しい項目の追加] ダイアログ ボックスで、インターフェイスに ICalc2Contract という名前を付けます。

  5. インターフェイス ファイルに、System.AddIn.Contract および System.AddIn.Pipeline への名前空間参照を追加します。

  6. コントラクト セグメントを完了するには、次のコードを使用します。 このインターフェイスには、AddInContractAttribute 属性が必要であることに注意してください。

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.AddIn.Contract
    Imports System.AddIn.Pipeline
    
    Namespace CalculatorContracts
        <AddInContract()> _
        Public Interface ICalc2Contract
            Inherits IContract
            Function GetAvailableOperations() As String
            Function Operate(ByVal operation As String, ByVal a As Double, ByVal b As Double) As Double
        End Interface
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.AddIn.Contract;
    using System.AddIn.Pipeline;
    
    namespace CalculatorContracts
    {
        [AddInContract]
        public interface ICalc2Contract : IContract
        {      
            string GetAvailableOperations();
            double Operate(String operation, double a, double b);
        }
    }
    

アドイン ビューとホスト ビューは、コードが同じであるため、ビューを同時に簡単に作成できます。 この 2 つのビューの唯一の相違点は、AddInBaseAttribute 属性が必要かどうか、ということです。アドイン ビューには必要ですが、アドインのホスト ビューには必要ありません。

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

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

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

  3. クラス名を Calculator2 に変更します。

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

  5. Calculator2 を abstract クラス (Visual Basic では MustInherit クラス) にします。

  6. このアドイン ビューには、次のコードを使用します。 このクラスには、AddInBaseAttribute 属性が必要であることに注意してください。

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.AddIn.Pipeline
    
    Namespace CalcAddInViews
        <AddInBase()> _
        Public MustInherit Class Calculator2
            Public MustOverride ReadOnly Property Operations() As String
    
            Public MustOverride Function Operate(ByVal operation As String, ByVal a As Double, ByVal b As Double) As Double
        End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.AddIn.Pipeline;
    
    namespace CalcAddInViews
    {
        [AddInBase]
        public abstract class Calculator2
        {
            public abstract string Operations
            {
                get;
            }
    
            public abstract double Operate(string operation, double a, double b);
        }
    }
    

アドインのホスト ビューを作成するには

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

  2. クラス名を Calculator に変更します。

  3. Calculator を abstract クラス (Visual Basic では MustInherit クラス) にします。

  4. クラス ファイルに、このアドインのホスト ビューを作成する次のコードを追加します。

    Imports Microsoft.VisualBasic
    Imports System
    Namespace CalcHVAs
    
        Public MustInherit Class Calculator
    
            Public MustOverride ReadOnly Property Operations() As String
    
            Public MustOverride Function Operate(ByVal operation As String, ByVal a As Double, ByVal b As Double) As Double
        End Class
    End Namespace
    
    namespace CalcHVAs {
    
    
        public abstract class Calculator {
    
            public abstract string Operations
            {
                get;
            }
    
            public abstract double Operate(string operation, double a, double b);
        }
    }
    

新しいホストで Version 1 のアドインを使用するには、Version 1 の計算機アドイン用に作成したアドイン ビューをソリューションに含める必要があります。

Version 1 のアドイン ビュー プロジェクトを追加するには

  1. ソリューション エクスプローラーで、CalculatorV2 ソリューションを右クリックします。

  2. [追加] をクリックし、[既存のプロジェクト] をクリックします。

  3. CalculatorV1 ソリューションが格納されているフォルダーに移動し、Calc1AddInView プロジェクトに対応するプロジェクト ファイルを選択します。

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

このアドイン側アダプターは、ビューからコントラクタへの 2 つのアダプターで構成されます。1 つは、Version 2 のアドイン ビューを Version 2 のコントラクトに適応するものであり、もう 1 つは、Version 1 のアドイン ビューを Version 2 のコントラクトに適応するものです。

このパイプラインでは、アドインによりホストにサービスが提供され、アドインからホストに型が渡されます。 ホストからアドインには型が渡されないため、コントラクトからビューへのアダプターは不要です。

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

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

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

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 次のプロジェクトへのプロジェクト参照を追加します。

    Calc2AddInView

    Calc2Contract

  4. 参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、各プロジェクト参照を選択し、[プロパティ][ローカルにコピーする][False] に設定します。 このチュートリアルの後の手順の「パイプラインの配置」で説明するように、アセンブリはパイプライン ディレクトリに配置されます。 Visual Basic で、[プロジェクトのプロパティ][参照] タブを使用して、2 つのプロジェクト参照に対応する [ローカルにコピーする][False] に設定します。

  5. プロジェクトの既定のクラス名を CalculatorViewToContractAddInSideAdapter に変更します。

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

  7. クラス ファイルに、CalcAddInViews および CalculatorContracts という隣接セグメントに対応する名前空間参照を追加します (Visual Basic では、Visual Basic プロジェクトで既定の名前空間をオフにしていない限り、これらの名前空間参照は Calc2AddInView.CalcAddInViews および Calc2Contract.CalculatorContracts です)。

  8. このアドイン側アダプターには、次のコードを使用します。 コントラクト インターフェイスは大きく異なりますが、実装パターンは Version 1 のアドイン側アダプターと似ています。

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.AddIn.Pipeline
    Imports System.AddIn.Contract
    Imports Calc2Contract.CalculatorContracts
    Imports Calc2AddInView.CalcAddInViews
    
    Namespace CalculatorContractsAddInAdapters
    
        <AddInAdapterAttribute()> _
        Public Class CalculatorViewToContractAddInAdapter
            Inherits ContractBase
            Implements ICalc2Contract
    
            Private _view As Calculator2
    
            Public Sub New(ByVal calculator As Calculator2)
                _view = calculator
            End Sub
    
            Public Function GetAvailableOperations() As String Implements ICalc2Contract.GetAvailableOperations
                Return _view.Operations
            End Function
    
            Public Function Operate(ByVal operation As String, ByVal a As Double, ByVal b As Double) As Double Implements ICalc2Contract.Operate
                Return _view.Operate(operation, a, b)
            End Function
        End Class
    End Namespace
    
    using System.AddIn.Pipeline;
    using CalcAddInViews;
    using CalculatorContracts;
    
    
    namespace CalcAddInSideAdapters {
    
    
        [AddInAdapterAttribute]
        public class CalculatorViewToContractAddInAdapter : ContractBase, ICalc2Contract {
    
            private Calculator2 _view;
    
            public CalculatorViewToContractAddInAdapter(Calculator2 calculator)
            {
                _view = calculator;
            }
    
            public string GetAvailableOperations()
            {
                return _view.Operations;
            }
    
            public double Operate(string operation, double a, double b)
            {
                return _view.Operate(operation, a, b);
            }
    
        }
    }
    

Version 1 のアドインが新しいホストと通信できるように、古いアドイン ビューのデータを新しいコントラクトに変換するためのアドイン側アダプターが、Version 1 のアドインのパイプラインで必要になります。

Version 1 から Version 2 へのアドイン側アダプターを作成するには

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

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

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 次のプロジェクトへのプロジェクト参照を追加します。

    Calc1AddInView

    Calc2Contract

  4. 参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、各プロジェクト参照を選択し、[プロパティ][ローカルにコピーする][False] に設定します。 Visual Basic で、[プロジェクトのプロパティ][参照] タブを使用して、2 つのプロジェクト参照に対応する [ローカルにコピーする][False] に設定します。

  5. プロジェクトの既定のクラス名を Calc2V1ViewToV2ContractAddInSideAdapter に変更します。

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

  7. クラス ファイルに、CalcAddInViews および CalculatorContracts という隣接セグメントに対応する名前空間参照を追加します (Visual Basic では、Visual Basic プロジェクトで既定の名前空間をオフにしていない限り、これらの名前空間参照は Calc1AddInView.CalcAddInViews および Calc2Contract.CalculatorContracts です)。 ビュー名前空間は Version 1 が基準で、コントラクトは Version 2 が基準であることに注意してください。

  8. AddInAdapterAttribute 属性を Calc2V1ViewToV2ContractAddInSideAdapter クラスに適用して、クラスをアドイン側アダプターとして指定します。

  9. Calc2V1ViewToV2ContractAddInSideAdapter クラスが ContractBase を継承するようにします。これによって、IContract インターフェイスの既定の実装が提供され、ICalc2Contract というパイプラインの Version 2 のコントラクト インターフェイスが実装されます。

  10. ICalculator を受け取り、これをプライベート フィールドにキャッシュし、基本クラスのコンストラクターを呼び出すパブリック コンストラクターを追加します。

  11. ICalc2Contract のメンバーを実装するには、コンストラクターに渡される ICalculator インスタンスの適切なメンバーを呼び出し、結果を返す必要があります。 Version 1 と Version 2 の相違により、switch ステートメント (Visual Basic では Select Case ステートメント) を使用して、ビュー (ICalculator) をコントラクト (ICalc2Contract) に適応させる必要があります。

    完成したアドイン側アダプターを次のコードに示します。

    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.AddIn.Pipeline
    Imports Calc1AddInView.CalcAddInViews
    Imports Calc2Contract.CalculatorContracts
    
    Namespace AddInSideV1toV2Adapter
    
    
        <AddInAdapter()> _
        Public Class Calc2V1ViewToV2ContractAddInSideAdapter
            Inherits ContractBase
            Implements ICalc2Contract
    
            Private _view As ICalculator
    
            Public Sub New(ByVal calc As ICalculator)
                MyBase.New()
                _view = calc
            End Sub
    
            Public Function GetAvailableOperations() As String Implements ICalc2Contract.GetAvailableOperations
                Return "+, -, *, /"
            End Function
    
            Public Function Operate(ByVal operation As String, ByVal a As Double, ByVal b As Double) _
             As Double Implements ICalc2Contract.Operate
                Select Case (operation)
                    Case "+"
                        Return _view.Add(a, b)
                    Case "-"
                        Return _view.Subtract(a, b)
                    Case "*"
                        Return _view.Multiply(a, b)
                    Case "/"
                        Return _view.Divide(a, b)
                    Case Else
                        Throw New InvalidOperationException(("This add-in does not support: " + operation))
                End Select
            End Function
        End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.AddIn.Pipeline;
    using CalcAddInViews;
    using CalculatorContracts;
    
    
    namespace AddInSideV1toV2Adapter
    {
        [AddInAdapter]
        public class Calc2V1ViewToV2ContractAddInSideAdapter : ContractBase, ICalc2Contract
        {
            ICalculator _view;
    
            public Calc2V1ViewToV2ContractAddInSideAdapter(ICalculator calc)
            {
                _view = calc;
            }
    
            public string GetAvailableOperations()
            {
                return  "+, -, *, /" ;
            }
    
            public double Operate(string operation, double a, double b)
            {
                switch (operation)
                {
                    case "+":
                        return _view.Add(a, b);
                    case "-":
                        return _view.Subtract(a, b);
                    case "*":
                        return _view.Multiply(a, b);
                    case "/":
                        return _view.Divide(a, b);
                    default:
                        throw new InvalidOperationException("This add-in does not support: " + operation);
                }
            }
    
        }
    }
    

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

このホスト側アダプターは、コントラクトからビューへの 1 つのアダプターで構成されます。 コントラクトからビューへのアダプターは、1 つだけで、両バージョンのアドインをサポートできます。それは、各アドイン側アダプターで、それぞれのビューを Version 2 のコントラクトに変換できるためです。

このパイプラインでは、アドインによりホストにサービスが提供され、アドインからホストに型が渡されます。 ホストからアドインには型が渡されないため、ビューからコントラクトへのアダプターは不要です。

有効期間の管理を実装するために、ContractHandle オブジェクトを使用してコントラクトに有効期間トークンをアタッチします。 有効期間の管理を機能させるためには、このハンドルへの参照を保持する必要があります。 トークンを適用した後のプログラミングは不要です。アドイン システムでは使用されなくなったオブジェクトを破棄し、ガベージ コレクションに含められるように設定できるためです。 詳細については、「有効期間管理」を参照してください。

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

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

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

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 次のプロジェクトへのプロジェクト参照を追加します。

    Calc2Contract

    Calc2HVA

  4. 参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、各プロジェクト参照を選択し、[プロパティ][ローカルにコピーする][False] に設定します。 Visual Basic で、[プロジェクトのプロパティ][参照] タブを使用して、2 つのプロジェクト参照に対応する [ローカルにコピーする][False] に設定します。

  5. プロジェクトの既定のクラス名を CalculatorContractToViewHostSideAdapter に変更します。

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

  7. クラス ファイルに、CalcHVAs および CalculatorContracts という隣接セグメントに対応する名前空間参照を追加します (Visual Basic では、Visual Basic プロジェクトで既定の名前空間をオフにしていない限り、これらの名前空間参照は Calc2HVA.CalcHVAs および Calc2Contract.CalculatorContracts です)。

  8. HostAdapterAttribute 属性を CalculatorContractToViewHostSideAdapter クラスに適用して、クラスをホスト側アダプターとして指定します。

  9. CalculatorContractToViewHostSideAdapter クラスが、CalcHVAs.Calculator (Visual Basic では Calc2HVA.CalcHVAs.Calculator) というアドインのホスト ビューを表す抽象基本クラスを継承するようにします。 アドインのホスト ビューがインターフェイスである Version 1 との相違に注意してください。

  10. ICalc2Contract というパイプライン コントラクト タイプを受け取るパブリック コンストラクターを追加します。 このコンストラクターは、コントラクトへの参照をキャッシュする必要があります。 コントラクタの新しい ContractHandle を作成およびキャッシュして、アドインの有効期間を管理する必要もあります。

    重要 :重要

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

  11. Calculator のメンバーをオーバーライドするには、コンストラクターに渡される ICalc2Contract インスタンスの対応するメンバーを呼び出し、結果を返します。 これによって、コントラクト (ICalc2Contract) がビュー (Calculator) に適応します。

    完成したホスト側アダプター セグメントを次のコードに示します。

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.AddIn.Pipeline
    Imports Calc2HVA.CalcHVAs
    Imports Calc2Contract.CalculatorContracts
    
    Namespace CalculatorContractsHostAdapers
        <HostAdapter()> _
        Public Class CalculatorContractToViewHostAdapter
            Inherits Calculator
    
        Private _contract As ICalc2Contract
        Private _handle As ContractHandle
    
        Public Sub New(ByVal contract As ICalc2Contract)
            _contract = contract
            _handle = New ContractHandle(contract)
        End Sub
    
        Public Overrides ReadOnly Property Operations() As String
            Get
                Return _contract.GetAvailableOperations()
            End Get
        End Property
    
        Public Overrides Function Operate(ByVal operation As String, ByVal a As Double, ByVal b As Double) As Double
            Return _contract.Operate(operation, a, b)
        End Function
    End Class
    End Namespace
    
    using System.AddIn.Pipeline;
    using CalcHVAs;
    using CalculatorContracts;
    
    namespace CalcHostSideAdapters {
    
    
    [HostAdapter]
    public class CalculatorContractToViewHostAdapter : Calculator {
    
        private CalculatorContracts.ICalc2Contract _contract;
    
        private System.AddIn.Pipeline.ContractHandle _handle;
    
        public CalculatorContractToViewHostAdapter(ICalc2Contract contract) {
            _contract = contract;
            _handle = new System.AddIn.Pipeline.ContractHandle(contract);
        }
    
    
        public override string Operations
        {
            get 
            { 
                return _contract.GetAvailableOperations(); 
            }
        }
    
        public override double Operate(string operation, double a, double b)
        {
            return _contract.Operate(operation, a, b);
        }
     }
    }
    

ホストの作成

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

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

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

  • 使用するアドインを指定するように促すメッセージを表示する。 この例では、2 つのアドインを使用できることがわかります。

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

  • RunCalculator メソッドを実行する。これにより、アドインのホスト ビューの指定に従ってアドインのメソッドが呼び出されます。

ホストを作成するには

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

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

  3. Calc2HVA プロジェクトへのプロジェクト参照を追加します。 参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、各プロジェクト参照を選択し、[プロパティ][ローカルにコピーする][False] に設定します。 Visual Basic で、[プロジェクトのプロパティ][参照] タブを使用して、[ローカルにコピーする][False] に設定します。

  4. クラス ファイル (Visual Basic ではモジュール) の名前を MathHost2 に変更します。

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

  6. クラス ファイルまたはモジュール ファイルに、System.AddIn.Hosting への名前空間参照を追加します。

  7. クラス ファイルまたはモジュール ファイルに、CalcHVAs というアドインのホスト ビューに対応する名前空間参照を追加します (Visual Basic では、Visual Basic プロジェクトで既定の名前空間をオフにしていない限り、この名前空間参照は Calc2HVA.CalcHVAs です)。

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

  9. 次のコードを使用してホスト アプリケーションを作成します。

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Text
    Imports System.AddIn.Hosting
    Imports Calc2HVA.CalcHVAs
    
    Namespace Mathhost
    
        Module MathHost2
    
            Sub Main()
                ' Assume that the current directory is the application folder, 
                ' and that it contains the pipeline folder structure. 
                Dim pipeRoot As String = Environment.CurrentDirectory & "\Pipeline"
    
                ' Rebuild the cache of pipline and add-in information.
                AddInStore.Rebuild(pipeRoot)
    
                ' Find add-ins of type Calculator under the specified pipeline root directory.
                Dim tokens As Collection(Of AddInToken) = AddInStore.FindAddIns(GetType(Calculator), pipeRoot)
    
                ' Determine which add-in to use.
                Dim calcToken As AddInToken = ChooseCalculator(tokens)
    
                ' Activate the selected AddInToken in a new  
                ' application domain with a specified security trust level.
                Dim calculator As Calculator = calcToken.Activate(Of Calculator)(AddInSecurityLevel.Internet)
    
                ' Run the calculator.
                RunCalculator(calculator)
            End Sub
    
            Private Function ChooseCalculator(ByVal tokens As Collection(Of AddInToken)) As AddInToken
                If tokens.Count = 0 Then
                    Console.WriteLine("No calculators are available")
                    Return Nothing
                End If
                Console.WriteLine("Available Calculators: ")
                ' Show the token properties for each token 
                ' in the AddInToken collection (tokens),
                ' preceded by the add-in number in [] brackets.
    
                Dim tokNumber As Integer = 1
                For Each tok As AddInToken In tokens
                    Console.WriteLine(vbTab & "[{0}]: {1} - {2}" & _
                            vbLf & vbTab & "{3}" & _
                            vbLf & vbTab & "{4}" & _
                            vbLf & vbTab & "{5} - {6}", _
                            tokNumber.ToString, tok.Name, _
                            tok.AddInFullName, tok.AssemblyName, _
                            tok.Description, tok.Version, tok.Publisher)
                    tokNumber = tokNumber + 1
                Next
                Console.WriteLine("Which calculator do you want to use?")
                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 ChooseCalculator(tokens)
            End Function
    
            Private Sub RunCalculator(ByVal calc As Calculator)
    
                If calc Is Nothing Then
                    'No calculators were found, read a line and exit
                    Console.ReadLine()
                End If
                Console.WriteLine("Available operations: " & calc.Operations)
                Console.WriteLine("Request a calculation , such as: 2 + 2")
                Console.WriteLine("Type ""exit"" to exit")
                Dim line As String = Console.ReadLine()
                Do While Not line.Equals("exit")
                    ' Parser  
                    Try
                        Dim c As Parser = New Parser(line)
                        Console.WriteLine(calc.Operate(c.action, c.A, c.B))
                    Catch
                        Console.WriteLine("Invalid command: {0}. Commands must be formated: [number] [operation] [number]", line)
                        Console.WriteLine("Available operations: " & calc.Operations)
                    End Try
    
                    line = Console.ReadLine()
                Loop
            End Sub
        End Module
    
    
        Friend Class Parser
    
            Public partA As Double
    
            Public partB As Double
    
            Public action As String
    
            Friend Sub New(ByVal line As String)
                MyBase.New()
                Dim parts() As String = line.Split(" ")
                partA = Double.Parse(parts(0))
                action = parts(1)
                partB = Double.Parse(parts(2))
            End Sub
    
            Public ReadOnly Property A() As Double
                Get
                    Return partA
                End Get
            End Property
    
            Public ReadOnly Property B() As Double
                Get
                    Return partB
                End Get
            End Property
    
            Public ReadOnly Property CalcAction() As String
                Get
                    Return action
                End Get
            End Property
        End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Text;
    using System.AddIn.Hosting;
    using CalcHVAs;
    
    namespace MathHost
    {
        class Program
        {
            static void Main()
            {
                // Assume that the current directory is the application folder, 
                // and that it contains the pipeline folder structure. 
                String addInRoot = Environment.CurrentDirectory + "\\Pipeline";
    
                //Check to see if new add-ins have been installed.
                AddInStore.Rebuild(addInRoot);
    
                //Search for Calculator add-ins.
                Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(Calculator), addInRoot);
    
                //Ask the user which add-in they would like to use.
                AddInToken calcToken = ChooseCalculator(tokens);
    
                //Activate the selected AddInToken in a new
                //application domain with the Internet trust level.
                Calculator calculator = calcToken.Activate<Calculator>(AddInSecurityLevel.Internet);
    
                //Run the add-in.
                RunCalculator(calculator);
            }
    
            private static AddInToken ChooseCalculator(Collection<AddInToken> tokens)
            {
                if (tokens.Count == 0)
                {
                    Console.WriteLine("No calculators are available");
                    return null;
                }
                Console.WriteLine("Available Calculators: ");
                // Show the token properties for each token 
                // in the AddInToken collection (tokens),
                // preceded by the add-in number in [] brackets.
                int tokNumber = 1;
                foreach (AddInToken tok in tokens)
                {
                    Console.WriteLine(String.Format("\t[{0}]: {1} - {2}\n\t{3}\n\t\t {4}\n\t\t {5} - {6}",
                        tokNumber.ToString(), 
                        tok.Name,
                        tok.AddInFullName,
                        tok.AssemblyName,
                        tok.Description,
                        tok.Version,
                        tok.Publisher));
                    tokNumber++;
                }
                Console.WriteLine("Which calculator do you want to use?");
                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 ChooseCalculator(tokens);
            }
    
            private static void RunCalculator(Calculator calc)
            {
    
                if (calc == null)
                {
                    //No calculators were found, read a line and exit.
                    Console.ReadLine();
                }
                Console.WriteLine("Available operations: " + calc.Operations);
                Console.WriteLine("Type \"exit\" to exit");
                String line = Console.ReadLine();
                while (!line.Equals("exit"))
                {
                    // The Parser class parses the user's input.
                    try
                    {
                        Parser c = new Parser(line);
                        Console.WriteLine(calc.Operate(c.Action, c.A, c.B));
                    }
                    catch
                    {
                        Console.WriteLine("Invalid command: {0}. Commands must be formated: [number] [operation] [number]", line);
                        Console.WriteLine("Available operations: " + calc.Operations);
                    }
    
                    line = Console.ReadLine();
                }
            }
        }
    
    
        internal class Parser
        {
            internal Parser(String line)
            {
                String[] parts = line.Trim().Split(' ');
                a = Double.Parse(parts[0]);
                action = parts[1];
                b = Double.Parse(parts[2]);
            }
    
            double a;
    
            public double A
            {
                get { return a; }
            }
            double b;
    
            public double B
            {
                get { return b; }
            }
            String action;
    
            public String Action
            {
                get { return action; }
            }
        }
    }
    
    メモメモ

    このコードでは、アプリケーション フォルダーにパイプライン フォルダー構造があると仮定しています。別の場所にある場合は、addInRoot 変数を設定するコード行を変更して、パイプライン ディレクトリ構造へのパスを変数に設定します。

アドインの作成

アドインにより、アドイン ビューで指定されたメソッドを実装します。 このアドインでは、Operations メソッドによって、アドインでサポートされる算術演算が指定された文字列が返されます。 Operate メソッドにより、ホストで選択された演算と 2 つの数値に基づく計算を実行するコードが作成されます。

アドインを作成するには

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

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

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. Calc2AddInView プロジェクトへのプロジェクト参照を追加します。 参照アセンブリがローカルなビルド フォルダーにコピーされることのないように、各プロジェクト参照を選択し、[プロパティ][ローカルにコピーする][False] に設定します。 Visual Basic で、[プロジェクトのプロパティ][参照] タブを使用して、[ローカルにコピーする][False] に設定します。

  4. クラス ファイル名を SampleV2AddIn に変更します。

  5. クラス ファイルに、System.AddIn および System.AddIn.Pipeline への名前空間参照を追加します。 System.AddIn.Pipeline が必要なのは、コードに QualificationDataAttribute 属性の例が含まれているためです。

  6. クラス ファイルに、CalcAddInViews (Visual Basic では Calc2AddInView.CalcAddInViews) という、Version 2 のアドイン ビュー セグメントの名前空間参照を追加します。

  7. AddInAttribute 属性を SampleV2AddIn クラスに適用して、クラスをアドインとして指定します。

  8. QualificationDataAttribute 属性を SampleV2AddIn クラスに適用し、ホストが AddInToken から取得できる情報を指定します。 この場合、情報は、アドインが各自のアプリケーション ドメインにあることを示します。 「方法 : 修飾データを使用する」を参照してください。

  9. SampleV2AddIn クラスが、Calculator2 というアドイン ビューを表す抽象基本クラスを継承するようにします。

  10. Calculator2 のメンバーをオーバーライドし、適切な計算の結果を返します。

    完成したアドインを次に示します。

    
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.AddIn
    Imports System.AddIn.Pipeline
    Imports Calc2AddInView.CalcAddInViews
    
    Namespace CalculatorAddIns
    ' This pipeline segment has
    ' two attributes:
    ' 1 - An AddInAttribute to identify
    '     this segment as an add-in.
    '
    ' 2 - A QualificationDataAttribute to
    '     indicate that the add-in should
    '     be loaded into a new application domain.
    
    <AddIn("Calculator Add-in", Version:="2.0.0.0")> _
    <QualificationData("Isolation", "NewAppDomain")> _
        Public Class SampleV2AddIn
        Inherits Calculator2
    Public Overrides ReadOnly Property Operations() As String
        Get
            Return "+, -, *, /, **"
        End Get
    End Property
    
    Public Overrides Function Operate(ByVal operation As String, _
            ByVal a As Double, ByVal b As Double) As Double
        Select Case operation
            Case "+"
                Return a + b
            Case "-"
                Return a - b
            Case "*"
                Return a * b
            Case "/"
                Return a / b
            Case "**"
                Return Math.Pow(a, b)
            Case Else
                Throw New InvalidOperationException("This add-in does not support: " & operation)
        End Select
    End Function
    
    End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.AddIn;
    using System.AddIn.Pipeline;
    using CalcAddInViews;
    namespace CalcAddIns
    {
    // This pipeline segment has
    // two attributes:
    // 1 - An AddInAttribute to identify
    //     this segment as an add-in.
    //
    // 2 - A QualificationDataAttribute to
    //     indicate that the add-in should
    //     be loaded into a new application domain.
    
        [AddIn("Calculator Add-in",Version="2.0.0.0")]
        [QualificationData("Isolation", "NewAppDomain")]
        public class SampleV2AddIn : Calculator2
        {
            public override string Operations
            {
                get
                {
                    return "+, -, *, /, **";
                }
            }
    
            public override double Operate(string operation, double a, double b)
            {
                switch (operation)
                {
                    case "+":
                        return a + b;
                    case "-":
                        return a - b;
                    case "*":
                        return a * b;
                    case "/":
                        return a / b;
                    case "**":
                        return Math.Pow(a, b);
                    default:
                        throw new InvalidOperationException("This add-in does not support: " + operation);
                }
            }
    
        }
    }
    

パイプラインの配置

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

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

  1. ソリューション内の各プロジェクトについて、[プロジェクトのプロパティ][ビルド] タブ (Visual Basic では [コンパイル] タブ) を使用して、[出力パス] (Visual Basic では [ビルド出力パス]) の値を設定します。 たとえば、アプリケーション フォルダーの名前が MyApp の場合、プロジェクトは次のフォルダーにビルドされます。

    プロジェクト

    パス

    AddInCalcV2

    MyApp\Pipeline\AddIns\CalcV2

    Calc2AddInSideAdapter

    MyApp\Pipeline\AddInSideAdapters

    Calc2V1toV2AddInSideAdapter

    MyApp\Pipeline\AddInSideAdapters

    Calc1AddInView

    MyApp\Pipeline\AddInViews

    Calc2AddInView

    MyApp\Pipeline\AddInViews

    Calc2Contract

    MyApp\Pipeline\Contracts

    MathHost2

    MyApp

    Calc2HostSideAdapter

    MyApp\Pipeline\HostSideAdapters

    Calc2HVA

    MyApp

    メモメモ

    アプリケーション フォルダー以外の場所にパイプライン フォルダー構造を配置した場合は、それに応じて、表内のパスを変更する必要があります。

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

  3. アプリケーション ディレクトリおよびパイプライン ディレクトリをチェックして、アセンブリが正しいディレクトリにコピーされ、余分なアセンブリが間違ったフォルダーにインストールされていないことを確認します。

    メモメモ

    AddInCalcV2 プロジェクト内で、Calc2AddInView プロジェクト参照について、[ローカルにコピーする][False] に変更しなかった場合、ローダー コンテキストの問題が原因で、アドインを見つけることができません。

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

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

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

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

  1. 両方のバージョンのアドインが配置されていることを確認します。

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

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

  4. 電卓に数式を入力します。たとえば、「2 + 2」などと入力します。

  5. 「exit」と入力し、Enter キーを押して、アプリケーションを閉じます。

  6. 手順 2. ~ 5. を繰り返して、他のアドインを実行します。

参照

処理手順

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

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

概念

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

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

パイプラインの開発