Share via


연습: 확장 가능한 응용 프로그램 만들기

이 연습에서는 단순한 계산기 기능을 수행하는 추가 기능에 대해 파이프라인을 만드는 방법을 설명합니다. 실제 시나리오를 보여 주는 대신 파이프라인의 기본 기능과 추가 기능이 호스트에 서비스를 제공하는 방법을 보여 줍니다.

이 연습에서는 다음 작업에 대해 설명합니다.

  • Visual Studio 솔루션 만들기

  • 파이프라인 디렉터리 구조 만들기

  • 계약 및 뷰 만들기

  • 추가 기능측 어댑터 만들기

  • 호스트측 어댑터 만들기

  • 호스트 만들기

  • 추가 기능 만들기

  • 파이프라인 배포

  • 호스트 응용 프로그램 실행

이 파이프라인은 호스트와 추가 기능 간에 serializable 형식(DoubleString)만 전달합니다. 복잡한 데이터 형식 컬렉션을 전달하는 방법을 보여 주는 예제는 연습: 호스트와 추가 기능 간의 컬렉션 전달을 참조하십시오.

이 파이프라인에 대한 계약은 네 가지 산술 연산인 더하기, 빼기, 곱하기, 나누기의 개체 모델을 정의합니다. 호스트는 추가 기능에 2 + 2와 같은 계산 수식을 제공하고 추가 기능은 그 결과를 호스트에 반환합니다.

계산기 추가 기능의 버전 2에서는 추가 계산 기능을 제공하고 버전 관리를 보여 줍니다. 이에 대한 내용은 연습: 호스트 변경으로 인한 이전 버전과의 호환성 활성화에서 설명합니다.

참고참고

추가 코드 샘플을 얻고 추가 기능 파이프라인 개발용 도구에 대한 고객 기술을 미리 보려면 CodePlex의 Managed Extensibility and Add-In Framework 사이트를 참조하십시오.

사전 요구 사항

이 연습을 진행하려면 먼저 다음 작업을 수행해야 합니다.

  • Visual Studio.

Visual Studio 솔루션 만들기

Visual Studio의 솔루션을 사용하여 파이프라인 세그먼트의 프로젝트를 포함할 수 있습니다.

파이프라인 솔루션을 만들려면

  1. Visual Studio에서 Calc1Contract라는 새 프로젝트를 만듭니다. 클래스 라이브러리 템플릿을 기반으로 합니다.

  2. 솔루션 이름을 CalculatorV1로 지정합니다.

파이프라인 디렉터리 구조 만들기

추가 기능 모델에서는 파이프라인 세그먼트 어셈블리를 지정한 디렉터리 구조에 넣어야 합니다. 파이프라인 구조에 대한 자세한 내용은 파이프라인 개발 요구 사항을 참조하십시오.

파이프라인 디렉터리 구조를 만들려면

  1. 컴퓨터에서 원하는 위치에 응용 프로그램 폴더를 만듭니다.

  2. 이 폴더 내에 다음과 같은 구조를 만듭니다.

    Pipeline
      AddIns
        CalcV1
        CalcV2
      AddInSideAdapters
      AddInViews
      Contracts
      HostSideAdapters
    

    여기에서는 편의를 위해 응용 프로그램 폴더 내에 파이프라인 폴더 구조를 넣었지만 반드시 그렇게 할 필요는 없습니다. 이 연습에서는 파이프라인 폴더 구조가 다른 위치에 포함되어 있는 경우 코드를 변경하는 방법을 설명하는 단계를 제공합니다. 파이프라인 개발 요구 사항의 파이프라인 디렉터리 요구 사항에 대한 설명을 참조하십시오.

    참고참고

    CalcV2 폴더는 연습: 호스트 변경으로 인한 이전 버전과의 호환성 활성화의 자리 표시자이며 이 연습에서 사용되지 않습니다.

계약 및 뷰 만들기

이 파이프라인의 계약 세그먼트는 4개의 메서드(add, subtract, multiply 및 divide)를 정의하는 ICalc1Contract 인터페이스를 정의합니다.

