逐步解說:在主應用程式變更時確保回溯相容性

本逐步解說將說明逐步解說:建立可延伸應用程式中描述的第 2 版管線。 第 2 版中包含更多計算功能,其中提供了支援主應用程式之算術運算的逗號分隔字串。 主應用程式接著便可以選擇一項運算,並送出方程式,讓增益集進行計算。

管線具有新的主應用程式和新合約。 若要讓第 1 版的增益集與新的主應用程式和合約搭配使用,管線要包含第 1 版中使用的增益集檢視和增益集端配接器 (Adapter),將資料從舊的增益集檢視轉換為新合約。 下圖顯示如何讓兩種增益集搭配相同的主應用程式使用。

新的主應用程式,舊的增益集

管線案例:新的主應用程式、舊的增益集。

這個管線也將在增益集管線案例中說明。

本逐步解說將說明下列工作:

  • 建立 Visual Studio 方案。

  • 建立管線目錄結構。

  • 建立合約和檢視。

  • 建立增益集端配接器,其中包括新版增益集和第 1 版增益集的配接器。

  • 建立主應用程式端配接器。

  • 建立主應用程式。

  • 建立增益集。

  • 部署管線。

  • 執行主應用程式。

本逐步解說同時示範使用抽象基底類別定義檢視,並顯示這類檢視與介面定義的檢視相容。 建議您使用介面。

注意事項注意事項

本逐步解說中顯示的部分程式碼包含沒有直接關聯的命名空間參考。逐步解說的步驟會精確反映出 Visual Studio 中所需的參考。

您可以在 CodePlex 上的 Managed 擴充性及增益集架構網站 (英文) 找到更多範例程式碼,以及可用來建置增益集管線之工具的客戶技術預覽。

必要條件

您需要下列元件才能完成此逐步解說:

  • Visual Studio.

  • 第 1 版的管線會在逐步解說:建立可延伸應用程式中說明。 由於第 2 版使用了第 1 版內開發的管線區段,因此您必須先開發及部署第 1 版的管線,才能執行本主題內的步驟。

建立 Visual Studio 方案

您可以使用 Visual Studio 內的方案來包含管線區段的專案。

若要建立管線方案

  1. 在 Visual Studio 中,建立名為 Calc2Contract 的新專案。 以 [類別庫] 範本為基礎。

  2. 將方案命名為 CalculatorV2。

建立管線目錄結構

增益集模型需要將管線區段組件放置在指定的目錄結構中。

若要建立管線目錄結構

  • 如果您尚未將 CalcV2 資料夾加入至逐步解說:建立可延伸應用程式中建立的管線資料夾結構,請先完成這項操作。 CalcV2 資料夾將保存新版的增益集。

    Pipeline
      AddIns
        CalcV1
        CalcV2
      AddInSideAdapters
      AddInViews
      Contracts
      HostSideAdapters
    

    管線資料夾結構並不一定要放置在應用程式資料夾中,為了方便在這些逐步解說中操作才這麼做。 如果您在第一個逐步解說中將管線資料夾結構放置在其他位置,請在本逐步解說中採用相同的方式。 請參閱管線開發需求中有關管線目錄需求的討論。

建立合約和檢視

這個管線的合約區段定義會 ICalc2Contract 介面,這個介面具有下列兩種方法:

  • GetAvailableOperations 方法。

    此方法會傳回數學運算字串,表示增益集支援主應用程式的數學運算。 第 2 版支援五種運算,而且這個方法會傳回字串 "+,-,*,/,**",其中 "**" 代表 Pow 運算。

    在增益集和主應用程式檢視中,此方法名為 Operations,而不是 GetAvailableOperations。

    您可以藉由將方法呼叫轉換為配接器的屬性,將合約的方法公開 (Expose) 為檢視的屬性。

  • Operate 方法。

    主應用程式會呼叫此方法,送出方程式供增益集進行計算,然後傳回結果。

若要建立合約

  1. 在名為 CalculatorV2 的 Visual Studio 方案中,開啟 Calc2Contract 專案。

  2. 在 [方案總管] 中,將下列組件的參考加入至 Calc2Contract 專案:

    System.AddIn.Contract.dll

    System.AddIn.dll

  3. 在 [方案總管] 中,排除加入至新 [類別庫] 專案的預設類別。

  4. 使用 [介面] 範本將新項目加入至專案。 在 [加入新項目] 對話方塊中,將介面命名為 ICalc2Contract。

  5. 在介面檔 (Interface File) 中,加入 System.AddIn.ContractSystem.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);
        }
    }
    

由於增益集檢視和主應用程式檢視具有相同的程式碼,所以您可以很輕鬆地同時建立這些檢視。 其中唯一不同的一個因素是:增益集檢視需要 AddInBaseAttribute 屬性,但增益集的主應用程式檢視則不需要任何屬性。

