Поделиться через


Пошаговое руководство. Включение обратной совместимости при изменении основного приложения

В этом пошаговом руководстве описывается версия 2 конвейера, который описан в разделе Пошаговое руководство. Создание расширяемого приложения. Версия 2 содержит дополнительные функциональные возможности вычислений путем предоставления основному приложению строки поддерживаемых арифметических действий, разделенных запятыми. Затем основное приложение выбирает действие и отправляет формулу в надстройку для вычисления.

Конвейер содержит новое основное приложение и новый контракт. Чтобы разрешить функционирование надстройки версии 1 с новым основным приложением и контрактом, конвейер содержит представление надстройки, которое используется для версии 1, а также адаптер на стороне надстройки, который преобразует данные из более старого представления надстройки в новый контракт. На следующем рисунке показаны, как обе надстройки могут работать с одним и тем же основным приложением.

Новое основное приложение, старые надстройки

Сценарий конвейера: новое основное приложение, старые надстройки.

Этот конвейер также описывается в разделе Сценарии конвейера надстройки.

В этом пошаговом руководстве описаны следующие задачи:

  • Создание решения в Visual Studio.

  • Создание структуры каталогов конвейера.

  • Создание контракта и представлений.

  • Создание адаптера на стороне надстройки, которая содержит адаптеры для новых версий надстройки, а также для надстройки версии 1.

  • Создание адаптера на стороне основного приложения.

  • Создание основного приложения.

  • Создание надстройки.

  • Развертывание конвейера.

  • Запуск основного приложения.

В этом пошаговом руководстве также демонстрируется использование абстрактных базовых классов для определения представлений, а также показано, что эти представления совместимы с представлениями, определенными в интерфейсах. Рекомендуется использовать интерфейсы.

ПримечаниеПримечание

В коде, приведенном в этом пошаговом руководстве, содержатся ссылки на внешние пространства имен.Действия в этом пошаговом руководстве с точностью отражают ссылки, необходимые в Visual Studio.

Дополнительные примеры кода и CTP-версии средств построения конвейеров надстроек см. на веб-узле CodePlex в разделе, посвященном управлению расширениями и надстройками.

Обязательные компоненты

Ниже приведены компоненты, необходимые для выполнения данного пошагового руководства.

  • 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.

    Можно предоставить эти методы в контракте как свойства представлений путем преобразования вызова метода в свойство адаптера.

  • Метод Operate.

    Основное приложение вызывает этот метод для отправки формулы в надстройку для вычисления и возвращения результата.

Чтобы создать контракт

  1. В решении Visual Studio CalculatorV2 откройте проект 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);
        }
    }
    

Так как в представлении надстройки и в представлении основного приложения используется один и тот же код, можно без труда создать оба представления одновременно. Они отличаются только одним: представление настройки нуждается в атрибуте AddInBaseAttribute; представление основного приложения, относящееся к надстройке, ни в каких атрибутах не нуждается.

Чтобы создать представление надстройки для версии 2

  1. Добавьте новый проект с именем Calc2AddInView в решение CalculatorV2. Он должен быть основан на шаблоне Библиотека классов.

  2. В обозревателе решений добавьте ссылку на System.AddIn.dll в проект Calc2AddInView.

  3. Переименуйте класс в Calculator2.

  4. В файле класса добавьте ссылку на пространство имен к System.AddIn.Pipeline.

  5. Сделайте Calculator2 классом abstract (MustInherit в Visual Basic).

  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 (MustInherit в Visual Basic).

  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.