계약을 만들려면

  1. CalculatorV1이라는 Visual Studio 솔루션에서 Calc1Contract 프로젝트를 엽니다.

  2. 솔루션 탐색기에서 다음 어셈블리에 대한 참조를 Calc1Contract 프로젝트에 추가합니다.

    System.AddIn.Contract.dll

    System.AddIn.dll

  3. 솔루션 탐색기에서 새 클래스 라이브러리 프로젝트에 추가되는 기본 클래스를 제외합니다.

  4. 솔루션 탐색기에서 인터페이스 템플릿을 사용하여 프로젝트에 새 항목을 추가합니다. 이때 새 항목 추가 대화 상자가 나타나면 인터페이스 이름을 ICalc1Contract로 지정합니다.

  5. 인터페이스 파일에서 System.AddIn.ContractSystem.AddIn.Pipeline에 대한 네임스페이스 참조를 추가합니다.

  6. 다음 코드를 사용하여 이 계약 세그먼트를 완료합니다. 이 인터페이스에는 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);
        }
    }
    
  7. 필요한 경우 Visual Studio 솔루션을 빌드합니다. 마지막 단계를 완료할 때까지 솔루션을 실행할 수는 없지만 단계가 끝날 때마다 솔루션을 빌드하면 각 프로젝트를 오류 없이 정확하게 만들 수 있습니다.

추가 기능의 첫 번째 버전의 경우에는 특히 추가 기능 뷰와 추가 기능 호스트 뷰의 코드가 같으므로 간단한 방법으로 동시에 뷰를 만들 수 있습니다. 단, 추가 기능 뷰에는 AddInBaseAttribute 특성이 필요하고 추가 기능 호스트 뷰에는 특성이 필요하지 않다는 차이점이 있습니다.

추가 기능 뷰를 만들려면

  1. Calc1AddInView라는 새 프로젝트를 CalculatorV1 솔루션에 추가합니다. 클래스 라이브러리 템플릿을 기반으로 합니다.

  2. 솔루션 탐색기에서 System.AddIn.dll에 대한 참조를 Calc1AddInView 프로젝트에 추가합니다.

  3. 솔루션 탐색기에서 새 클래스 라이브러리 프로젝트에 추가되는 기본 클래스를 제외하고 인터페이스 템플릿을 사용하여 프로젝트에 새 항목을 추가합니다. 이때 새 항목 추가 대화 상자가 나타나면 인터페이스 이름을 ICalculator로 지정합니다.

  4. 인터페이스 파일에서 System.AddIn.Pipeline에 대한 네임스페이스 참조를 추가합니다.

  5. 다음 코드를 사용하여 이 추가 기능 뷰를 완료합니다. 이 인터페이스에는 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);
        }
    }
    
  6. 필요한 경우 Visual Studio 솔루션을 빌드합니다.

추가 기능의 호스트 뷰를 만들려면

  1. Calc1HVA라는 새 프로젝트를 CalculatorV1 솔루션에 추가합니다. 클래스 라이브러리 템플릿을 기반으로 합니다.

  2. 솔루션 탐색기에서 새 클래스 라이브러리 프로젝트에 추가되는 기본 클래스를 제외하고 인터페이스 템플릿을 사용하여 프로젝트에 새 항목을 추가합니다. 이때 새 항목 추가 대화 상자가 나타나면 인터페이스 이름을 ICalculator로 지정합니다.

  3. 인터페이스 파일에서 다음 코드를 사용하여 추가 기능 호스트 뷰를 완료합니다.

    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);
        }
    }
    
  4. 필요한 경우 Visual Studio 솔루션을 빌드합니다.

추가 기능측 어댑터 만들기

이 추가 기능측 어댑터는 뷰에서 계약으로 변환하는 하나의 어댑터로 구성되어 있습니다. 이 파이프라인 세그먼트는 추가 기능 뷰의 형식을 계약으로 변환합니다.

이 파이프라인에서 추가 기능은 호스트에 서비스를 제공하고 형식은 추가 기능에서 호스트로 흐릅니다. 형식은 호스트에서 추가 기능으로 흐르지 않으므로 이 파이프라인의 추가 기능측에 계약에서 뷰로 변환하는 어댑터를 포함할 필요가 없습니다.

