Пошаговое руководство. Создание расширяемого приложения
В этом пошаговом руководстве описано, как создать конвейер для надстройки, которая выполняет простые функции калькулятора. Здесь не приводится сценария, пригодного для использования в производственной среде, а просто демонстрируется основные функции конвейера и предоставление обслуживание надстройкой основного приложения.
В этом пошаговом руководстве описаны следующие задачи:
Создание решения в Visual Studio.
Создание структуры каталогов конвейера.
Создание контракта и представлений.
Создание адаптера на стороне надстройки.
Создание адаптера на стороне основного приложения.
Создание основного приложения.
Создание надстройки.
Развертывание конвейера.
Запуск основного приложения.
Этот конвейер передает только сериализованные типы (Double и String) между основным приложением и надстройкой. Пример, в котором показано, как передавать коллекции сложных типов данных, см. в разделе Пошаговое руководство. Передача коллекций между основными приложениями и надстройками.
Контракт для этого конвейера определяет модель объекта из четырех арифметических операций: сложение, вычитание, умножение и деление. Основное приложение предоставляет надстройке формулу, которую надо рассчитать, например 2 + 2, а надстройка возвращает обратно результат.
В версии 2 надстройки калькулятора предоставляются дополнительные возможности вычисления, и демонстрируется управление версиями. Это описано в разделе Пошаговое руководство. Включение обратной совместимости при изменении основного приложения.
Примечание |
---|
Дополнительные примеры кода и CTP-версии средств построения конвейеров надстроек см. на веб-узле CodePlex в разделе, посвященном управлению расширениями и надстройками. |
Обязательные компоненты
Для выполнения данного пошагового руководства необходимо следующее:
- Visual Studio.
Создание решения в Visual Studio.
Используйте решение в Visual Studio, чтобы разместить проекты сегментов конвейера.
Чтобы создать решение конвейера
В Visual Studio создайте новый проект с именем Calc1Contract. Он должен быть основан на шаблоне Библиотека классов.
Назовите решение CalculatorV1.
Создание структуры каталогов конвейера
Для модели надстройки необходимо, чтобы сборки сегментов конвейера были размещены в определенной структуре каталогов. Дополнительные сведения о структуре конвейера см. в разделе Требования к разработке конвейера.
Чтобы создать структуру каталогов конвейера
Создайте папку приложения где-либо на локальном компьютере.
В этой папке создайте следующую структуру:
Pipeline AddIns CalcV1 CalcV2 AddInSideAdapters AddInViews Contracts HostSideAdapters
Не необходимости размещать структуру папок конвейера в папке приложения; это делается только один раз для удобства. На определенном этапе этого пошагового руководства объясняется, как изменить код, если структура папок конвейера расположена в другом месте. См. описание требований к каталогам конвейера в разделе Требования к разработке конвейера.
Примечание Папка CalcV2 в этом пошаговом руководстве не используется; это местозаполнитель для Пошаговое руководство. Включение обратной совместимости при изменении основного приложения.
Создание контракта и представлений
Сегмент контракта для этого конвейера определяет интерфейс ICalc1Contract, который, в свою очередь, определяет четыре метода: add, subtract, multiply и divide.
Чтобы создать контракт
В решении Visual Studio с именем CalculatorV1 откройте проект Calc1Contract.
В обозревателе решений в проект Calc1Contract добавьте ссылки на следующие сборки:
System.AddIn.Contract.dll
System.AddIn.dll
В обозревателе решений исключите класс по умолчанию, который был добавлен в новые проекты Библиотека классов.
В Обозревателе решений добавьте в проект новый элемент с помощью шаблона Интерфейс. В диалоговом окне Добавление нового элемента назовите этот интерфейс ICalc1Contract.
В файле интерфейса добавьте ссылки на пространства имен к System.AddIn.Contract и System.AddIn.Pipeline.
Используйте следующий код для завершения этого сегмента контракта. Обратите внимание, что этот интерфейс должен иметь атрибут AddInContractAttribute.
Imports System.AddIn.Contract Imports System.AddIn.Pipeline Namespace CalculatorContracts ' The AddInContractAttribute identifes this pipeline segment as a ' contract. <AddInContract()> _ Public Interface ICalc1Contract Inherits IContract Function Add(ByVal a As Double, ByVal b As Double) As Double Function Subtract(ByVal a As Double, ByVal b As Double) As Double Function Multiply(ByVal a As Double, ByVal b As Double) As Double Function Divide(ByVal a As Double, ByVal b As Double) As Double End Interface End Namespace
using System.AddIn.Contract; using System.AddIn.Pipeline; namespace CalculatorContracts { // The AddInContractAttribute identifes this pipeline segment as a // contract. [AddInContract] public interface ICalc1Contract : IContract { double Add(double a, double b); double Subtract(double a, double b); double Multiply(double a, double b); double Divide(double a, double b); } }
При необходимости постройте решение Visual Studio. Это решение не может быть выполнено до процедуры завершения, однако ее построение после каждой процедуры гарантирует правильность каждого проекта.
Так как представление надстройки и представление основного приложения, относящееся к надстройке, как правило, не отличаются в коде, особенно в первой версии надстройки, можно без труда создать оба этих представления одновременно. Они отличаются только в одном: представление надстройки нуждается в атрибуте AddInBaseAttribute, тогда как представление основного приложения, относящееся к надстройке, не нуждается в атрибутах.
Чтобы создать представление надстройки
Добавьте новый проект с именем Calc1AddInView в решение CalculatorV1. Он должен быть основан на шаблоне Библиотека классов.
В обозревателе решений добавьте ссылку на System.AddIn.dll в проект Calc1AddInView.
В обозревателе решений исключите класс по умолчанию, который был добавлен в новые проекты Библиотека классов, затем добавьте новый элемент в этот проект с помощью шаблона Интерфейс. В диалоговом окне Добавление нового элемента назовите этот интерфейс ICalculator.
В файле интерфейса добавьте ссылку на пространство имен к System.AddIn.Pipeline.
Используйте следующий код для завершения этого представления надстройки. Обратите внимание, что этот интерфейс должен иметь атрибут AddInBaseAttribute.
Imports System.AddIn.Pipeline Namespace CalcAddInViews ' The AddInBaseAttribute identifes this interface as the basis for the ' add-in view pipeline segment. <AddInBaseAttribute()> _ Public Interface ICalculator Function Add(ByVal a As Double, ByVal b As Double) As Double Function Subtract(ByVal a As Double, ByVal b As Double) As Double Function Multiply(ByVal a As Double, ByVal b As Double) As Double Function Divide(ByVal a As Double, ByVal b As Double) As Double End Interface End Namespace
using System.AddIn.Pipeline; namespace CalcAddInViews { // The AddInBaseAttribute identifes this interface as the basis for // the add-in view pipeline segment. [AddInBase()] public interface ICalculator { double Add(double a, double b); double Subtract(double a, double b); double Multiply(double a, double b); double Divide(double a, double b); } }
При необходимости постройте решение Visual Studio.
Чтобы создать представление основного приложения, относящееся к надстройке
Добавьте к решению CalculatorV1 новый проект Calc1HVA. Он должен быть основан на шаблоне Библиотека классов.
В обозревателе решений исключите класс по умолчанию, который был добавлен в новые проекты Библиотека классов, затем добавьте новый элемент в этот проект с помощью шаблона Интерфейс. В диалоговом окне Добавление нового элемента назовите этот интерфейс ICalculator.
В файле интерфейса используйте следующий код для завершения представления основного приложения, относящегося к надстройке.
Namespace CalcHVAs Public Interface ICalculator Function Add(ByVal a As Double, ByVal b As Double) As Double Function Subtract(ByVal a As Double, ByVal b As Double) As Double Function Multiply(ByVal a As Double, ByVal b As Double) As Double Function Divide(ByVal a As Double, ByVal b As Double) As Double End Interface End Namespace
namespace CalcHVAs { public interface ICalculator { double Add(double a, double b); double Subtract(double a, double b); double Multiply(double a, double b); double Divide(double a, double b); } }
При необходимости постройте решение Visual Studio.
Создание адаптера на стороне надстройки
Этот адаптер на стороне надстройки состоит из одного адаптера "представление-контракт". В этом сегменте конвейера преобразуются типы из представления надстройки в контракт.
В этом конвейере надстройка обслуживает основное приложение, а типы направляются из надстройки в основное приложение. Так как никакие типы не направляются из основного приложения в надстройку, нет необходимости включать адаптер "контракт-представление" на стороне надстройки в этом конвейере.
Чтобы создать адаптер на стороне надстройки
Добавьте в решение CalculatorV1 новый проект Calc1AddInSideAdapter. Он должен быть основан на шаблоне Библиотека классов.
В обозревателе решений добавьте ссылки на следующие сборки в проект Calc1AddInSideAdapter.
System.AddIn.dll
System.AddIn.Contract.dll
Добавьте ссылки проекта на проекты прилегающих сегментов конвейера:
Calc1AddInView
Calc1Contract
Выберите ссылку каждого проекта и в поле Свойства задайте значение False для параметра Копировать локально. В Visual Basic используйте вкладку Ссылки в разделе Свойства проекта для задания значения параметра Копировать локально равным False для двух ссылок проекта.
Переименуйте класс проекта по умолчанию CalculatorViewToContractAddInSideAdapter.
В файле класса добавьте ссылки на пространство имен к System.AddIn.Pipeline.
В файле класса добавьте ссылки на пространства имен для прилегающих сегментов CalcAddInViews и CalculatorContracts. (В Visual Basic этими ссылками на пространства имен являются Calc1AddInView.CalcAddInViews и Calc1Contract.CalculatorContracts, если только не были отключены пространства имен по умолчанию в проектах Visual Basic).
Примените атрибут AddInAdapterAttribute к классу CalculatorViewToContractAddInSideAdapter, чтобы указать его в качестве адаптера на стороне надстройки.
Класс CalculatorViewToContractAddInSideAdapter должен наследовать ContractBase, что предоставляет реализацию интерфейса IContract по умолчанию и реализует интерфейс контракта для конвейера ICalc1Contract.
Добавьте открытый конструктор, который принимает ICalculator, кэширует его в закрытом поле и вызывает базовый класс конструктора.
Чтобы реализовать элементы ICalc1Contract, просто вызовите соответствующие элементы экземпляра ICalculator, которые передаются в конструктор, и возвратите результат. Это адаптирует представление (ICalculator) к контракту (ICalc1Contract).
В следующем коде показан завершенный адаптер на стороне надстройки.
Imports System.AddIn.Pipeline Imports Calc1AddInView.CalcAddInViews Imports Calc1Contract.CalculatorContracts Namespace CalcAddInSideAdapters ' The AddInAdapterAttribute identifes this class as the add-in-side ' adapter pipeline segment. <AddInAdapter()> _ Public Class CalculatorViewToContractAddInSideAdapter Inherits ContractBase Implements ICalc1Contract Private _view As ICalculator Public Sub New(ByVal view As ICalculator) MyBase.New() _view = view End Sub Public Function Add(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Add Return _view.Add(a, b) End Function Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Subtract Return _view.Subtract(a, b) End Function Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Multiply Return _view.Multiply(a, b) End Function Public Function Divide(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Divide Return _view.Divide(a, b) End Function End Class End Namespace
using System.AddIn.Pipeline; using CalcAddInViews; using CalculatorContracts; namespace CalcAddInSideAdapters { // The AddInAdapterAttribute identifes this class as the add-in-side adapter // pipeline segment. [AddInAdapter()] public class CalculatorViewToContractAddInSideAdapter : ContractBase, ICalc1Contract { private ICalculator _view; public CalculatorViewToContractAddInSideAdapter(ICalculator view) { _view = view; } public virtual double Add(double a, double b) { return _view.Add(a, b); } public virtual double Subtract(double a, double b) { return _view.Subtract(a, b); } public virtual double Multiply(double a, double b) { return _view.Multiply(a, b); } public virtual double Divide(double a, double b) { return _view.Divide(a, b); } } }
При необходимости постройте решение Visual Studio.
Создание адаптера на стороне основного приложения
Этот адаптер на стороне основного приложения состоит из одного адаптера "контракт-представление". Этот сегмент адаптирует контракт к представлению основного приложения, относящемуся к надстройке.
В этом конвейере надстройка обслуживает основное приложение, а типы направляются из надстройки в основное приложение. Так как никакие типы не направляются от основного приложения в надстройку, нет необходимости включать адаптер "представление-контракт".
Для управления временем существования необходимо использовать объект ContractHandle, чтобы связать с контрактом маркер времени существования. Чтобы механизм управления временем существования работал, необходимо хранить ссылку на данный дескриптор. После применения маркера пропадает необходимость в дополнительном программировании, так как система надстройки может удалить объекты, если они уже не используются, и сделать их доступными для сборщика мусора. Дополнительные сведения см. в разделе Управление жизненным циклом объекта.
Чтобы создать адаптер на стороне основного приложения
Добавьте новый проект с именем Calc1HostSideAdapter в решение CalculatorV1. Он должен быть основан на шаблоне Библиотека классов.
В обозревателе решений добавьте ссылки на следующие сборки в проект Calc1HostSideAdapter:
System.AddIn.dll
System.AddIn.Contract.dll
Добавление ссылок проекта в проекты прилегающих сегментов:
Calc1Contract
Calc1HVA
Выберите ссылку каждого проекта и в поле Свойства задайте значение False для параметра Копировать локально. В Visual Basic используйте вкладку Ссылки в разделе Свойства проекта для задания значения параметра Копировать локально равным False для двух ссылок проекта.
Переименуйте класс проекта по умолчанию CalculatorContractToViewHostSideAdapter.
В файле класса добавьте ссылки на пространство имен к System.AddIn.Pipeline.
В файле класса добавьте ссылки на пространства имен для прилегающих сегментов: CalcHVAs и CalculatorContracts. (В Visual Basic этими ссылками на пространства имен являются Calc1HVA.CalcHVAs и Calc1Contract.CalculatorContracts, если только пространства имен по умолчанию не были отключены в проектах Visual Basic.)
Примените атрибут HostAdapterAttribute к классу CalculatorContractToViewHostSideAdapter, чтобы определить его как сегмент адаптера на стороне основного приложения.
Класс CalculatorContractToViewHostSideAdapter должен реализовывать интерфейс, который представляет представление основного приложения, относящееся к надстройке: Calc1HVAs.ICalculator (Calc1HVA.CalcHVAs.ICalculator в Visual Basic).
Добавьте открытый конструктор, который принимает тип контракта конвейера ICalc1Contract. Конструктор должен кэшировать ссылки на контракт. Также он должен создавать и кэшировать новый дескриптор ContractHandle для контракта, чтобы управлять жизненным циклом надстройки.
Важно Дескриптор ContractHandle играет ключевую роль в управлении временем существования.Если не сохранить ссылку на объект ContractHandle, он будет удален при сборке мусора, и конвейер закроется неожиданно для программы.Это может вызвать ошибки, которые сложно диагностировать, например AppDomainUnloadedException.Завершение работы является неотъемлемым этапом жизненного цикла конвейера, поэтому с помощью кода управления временем существования невозможно определить такое состояние как ошибку.
Чтобы реализовать элементы ICalculator, просто вызовите соответствующие элементы экземпляра ICalc1Contract, которые передаются в конструктор, и возвратите результаты. Это адаптирует контракт (ICalc1Contract) к представлению (ICalculator).
В следующем коде показан завершенный адаптер на стороне основного приложения.
Imports System.AddIn.Pipeline Imports Calc1Contract.CalculatorContracts Imports Calc1HVA.CalcHVAs Namespace CalcHostSideAdapters ' The HostAdapterAttribute identifes this class as the host-side adapter ' pipeline segment. <HostAdapterAttribute()> _ Public Class CalculatorContractToViewHostSideAdapter Implements ICalculator Private _contract As ICalc1Contract Private _handle As System.AddIn.Pipeline.ContractHandle Public Sub New(ByVal contract As ICalc1Contract) MyBase.New() _contract = contract _handle = New ContractHandle(contract) End Sub Public Function Add(ByVal a As Double, ByVal b As Double) As Double _ Implements ICalculator.Add Return _contract.Add(a, b) End Function Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double _ Implements ICalculator.Subtract Return _contract.Subtract(a, b) End Function Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double _ Implements ICalculator.Multiply Return _contract.Multiply(a, b) End Function Public Function Divide(ByVal a As Double, ByVal b As Double) As Double _ Implements ICalculator.Divide Return _contract.Divide(a, b) End Function End Class End Namespace
using System.AddIn.Pipeline; using CalcHVAs; using CalculatorContracts; namespace CalcHostSideAdapters { // The HostAdapterAttribute identifes this class as the host-side adapter // pipeline segment. [HostAdapterAttribute()] public class CalculatorContractToViewHostSideAdapter : ICalculator { private ICalc1Contract _contract; private System.AddIn.Pipeline.ContractHandle _handle; public CalculatorContractToViewHostSideAdapter(ICalc1Contract contract) { _contract = contract; _handle = new ContractHandle(contract); } public double Add(double a, double b) { return _contract.Add(a, b); } public double Subtract(double a, double b) { return _contract.Subtract(a, b); } public double Multiply(double a, double b) { return _contract.Multiply(a, b); } public double Divide(double a, double b) { return _contract.Divide(a, b); } } }
При необходимости постройте решение Visual Studio.
Создание основного приложения
Основное приложение взаимодействует с надстройкой посредством представления основного приложения, относящегося к надстройке. При этом используются методы обнаружения и активации надстройки, которые предоставляются классами AddInStore и AddInToken для выполнения следующих действий:
Обновление кэша конвейера и сведений надстройки.
Обнаружение надстроек типа представления основного приложения ICalculator в указанном корневом каталоге конвейера.
Запрос пользователя на указание надстройки, которая должна быть использована.
Активация выбранной надстройки в новом домене приложения с выбранным уровнем доверия.
Выполнение пользовательского метода RunCalculator, который вызывает методы надстройки, как указано в представлении основного приложения, относящемся к надстройке.
Чтобы создать основное приложение
Добавление нового проекта с именем Calc1Host в решение CalculatorV1. Он должен быть основан на шаблоне Консольное приложение.
В обозревателе решений добавьте ссылку на сборку System.AddIn.dll в проект Calc1Host.
Добавьте ссылку проекта в проект Calc1HVA. Выберите ссылку проекта, затем в разделе Свойства задайте значение False для параметра Копировать локально. В Visual Basic используйте пункт Свойства проекта на вкладке Ссылки, чтобы задать для параметра Копировать локально значение False.
Переименуйте файл класса (модуль в Visual Basic) MathHost1.
В Visual Basic используйте вкладку Приложение диалогового окна Свойства проекта для задания значения Sub Main для параметра Автоматически запускаемый объект.
В классе или файле модуля добавьте ссылку на пространство имен к System.AddIn.Hosting.
В файле класса или модуля добавьте ссылку на пространства имен для представления основного приложения, относящегося к надстройке: CalcHVAs. (В Visual Basic этой ссылкой на пространство имен является Calc1HVA.CalcHVAs, если только не были отключены пространства имен по умолчанию в проектах Visual Basic.)
В Обозревателе решений выберите решение, затем в меню Проект выберите Свойства. В диалоговом окне Страницы свойств решения задайте Один запускаемый объект как этот проект основного приложения.
В файле класса или модуля используйте метод AddInStore.Update для обновления кэша. Используйте метод AddInStore.FindAddIn для получения коллекции маркеров, а также используйте метод AddInToken.Activate для активации надстройки.
В следующем коде показано завершение основного приложения.
Imports System.Collections.Generic Imports System.Collections.ObjectModel Imports System.AddIn.Hosting Imports Calc1HVA.CalcHVAs Namespace MathHost Module MathHost1 Sub Main() ' Assume that the current directory is the application folder, ' and that it contains the pipeline folder structure. Dim addInRoot As String = Environment.CurrentDirectory & "\Pipeline" ' Update the cache files of the pipeline segments and add-ins. Dim warnings() As String = AddInStore.Update(addInRoot) For Each warning As String In warnings Console.WriteLine(warning) Next ' Search for add-ins of type ICalculator (the host view of the add-in). Dim tokens As System.Collections.ObjectModel.Collection(Of AddInToken) = _ AddInStore.FindAddIns(GetType(ICalculator), addinRoot) ' Ask the user which add-in they would like to use. Dim calcToken As AddInToken = ChooseCalculator(tokens) ' Activate the selected AddInToken in a new application domain ' with the Internet trust level. Dim calc As ICalculator = _ calcToken.Activate(Of ICalculator)(AddInSecurityLevel.Internet) ' Run the add-in. RunCalculator(calc) 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 ICalculator) If IsNothing(calc) Then 'No calculators were found, read a line and exit. Console.ReadLine() End If Console.WriteLine("Available operations: +, -, *, /") Console.WriteLine("Request a calculation , such as: 2 + 2") Console.WriteLine("Type 'exit' to exit") Dim line As String = Console.ReadLine While Not line.Equals("exit") ' The Parser class parses the user's input. Try Dim c As Parser = New Parser(line) Select Case (c.action) Case "+" Console.WriteLine(calc.Add(c.a, c.b)) Case "-" Console.WriteLine(calc.Subtract(c.a, c.b)) Case "*" Console.WriteLine(calc.Multiply(c.a, c.b)) Case "/" Console.WriteLine(calc.Divide(c.a, c.b)) Case Else Console.WriteLine("{0} is an invalid command. Valid commands are +,-,*,/", c.action) End Select Catch Ex As System.Exception Console.WriteLine("Invalid command: {0}. Commands must be formated: [number] [operation] [number]", line) End Try line = Console.ReadLine End While End Sub End Module 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.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"; // Update the cache files of the pipeline segments and add-ins. string[] warnings = AddInStore.Update(addInRoot); foreach (string warning in warnings) { Console.WriteLine(warning); } // Search for add-ins of type ICalculator (the host view of the add-in). Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(ICalculator), 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. ICalculator calc = calcToken.Activate<ICalculator>(AddInSecurityLevel.Internet); // Run the add-in. RunCalculator(calc); } 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(ICalculator calc) { if (calc == null) { //No calculators were found; read a line and exit. Console.ReadLine(); } Console.WriteLine("Available operations: +, -, *, /"); Console.WriteLine("Request a calculation , such as: 2 + 2"); 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); switch (c.Action) { case "+": Console.WriteLine(calc.Add(c.A, c.B)); break; case "-": Console.WriteLine(calc.Subtract(c.A, c.B)); break; case "*": Console.WriteLine(calc.Multiply(c.A, c.B)); break; case "/": Console.WriteLine(calc.Divide(c.A, c.B)); break; default: Console.WriteLine("{0} is an invalid command. Valid commands are +,-,*,/", c.Action); break; } } catch { Console.WriteLine("Invalid command: {0}. Commands must be formated: [number] [operation] [number]", line); } line = Console.ReadLine(); } } } internal class Parser { double a; double b; string action; internal Parser(string line) { string[] parts = line.Split(' '); a = double.Parse(parts[0]); action = parts[1]; b = double.Parse(parts[2]); } public double A { get { return a; } } public double B { get { return b; } } public string Action { get { return action; } } } }
Примечание В этом коде предполагается, что структура папок конвейера расположена в папке приложения.Если эта структура расположена где-либо еще, измените строку кода, в которой задается переменная addInRoot, чтобы эта переменная содержала путь к структуре каталогов конвейера.
В коде используется метод ChooseCalculator для отображения списка маркеров и для запроса пользователя о выборе надстройки. В методе RunCalculator пользователь должен ввести простые математические выражения, затем они обрабатываются с помощью класса Parser, после чего надстройка возвращает результаты.
При необходимости постройте решение Visual Studio.
Создание надстройки
Надстройка реализует методы, указанные в представлении надстройки. Эта надстройка реализует операции Add, Subtract, Multiply и Divide, а затем возвращает результаты основному приложению.
Чтобы создать надстройку
Добавьте новый проект с названием AddInCalcV1 в решение CalculatorV1. Он должен быть основан на шаблоне Библиотека классов.
В Обозревателе решений добавьте в проект ссылку на сборку System.AddIn.dll.
Добавьте ссылку проекта к проекту Calc1AddInView. Выберите ссылку проекта, затем в разделе Свойства задайте значение False для параметра Копировать локально. В Visual Basic используйте вкладку Ссылки Свойств проекта для задания для параметра Копировать локально значение False для ссылки проекта.
Переименуйте класс AddInCalcV1.
В файле класса добавьте ссылку на пространство имен к System.AddIn, затем добавьте сегмент надстройки CalcAddInViews (Calc1AddInView.CalcAddInViews в Visual Basic).
Примените атрибут AddInAttribute к классу AddInCalcV1 для идентификации класса в качестве надстройки.
Класс AddInCalcV1 должен реализовывать интерфейс, который представляет представление надстройки: CalcAddInViews.ICalculator (Calc1AddInView.CalcAddInViews.ICalculator в Visual Basic).
Реализует элементы ICalculator посредством возвращения результатов соответствующих вычислений.
В следующем коде показано, как завершить надстройку.
Imports System.AddIn Imports Calc1AddInView.CalcAddInViews Namespace CalcAddIns ' The AddInAttribute identifies this pipeline segment as an add-in. <AddIn("Calculator AddIn", Version:="1.0.0.0")> _ Public Class AddInCalcV1 Implements ICalculator Public Function Add(ByVal a As Double, ByVal b As Double) As Double _ Implements ICalculator.Add Return (a + b) End Function Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double _ Implements ICalculator.Subtract Return (a - b) End Function Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double _ Implements ICalculator.Multiply Return (a * b) End Function Public Function Divide(ByVal a As Double, ByVal b As Double) As Double _ Implements ICalculator.Divide Return (a / b) End Function End Class End Namespace
using System.Collections.Generic; using System.AddIn; using CalcAddInViews; namespace CalcAddIns { // The AddInAttribute identifies this pipeline segment as an add-in. [AddIn("Calculator AddIn",Version="1.0.0.0")] public class AddInCalcV1 : ICalculator { public double Add(double a, double b) { return a + b; } public double Subtract(double a, double b) { return a - b; } public double Multiply(double a, double b) { return a * b; } public double Divide(double a, double b) { return a / b; } } }
При необходимости постройте решение Visual Studio.
Развертывание конвейера
Теперь можно создать и развернуть сегменты надстройки в требуемой структуре каталогов конвейера.
Чтобы развернуть сегменты в конвейере
Для каждого проекта в этом решении используйте вкладку Построение свойств проекта (вкладка Compile в Visual Basic) для установки значения Путь к выходным данным (Путь к выходным данным построения в Visual Basic). Если назвать папку приложения, например, MyApp, построение проектов будет осуществляться в следующих папках:
Проект
Путь
AddInCalcV1
MyApp\Pipeline\AddIns\CalcV1
Calc1AddInSideAdapter
MyApp\Pipeline\AddInSideAdapters
Calc1AddInView
MyApp\Pipeline\AddInViews
Calc1Contract
MyApp\Pipeline\Contracts
Calc1Host
MyApp
Calc1HostSideAdapter
MyApp\Pipeline\HostSideAdapters
Calc1HVA
MyApp
Примечание Если следует разместить структуру папок конвейера в месте, отличном от папки приложения, необходимо изменить соответствующим образом пути, приведенные в таблице.См. описание требований к каталогам конвейера в разделе Требования к разработке конвейера.
Создайте решение Visual Studio.
Проверьте каталоги приложения и конвейера, чтобы удостовериться в том, что сборки были скопированы в правильные каталоги и что в других папках не осталось дополнительных копий сборок.
Примечание Если для параметра Копировать локально не было задано значение False для ссылки проекта Calc1AddInView в проекте AddInCalcV1, контекстные проблемы загрузчика помешают нахождению надстройки.
Сведения о развертывании в конвейере см. в разделе Требования к разработке конвейера.
Запуск основного приложения
Теперь все готово к запуску основного приложения и взаимодействию с надстройкой.
Чтобы выполнить основное приложение
В командной строке перейдите в каталог приложения и запустите основное приложение Calc1Host.exe.
Основное приложение находит все доступные надстройки этого типа и запрашивает пользователя о выборе надстройки. Введите 1 для единственной доступной надстройки.
Введите формулу для калькулятора, например 2 + 2. Между цифрами и знаком должны быть пробелы.
Введите команду exit и нажмите клавишу ВВОД, чтобы закрыть приложение.
См. также
Задачи
Пошаговое руководство. Включение обратной совместимости при изменении основного приложения
Пошаговое руководство. Передача коллекций между основными приложениями и надстройками
Основные понятия
Требования к разработке конвейера