Чтобы добавить проект представления надстройки из версии 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 этими ссылками на пространства имен являются Calc2AddInView.CalcAddInViews и Calc2Contract.CalculatorContracts, если только в проектах Visual Basic не были отключены пространства имен по умолчанию.)

  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 этими ссылками на пространства имен являются Calc1AddInView.CalcAddInViews и Calc2Contract.CalculatorContracts, если только в проектах Visual Basic не были отключены пространства имен по умолчанию.) Обратите внимание, что пространство имен представления берется из версии 1, а контракт из версии 2.

  8. Примените атрибут AddInAdapterAttribute к классу Calc2V1ViewToV2ContractAddInSideAdapter, чтобы указать его в качестве адаптера на стороне надстройки.

  9. Класс Calc2V1ViewToV2ContractAddInSideAdapter должен наследовать ContractBase, что предоставляет реализацию интерфейса IContract по умолчанию и реализует интерфейс контракта версии 2 для конвейера ICalc2Contract.

  10. Добавьте открытый конструктор, который принимает ICalculator, кэширует его в закрытом поле и вызывает базовый класс конструктора.

  11. Чтобы реализовать элементы ICalc2Contract, необходимо вызвать соответствующие элементы экземпляра ICalculator, который передается в конструктор, после чего возвращается результат. Вследствие различий между интерфейсами контрактов версии 1 и версии 2 необходимо задействовать оператор switch (оператор Select Case в Visual Basic) для адаптации представления (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, чтобы связать с контрактом маркер времени существования. Чтобы механизм управления временем существования работал, необходимо хранить ссылку на данный дескриптор. После применения маркера пропадает необходимость в дополнительном программировании, так как система надстройки может удалить объекты, если они уже не используются, и сделать их доступными для сборщика мусора. Дополнительные сведения см. в разделе Управление жизненным циклом объекта.

Чтобы создать адаптер на стороне основного приложения

  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 этими ссылками на пространства имен являются Calc2HVA.CalcHVAs и Calc2Contract.CalculatorContracts, если только в проектах Visual Basic не отключены пространства имен по умолчанию.)

  8. Примените атрибут HostAdapterAttribute к классу CalculatorContractToViewHostSideAdapter, чтобы определить его как адаптер на стороне основного приложения.

  9. Класс CalculatorContractToViewHostSideAdapter должен наследовать абстрактный базовый класс, который представляет представление основного приложения, относящееся к надстройке: CalcHVAs.Calculator (Calc2HVA.CalcHVAs.Calculator в Visual Basic). Обратите внимание на отличие от версии 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);
        }
     }
    }
    

Создание основного приложения

Основное приложение взаимодействует с надстройкой посредством представления основного приложения. При этом используются методы обнаружения и активации надстройки, которые предоставляются классами AddInStore и AddInToken для выполнения следующих действий:

  • Повторное создание кэша конвейера и сведений надстройки.

  • Обнаружение надстроек типа 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 этой ссылкой на пространство имен является Calc2HVA.CalcHVAs, если только в проектах Visual Basic не были отключены пространства имен по умолчанию.)

  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.AddIn и System.AddIn.Pipeline. Пространство имен System.AddIn.Pipeline необходимо только потому, что код включает пример атрибута QualificationDataAttribute.

  6. В файле класса добавьте ссылку на пространство имен для сегмента представления надстройки версии 2: CalcAddInViews (Calc2AddInView.CalcAddInViews в Visual Basic).

  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. Для каждого проекта в этом решении используйте вкладку Построение свойств проекта (вкладка Compile в 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. Проверьте каталоги приложения и конвейера, чтобы удостовериться в том, что сборки были скопированы в правильные каталоги и что в других папках не осталось дополнительных копий сборок.

    ПримечаниеПримечание

    Если для параметра Копировать локально не было задано значение False для ссылки проекта Calc2AddInView в проекте AddInCalcV2, контекстные проблемы загрузчика помешают нахождению надстройки.

    Сведения о развертывании в конвейере см. в разделе Требования к разработке конвейера.

Запуск основного приложения

Теперь все готово для запуска основного приложения и взаимодействия с надстройками.

Чтобы выполнить основное приложение

  1. Убедитесь, что развернуты обе версии надстройки.

  2. В командной строке перейдите в каталог приложение и запустите основное приложение. В этом примере основным приложением является MathHost2.exe.

  3. Основное приложение находит все доступные надстройки этого типа и запрашивает пользователя о выборе надстройки. Введите 1 или 2.

  4. Введите формулу для калькулятора, например 2 + 2.

  5. Введите команду exit и нажмите клавишу ВВОД, чтобы закрыть приложение.

  6. Повторите шаги 2-5 для запуска другой надстройки.

См. также

Задачи

Пошаговое руководство. Создание расширяемого приложения

Пошаговое руководство. Передача коллекций между основными приложениями и надстройками

Основные понятия

Требования к разработке конвейера

Контракты, представления и адаптеры

Разработка конвейера