추가 기능측 어댑터를 만들려면

  1. Calc1AddInSideAdapter라는 새 프로젝트를 CalculatorV1 솔루션에 추가합니다. 클래스 라이브러리 템플릿을 기반으로 합니다.

  2. 솔루션 탐색기에서 다음 어셈블리에 대한 참조를 Calc1AddInSideAdapter 프로젝트에 추가합니다.

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 인접한 파이프라인 세그먼트의 프로젝트에 프로젝트 참조를 추가합니다.

    Calc1AddInView

    Calc1Contract

  4. 각 프로젝트 참조를 선택한 다음 속성에서 로컬 복사False로 설정합니다. Visual Basic에서는 프로젝트 속성참조 탭을 사용하여 두 프로젝트 참조의 로컬 복사 값을 False로 설정합니다.

  5. 프로젝트의 기본 클래스인 CalculatorViewToContractAddInSideAdapter의 이름을 바꿉니다.

  6. 클래스 파일에서 System.AddIn.Pipeline에 대한 네임스페이스 참조를 추가합니다.

  7. 클래스 파일에서 인접 세그먼트에 대한 네임스페이스 참조 CalcAddInViews 및 CalculatorContracts를 추가합니다. Visual Basic의 경우 Visual Basic 프로젝트에서 기본 네임스페이스를 해제하지 않았으면 이러한 네임스페이스 참조는 Calc1AddInView.CalcAddInViews 및 Calc1Contract.CalculatorContracts입니다.

  8. CalculatorViewToContractAddInSideAdapter 클래스에 AddInAdapterAttribute 특성을 적용하여 이 클래스를 추가 기능측 어댑터로 식별합니다.

  9. IContract 인터페이스의 기본 구현을 제공하는 ContractBase를 상속하도록 CalculatorViewToContractAddInSideAdapter 클래스를 설정하고 파이프라인의 계약 인터페이스 ICalc1Contract를 구현합니다.

  10. ICalculator를 사용하는 공용 생성자를 추가하여 전용 필드에 캐시하고 기본 클래스 생성자를 호출합니다.

  11. ICalc1Contract의 멤버를 구현하려면 생성자에 전달되는 ICalculator 인스턴스의 해당 멤버를 호출하고 결과를 반환하면 됩니다. 이렇게 하면 계약(ICalc1Contract)에 맞게 뷰(ICalculator)가 변경됩니다.

    다음 코드에서는 완성된 추가 기능측 어댑터를 보여 줍니다.

    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);
            }
        }
    }
    
  12. 필요한 경우 Visual Studio 솔루션을 빌드합니다.

호스트측 어댑터 만들기

이 호스트측 어댑터는 계약에서 뷰로 변환하는 하나의 어댑터로 구성되어 있습니다. 이 세그먼트는 추가 기능의 호스트 뷰에 맞게 계약을 변경합니다.

이 파이프라인에서 추가 기능은 호스트에 서비스를 제공하고 형식은 추가 기능에서 호스트로 흐릅니다. 형식은 호스트에서 추가 기능으로 흐르지 않으므로 뷰에서 계약으로 변환하는 어댑터를 포함할 필요가 없습니다.

수명 관리를 구현하려면 ContractHandle 개체를 사용하여 계약에 수명 토큰을 연결합니다. 이 핸들에 대한 참조를 유지해야 수명 관리가 정상적으로 작동합니다. 추가 기능 시스템에서 더 이상 사용되지 않는 개체를 삭제하고 가비지 수집에 사용 가능하도록 설정할 수 있으므로 토큰이 적용된 후 추가 프로그래밍이 필요하지 않습니다. 자세한 내용은 수명 관리를 참조하십시오.