若要建立第 2 版的增益集檢視

  1. 將名為 Calc2AddInView 的新專案加入至 CalculatorV2 方案。 以 [類別庫] 範本為基礎。

  2. 在 [方案總管] 中,將 System.AddIn.dll 的參考加入至 Calc2AddInView 專案。

  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. 將名為 Calc2HVA 的新專案加入至 CalculatorV2 方案。 以 [類別庫] 範本為基礎。

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

若要使用新的主應用程式示範第 1 版增益集的使用方式,方案必須包含為第 1 版 calculator 增益集建立的增益集檢視。

若要加入來自第 1 版的增益集檢視專案

  1. 在 [方案總管] 中,以滑鼠右鍵按一下 [CalculatorV2] 方案。

  2. 按一下 [加入],再按一下 [現有專案]。

  3. 移至包含 CalculatorV1 方案的資料夾,並選取 Calc1AddInView 專案的專案檔。

建立增益集端配接器

這個增益集端配接器是由兩個檢視至合約配接器所組成:其中一個用來配接第 2 版增益集檢視至第 2 版合約,另一個則用來配接第 1 版增益集檢視至第 2 版合約。

在本管線中,增益集提供主應用程式服務,型別也會從增益集移往主應用程式。 由於沒有型別從主應用程式移往增益集,因此不需要包含合約至檢視配接器。

若要建立增益集端配接器

  1. 將名為 Calc2AddInSideAdapter 的新專案加入至 CalculatorV2 方案。 以 [類別庫] 範本為基礎。

  2. 在 [方案總管] 中,將下列組件的參考加入至 Calc2AddInSideAdapter 專案:

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 將專案參考加入至下列專案:

    Calc2AddInView

    Calc2Contract

  4. 選取每個專案參考,然後在 [屬性] 中,將 [複製到本機] 設定為 [False],使參考的組件無法複製到本機建置資料夾。 組件將位於管線目錄中,如本逐步解說稍後的「部署管線」程序所述。 在 Visual Basic 中,使用 [專案屬性] 的 [參考] 索引標籤,將兩個專案參考的 [複製到本機] 設定為 [False]。

  5. 重新命名專案的預設類別 CalculatorViewToContractAddInSideAdapter。

  6. 在類別檔案中,加入 System.AddIn.Pipeline 的命名空間參考。

  7. 在類別檔案中,加入相鄰區段的命名空間參考:CalcAddInViews 和 CalculatorContracts 除非您有關閉 Visual Basic 專案中的預設命名空間,否則在 Visual Basic 中,這些命名空間參考為 Calc2AddInView.CalcAddInViews 和 Calc2Contract.CalculatorContracts。

  8. 使用下列程式碼做為這個增益集端配接器。 實作模式與第 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);
            }
    
        }
    }
    

若要讓第 1 版增益集與新的主應用程式進行通訊,第 1 版增益集的管線需要增益集端配接器,將資料從舊的增益集檢視轉換成新合約。

若要建立第 1 版至第 2 版的增益集端配接器

  1. 將名為 Calc2V1toV2AddInSideAdapter 的新專案加入至 CalculatorV2 方案。 以 [類別庫] 範本為基礎。

  2. 在 [方案總管] 中,將下列組件的參考加入至 Calc2V1toV2AddInSideAdapter 專案:

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 將專案參考加入至下列專案:

    Calc1AddInView

    Calc2Contract

  4. 選取每個專案參考,然後在 [屬性] 中,將 [複製到本機] 設定為 [False],使參考的組件無法複製到本機建置資料夾。 在 Visual Basic 中,使用 [專案屬性] 的 [參考] 索引標籤,將兩個專案參考的 [複製到本機] 設定為 [False]。

  5. 重新命名專案的預設類別 Calc2V1ViewToV2ContractAddInSideAdapter。

  6. 在類別檔案中,加入 System.AddIn.Pipeline 的命名空間參考。

  7. 在類別檔案中,加入相鄰區段的命名空間參考:CalcAddInViews 和 CalculatorContracts 除非您有關閉 Visual Basic 專案中的預設命名空間,否則在 Visual Basic 中,這些命名空間參考為 Calc1AddInView.CalcAddInViews 和 Calc2Contract.CalculatorContracts。 請注意,檢視命名空間來自第 1 版,合約則來自第 2 版。

  8. 套用 AddInAdapterAttribute 屬性至 Calc2V1ViewToV2ContractAddInSideAdapter 類別,以識別做為增益集端配接器。

  9. 讓 Calc2V1ViewToV2ContractAddInSideAdapter 類別繼承 ContractBase,該基底類別提供 IContract 介面的預設實作,並實作管線 ICalc2Contract 的第 2 版合約介面。

  10. 加入公用建構函式,以接受 ICalculator、快取至私用欄位並呼叫基底類別建構函式。

  11. 若要實作 ICalc2Contract 的成員,您必須呼叫傳遞至建構函式的 ICalculator 執行個體之適當成員,並且傳回結果。 由於第 1 版和第 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);
                }
            }
    
        }
    }
    