호스트측 어댑터를 만들려면

  1. Calc1HostSideAdapter라는 새 프로젝트를 CalculatorV1 솔루션에 추가합니다. 클래스 라이브러리 템플릿을 기반으로 합니다.

  2. 솔루션 탐색기에서 다음 어셈블리에 대한 참조를 Calc1HostSideAdapter 프로젝트에 추가합니다.

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 인접 세그먼트의 프로젝트에 프로젝트 참조를 추가합니다.

    Calc1Contract

    Calc1HVA

  4. 각 프로젝트 참조를 선택한 다음 속성에서 로컬 복사False로 설정합니다. Visual Basic에서는 프로젝트 속성참조 탭을 사용하여 두 프로젝트 참조의 로컬 복사 값을 False로 설정합니다.

  5. 프로젝트의 기본 클래스인 CalculatorContractToViewHostSideAdapter의 이름을 바꿉니다.

  6. 클래스 파일에서 System.AddIn.Pipeline에 대한 네임스페이스 참조를 추가합니다.

  7. 클래스 파일에서 인접 세그먼트에 대한 네임스페이스 참조 CalcHVAs 및 CalculatorContracts를 추가합니다. Visual Basic의 경우 Visual Basic 프로젝트에서 기본 네임스페이스를 해제하지 않았으면 이러한 네임스페이스 참조는 Calc1HVA.CalcHVAs 및 Calc1Contract.CalculatorContracts입니다.

  8. CalculatorContractToViewHostSideAdapter 클래스에 HostAdapterAttribute 특성을 적용하여 이 클래스를 호스트측 어댑터 세그먼트로 식별합니다.

  9. 추가 기능의 호스트 뷰를 나타내는 인터페이스인 Calc1HVAs.ICalculator(Visual Basic의 경우 Calc1HVA.CalcHVAs.ICalculator)를 구현하도록 CalculatorContractToViewHostSideAdapter 클래스를 설정합니다.

  10. 파이프라인 계약 형식(ICalc1Contract)을 사용하는 공용 생성자를 추가합니다. 이 생성자는 계약에 대한 참조를 캐시해야 합니다. 또한 계약에 대해 새 ContractHandle을 만들고 캐시하여 추가 기능의 수명을 관리해야 합니다.

    중요중요

    ContractHandle은 수명 관리에 필수적입니다.ContractHandle 개체에 대한 참조를 유지하지 못하는 경우 가비지 수집을 통해 이를 회수하게 되며 프로그램에서 더 이상 필요로 하지 않는 파이프라인은 종료됩니다.이로 인해 AppDomainUnloadedException 같이 진단하기 어려운 오류가 발생할 수 있습니다.종료는 파이프라인 수명의 정상적인 단계이므로 수명 관리 코드에서 이 상태가 오류인지 여부를 감지할 수는 없습니다.

  11. ICalculator의 멤버를 구현하려면 생성자에 전달되는 ICalc1Contract 인스턴스의 해당 멤버를 호출하고 결과를 반환하면 됩니다. 이렇게 하면 뷰(ICalculator)에 맞게 계약(ICalc1Contract)이 변경됩니다.

    다음 코드에서는 완성된 호스트측 어댑터를 보여 줍니다.

    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);
            }
        }
    }
    
  12. 필요한 경우 Visual Studio 솔루션을 빌드합니다.

호스트 만들기

호스트 응용 프로그램은 추가 기능의 호스트 뷰를 통해 추가 기능과 상호 작용합니다. AddInStoreAddInToken 클래스에서 제공하는 추가 기능 검색 및 활성화 메서드를 사용하여 다음을 수행합니다.

  • 파이프라인 및 추가 기능 정보의 캐시를 업데이트합니다.

  • 지정한 파이프라인 루트 디렉터리에서 호스트 뷰 형식 ICalculator의 추가 기능을 찾습니다.

  • 사용할 추가 기능을 지정하라는 메시지를 사용자에게 표시합니다.

  • 새 응용 프로그램 도메인에서 지정된 보안 신뢰 수준으로 선택한 추가 기능을 활성화합니다.

  • 추가 기능의 호스트 뷰에서 지정한 대로 추가 기능의 메서드를 호출하는 사용자 지정 RunCalculator 메서드를 실행합니다.

호스트를 만들려면

  1. Calc1Host라는 새 프로젝트를 CalculatorV1 솔루션에 추가합니다. 콘솔 응용 프로그램 템플릿을 기반으로 합니다.

  2. 솔루션 탐색기에서 System.AddIn.dll 어셈블리에 대한 참조를 Calc1Host 프로젝트에 추가합니다.

  3. 프로젝트 참조를 Calc1HVA 프로젝트에 추가합니다. 프로젝트 참조를 선택한 다음 속성에서 로컬 복사False로 설정합니다. Visual Basic에서는 프로젝트 속성참조 탭을 사용하여 로컬 복사 값을 False로 설정합니다.

  4. 클래스 파일(Visual Basic의 경우 모듈) MathHost1의 이름을 바꿉니다.

  5. Visual Basic에서 프로젝트 속성 대화 상자의 응용 프로그램 탭을 사용하여 시작 개체Sub Main으로 설정합니다.

  6. 클래스 또는 모듈 파일에서 System.AddIn.Hosting에 대한 네임스페이스 참조를 추가합니다.

  7. 클래스 또는 모듈 파일에서 추가 기능의 호스트 뷰에 대한 네임스페이스 참조인 CalcHVAs를 추가합니다. Visual Basic의 경우 Visual Basic 프로젝트에서 기본 네임스페이스를 해제하지 않았으면 이 네임스페이스 참조는 Calc1HVA.CalcHVAs입니다.

  8. 솔루션 탐색기에서 솔루션을 선택하고 프로젝트 메뉴에서 속성을 선택합니다. 솔루션 속성 페이지 대화 상자에서 한 개의 시작 프로젝트를 이 호스트 응용 프로그램 프로젝트로 설정합니다.

  9. 클래스 또는 모듈 파일에서 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 클래스를 사용하여 식을 구문 분석하고, 추가 기능에서 반환하는 결과를 표시합니다.

  10. 필요한 경우 Visual Studio 솔루션을 빌드합니다.

추가 기능 만들기

추가 기능은 추가 기능 뷰에서 지정한 메서드를 구현합니다. 이 추가 기능은 Add, Subtract, Multiply 및 Divide 연산을 구현하고 그 결과를 호스트에 반환합니다.

추가 기능을 만들려면

  1. AddInCalcV1이라는 새 프로젝트를 CalculatorV1 솔루션에 추가합니다. 클래스 라이브러리 템플릿을 기반으로 합니다.

  2. 솔루션 탐색기에서 System.AddIn.dll 어셈블리에 대한 참조를 프로젝트에 추가합니다.

  3. Calc1AddInView 프로젝트에 프로젝트 참조를 추가합니다. 프로젝트 참조를 선택한 다음 속성에서 로컬 복사False로 설정합니다. Visual Basic에서는 프로젝트 속성참조 탭을 사용하여 프로젝트 참조의 로컬 복사 값을 False로 설정합니다.

  4. AddInCalcV1 클래스의 이름을 바꿉니다.

  5. 클래스 파일에서 System.AddIn 및 추가 기능 뷰 세그먼트에 대한 네임스페이스 참조인 CalcAddInViews(Visual Basic의 경우 Calc1AddInView.CalcAddInViews)를 추가합니다.

  6. AddInCalcV1 클래스에 AddInAttribute 특성을 적용하여 이 클래스를 추가 기능으로 식별합니다.

  7. 추가 기능 뷰를 나타내는 인터페이스인 CalcAddInViews.ICalculator(Visual Basic의 경우 Calc1AddInView.CalcAddInViews.ICalculator)를 구현하도록 AddInCalcV1 클래스를 설정합니다.

  8. 해당 계산 결과를 반환하여 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;
            }
        }
    }
    
  9. 필요한 경우 Visual Studio 솔루션을 빌드합니다.

파이프라인 배포

이제 추가 기능 세그먼트를 빌드하고 필요한 파이프라인 디렉터리 구조에 배포할 준비가 되었습니다.

세그먼트를 파이프라인에 배포하려면

  1. 솔루션의 각 프로젝트에 대해 프로젝트 속성빌드 탭(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

    참고참고

    파이프라인 폴더 구조를 응용 프로그램 폴더 이외의 다른 위치에 추가하려면 이 표에 제공된 경로를 적절하게 수정해야 합니다.파이프라인 개발 요구 사항의 파이프라인 디렉터리 요구 사항에 대한 설명을 참조하십시오.

  2. Visual Studio 솔루션을 빌드합니다.

  3. 응용 프로그램 디렉터리 및 파이프라인 디렉터리를 검사하여 어셈블리가 올바른 디렉터리에 복사되었는지 그리고 잘못된 폴더에 추가 어셈블리 복사본이 설치되어 있지 않은지 확인합니다.

    참고참고

    AddInCalcV1 프로젝트에서 Calc1AddInView 프로젝트 참조에 대해 로컬 복사False로 변경하지 않은 경우에는 로더 컨텍스트 문제가 발생하여 추가 기능을 찾을 수 없게 됩니다.

    파이프라인에 배포하는 방법에 대한 자세한 내용은 파이프라인 개발 요구 사항을 참조하십시오.

호스트 응용 프로그램 실행

이제 호스트를 실행하고 추가 기능과 상호 작용할 준비가 되었습니다.

호스트 응용 프로그램을 실행하려면

  1. 명령 프롬프트에서 응용 프로그램 디렉터리로 이동하여 호스트 응용 프로그램 Calc1Host.exe를 실행합니다.

  2. 호스트는 해당 형식의 사용 가능한 모든 추가 기능을 찾고 추가 기능을 선택하라는 메시지를 표시합니다. 사용 가능한 추가 기능이 하나뿐이면 1을 입력합니다.

  3. 계산기의 수식을 입력합니다(예: 2 + 2). 숫자와 연산자 사이에 공백이 있어야 합니다.

  4. exit을 입력하고 Enter 키를 눌러 응용 프로그램을 닫습니다.

참고 항목

작업

연습: 호스트 변경으로 인한 이전 버전과의 호환성 활성화

연습: 호스트와 추가 기능 간의 컬렉션 전달

개념

파이프라인 개발 요구 사항

계약, 뷰 및 어댑터

파이프라인 개발