建立主應用程式端配接器

這個主應用程式端配接器是由一個合約至檢視配接器所組成。 只要有一個合約至檢視配接器,就足以支援兩個版本的增益集,因為每個增益集端配接器都會從各自的檢視轉換成第 2 版合約。

在本管線中,增益集提供主應用程式服務,型別也會從增益集移往主應用程式。 由於沒有型別從主應用程式移往增益集,您不需要包含檢視至合約的配接器。

若要實作存留期管理,請使用 ContractHandle 物件,將存留期語彙基元附加至合約。 您必須保留此控制代碼的參考,存留期管理才會運作。 套用語彙基元 (Token) 後便不需要進行其他的程式設計,因為增益集系統可以在不再使用物件時處置 (Dispose) 那些物件,並使其可供記憶體回收使用。 如需詳細資訊,請參閱 存留期管理

若要建立主應用程式端配接器

  1. 將名為 Calc2HostSideAdapter 的新專案加入至 CalculatorV2 方案。 以 [類別庫] 範本為基礎。

  2. 在 [方案總管],將下列組件的參考加入至 Calc2HostSideAdapter 專案:

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 將專案參考加入至下列專案:

    Calc2Contract

    Calc2HVA

  4. 選取每個專案參考,然後在 [屬性] 中,將 [複製到本機] 設定為 [False],使參考的組件無法複製到本機建置資料夾。 在 Visual Basic 中,使用 [專案屬性] 的 [參考] 索引標籤,將兩個專案參考的 [複製到本機] 設定為 [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)。 請注意與第 1 版的差異,其中增益集的主應用程式檢視為介面。

  10. 加入公用建構函式,以接受管線合約類型 ICalc2Contract。 建構函式必須快取合約參考, 也必須建立和快取合約的新 ContractHandle,以管理增益集的存留期。

    重要

    ContractHandle 對於存留期管理來說非常重要。如果您無法保留 ContractHandle 物件的參考,記憶體回收將會回收該物件,而且若程式不接受管線,管線將隨即關閉。這可能會造成難以診斷的錯誤,例如 AppDomainUnloadedException。關機是管線週期的正常階段,因此存留期管理程式碼無法將這種狀況偵測為錯誤。

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

建立主應用程式

主應用程式 (Host Application) 會透過主應用程式檢視與增益集互動。 它會使用 AddInStoreAddInToken 類別所提供的增益集探索 (Discovery) 和啟動方法,以執行下列動作:

  • 重建管線的快取和增益集資訊。

  • 在指定的管線根目錄下找出型別為 Calculator 的增益集。

  • 提示使用者指定要使用的增益集。 在這個範例中,您將會看到兩個可用的增益集。

  • 以指定的安全信任層級,啟動新的應用程式定義域中選取的增益集。

  • 執行 RunCalculator 方法,這會呼叫由增益集的主應用程式檢視所提供之增益集的方法。

若要建立主應用程式

  1. 將名為 MathHost2 的新專案加入至 CalculatorV2 方案。 以 [主控台應用程式] 範本為基礎。

  2. 在 [方案總管] 中,將 System.AddIn.dll 組件的參考加入至 MathHost2 專案。

  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 方法可提供程式碼,根據主應用程式選取的運算和兩個數字計算結果。

若要建立增益集

  1. 將名為 AddInCalcV2 的新專案加入至 CalculatorV2 方案。 以 [類別庫] 範本為基礎。

  2. 在 [方案總管] 中,將下列組件的參考加入至 AddInCalcV2 專案:

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 在 Calc2AddInView 專案中加入專案參考。 選取專案參考,然後在 [屬性] 中,將 [複製到本機] 設定為 [False],使參考的組件無法複製到本機建置資料夾。 在 Visual Basic 中,使用 [專案屬性] 的 [參考] 索引標籤,將 [複製到本機] 設定為 [False]。

  4. 重新命名類別檔案 SampleV2AddIn。

  5. 在類別檔案中,加入 System.AddInSystem.AddIn.Pipeline 的命名空間參考。 System.AddIn.Pipeline 只有在程式碼包含 QualificationDataAttribute 屬性的範例時才需要。

  6. 在類別檔案中,加入第 2 版增益集檢視區段的命名空間參考:CalcAddInViews (在 Visual Basic 中為 Calc2AddInView.CalcAddInViews)。

  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,執行其他增益集。

請參閱

工作

逐步解說:建立可延伸應用程式

逐步解說:在主應用程式和增益集之間傳遞集合

概念

管線開發需求

合約、檢視和配接器

管線開發