방법: 이중 계약 만들기

이 항목에서는 이중(양방향) 계약을 사용하는 메서드를 만드는 기본 단계를 보여 줍니다. 이중 계약을 사용하면 클라이언트와 서버가 각각 독립적으로 통신하므로 서로 호출을 시작할 수 있습니다. 이중 계약은 WCF(Windows Communication Foundation) 서비스에서 사용할 수 있는 세 가지 메시지 패턴 중 하나입니다. 다른 두 가지 메시지 패턴은 단방향 및 요청-회신입니다. 이중 계약은 클라이언트와 서버 간 두 개의 단방향 계약으로 구성되며, 메서드 호출을 상호 관련시키지 않아도 됩니다. 서비스가 클라이언트에 세부 정보를 쿼리하거나 클라이언트에서 이벤트를 명시적으로 발생시킬 때 이러한 종류의 계약을 사용합니다. 이중 계약을 위한 클라이언트 애플리케이션을 만드는 방법에 대한 자세한 내용은 방법: 이중 계약으로 서비스 액세스를 참조하세요. 작동하는 샘플은 이중 샘플을 참조하세요.

이중 계약을 만들려면

  1. 이중 계약의 서버 측을 구성하는 인터페이스를 만듭니다.

  2. 인터페이스에 ServiceContractAttribute 클래스를 적용합니다.

    [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required,
                     CallbackContract=typeof(ICalculatorDuplexCallback))]
    public interface ICalculatorDuplex
    {
        [OperationContract(IsOneWay=true)]
        void Clear();
        [OperationContract(IsOneWay = true)]
        void AddTo(double n);
        [OperationContract(IsOneWay = true)]
        void SubtractFrom(double n);
        [OperationContract(IsOneWay = true)]
        void MultiplyBy(double n);
        [OperationContract(IsOneWay = true)]
        void DivideBy(double n);
    }
    
    <ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples", SessionMode:=SessionMode.Required, _
                    CallbackContract:=GetType(ICalculatorDuplexCallback))> _
    Public Interface ICalculatorDuplex
    
        <OperationContract(IsOneWay:=True)> _
        Sub Clear()
        <OperationContract(IsOneWay:=True)> _
        Sub AddTo(ByVal n As Double)
        <OperationContract(IsOneWay:=True)> _
        Sub SubtractFrom(ByVal n As Double)
        <OperationContract(IsOneWay:=True)> _
        Sub MultiplyBy(ByVal n As Double)
        <OperationContract(IsOneWay:=True)> _
        Sub DivideBy(ByVal n As Double)
    End Interface
    
    
  3. 인터페이스에 메서드 서명을 선언합니다.

  4. 공용 계약의 일부여야 하는 각 메서드 서명에 OperationContractAttribute 클래스를 적용합니다.

  5. 서비스가 클라이언트에서 호출할 수 있는 작업 집합을 정의하는 콜백 인터페이스를 만듭니다.

    public interface ICalculatorDuplexCallback
    {
        [OperationContract(IsOneWay = true)]
        void Equals(double result);
        [OperationContract(IsOneWay = true)]
        void Equation(string eqn);
    }
    
    Public Interface ICalculatorDuplexCallback
        <OperationContract(IsOneWay:=True)> _
        Sub Equals(ByVal result As Double)
        <OperationContract(IsOneWay:=True)> _
        Sub Equation(ByVal eqn As String)
    end interface
    
    
  6. 콜백 인터페이스에 메서드 서명을 선언합니다.

  7. 공용 계약의 일부여야 하는 각 메서드 서명에 OperationContractAttribute 클래스를 적용합니다.

  8. 기본 인터페이스의 CallbackContract 속성을 콜백 인터페이스의 형식으로 설정하여 이중 계약에 두 개의 인터페이스를 연결합니다.

클라이언트에서 메서드를 호출하려면

  1. 기본 계약의 서비스 구현에서 콜백 인터페이스에 대한 변수를 선언합니다.

  2. 변수를 GetCallbackChannel 클래스의 OperationContext 메서드에서 반환한 개체 참조로 설정합니다.

    ICalculatorDuplexCallback callback = null;
    
    Dim callback As ICalculatorDuplexCallback
    
    callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
    
    callback = OperationContext.Current.GetCallbackChannel(Of ICalculatorDuplexCallback)()
    
  3. 콜백 인터페이스에서 정의한 메서드를 호출합니다.

예시

다음 코드 예제에서는 이중 통신을 수행하는 방법을 보여 줍니다. 서비스의 계약에는 앞뒤로 이동하기 위한 서비스 작업이 포함됩니다. 클라이언트의 계약에는 해당 위치를 보고하는 서비스 작업이 포함됩니다.

// Define a duplex service contract.
// A duplex contract consists of two interfaces.
// The primary interface is used to send messages from client to service.
// The callback interface is used to send messages from service back to client.
// ICalculatorDuplex allows one to perform multiple operations on a running result.
// The result is sent back after each operation on the ICalculatorCallback interface.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required,
                 CallbackContract=typeof(ICalculatorDuplexCallback))]
public interface ICalculatorDuplex
{
    [OperationContract(IsOneWay=true)]
    void Clear();
    [OperationContract(IsOneWay = true)]
    void AddTo(double n);
    [OperationContract(IsOneWay = true)]
    void SubtractFrom(double n);
    [OperationContract(IsOneWay = true)]
    void MultiplyBy(double n);
    [OperationContract(IsOneWay = true)]
    void DivideBy(double n);
}
// The callback interface is used to send messages from service back to client.
// The Equals operation will return the current result after each operation.
// The Equation operation will return the complete equation after Clear() is called.
public interface ICalculatorDuplexCallback
{
    [OperationContract(IsOneWay = true)]
    void Equals(double result);
    [OperationContract(IsOneWay = true)]
    void Equation(string eqn);
}
// Service class which implements a duplex service contract.
// Use an InstanceContextMode of PerSession to store the result
// An instance of the service will be bound to each duplex session
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class CalculatorService : ICalculatorDuplex
{
    double result;
    string equation;
    ICalculatorDuplexCallback callback = null;

    public CalculatorService()
    {
        result = 0.0D;
        equation = result.ToString();
        callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
    }

    public void Clear()
    {
        callback.Equation(equation + " = " + result.ToString());
        result = 0.0D;
        equation = result.ToString();
    }

    public void AddTo(double n)
    {
        result += n;
        equation += " + " + n.ToString();
        callback.Equals(result);
    }

    public void SubtractFrom(double n)
    {
        result -= n;
        equation += " - " + n.ToString();
        callback.Equals(result);
    }

    public void MultiplyBy(double n)
    {
        result *= n;
        equation += " * " + n.ToString();
        callback.Equals(result);
    }

    public void DivideBy(double n)
    {
        result /= n;
        equation += " / " + n.ToString();
        callback.Equals(result);
    }
}
' Define a duplex service contract.
' A duplex contract consists of two interfaces.
' The primary interface is used to send messages from client to service.
' The callback interface is used to send messages from service back to client.
' ICalculatorDuplex allows one to perform multiple operations on a running result.
' The result is sent back after each operation on the ICalculatorCallback interface.
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples", SessionMode:=SessionMode.Required, _
                CallbackContract:=GetType(ICalculatorDuplexCallback))> _
Public Interface ICalculatorDuplex

    <OperationContract(IsOneWay:=True)> _
    Sub Clear()
    <OperationContract(IsOneWay:=True)> _
    Sub AddTo(ByVal n As Double)
    <OperationContract(IsOneWay:=True)> _
    Sub SubtractFrom(ByVal n As Double)
    <OperationContract(IsOneWay:=True)> _
    Sub MultiplyBy(ByVal n As Double)
    <OperationContract(IsOneWay:=True)> _
    Sub DivideBy(ByVal n As Double)
End Interface

' The callback interface is used to send messages from service back to client.
' The Equals operation will return the current result after each operation.
' The Equation operation will return the complete equation after Clear() is called.
Public Interface ICalculatorDuplexCallback
    <OperationContract(IsOneWay:=True)> _
    Sub Equals(ByVal result As Double)
    <OperationContract(IsOneWay:=True)> _
    Sub Equation(ByVal eqn As String)
end interface

' Service class which implements a duplex service contract.
' Use an InstanceContextMode of PerSession to store the result
' An instance of the service will be bound to each duplex session
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession)> _
Public Class CalculatorService
    Implements ICalculatorDuplex
    Dim result As Double
    Dim equation As String
    Dim callback As ICalculatorDuplexCallback

    Public Sub New()
        result = 0D
        equation = result.ToString()
        callback = OperationContext.Current.GetCallbackChannel(Of ICalculatorDuplexCallback)()

    End Sub
    Public Sub AddTo(ByVal n As Double) Implements ICalculatorDuplex.AddTo
        result += n
        equation += " + " + n.ToString()
        callback.Equals(result)
    End Sub

    Public Sub Clear() Implements ICalculatorDuplex.Clear
        callback.Equation(equation + " = " + result.ToString())
        result = 0D
        equation = result.ToString()
    End Sub

    Public Sub DivideBy(ByVal n As Double) Implements ICalculatorDuplex.DivideBy
        result /= n
        equation += " / " + n.ToString()
        callback.Equals(result)
    End Sub

    Public Sub MultiplyBy(ByVal n As Double) Implements ICalculatorDuplex.MultiplyBy
        result *= n
        equation += " * " + n.ToString()
        callback.Equals(result)
    End Sub

    Public Sub SubtractFrom(ByVal n As Double) Implements ICalculatorDuplex.SubtractFrom
        result -= n
        equation += " - " + n.ToString()
        callback.Equals(result)
    End Sub
End Class
  • ServiceContractAttributeOperationContractAttribute 특성을 적용하면 WSDL(웹 서비스 기술 언어)에서 서비스 계약 정의를 자동으로 생성할 수 있습니다.

  • ServiceModel 메타데이터 유틸리티 도구(Svcutil.exe)를 사용하여 WSDL 문서와 코드(선택 사항) 및 클라이언트에 대한 구성을 검색합니다.

  • 이중 서비스를 노출하는 엔드포인트를 보호해야 합니다. 서비스가 이중 메시지를 받으면 들어오는 해당 메시지에서 ReplyTo를 확인하여 회신을 보낼 위치를 결정합니다. 채널이 보안되지 않으면 신뢰할 수 없는 클라이언트가 대상 컴퓨터의 ReplyTo를 사용하여 악의적인 메시지를 보낼 수 있으므로 해당 대상 컴퓨터의 서비스 거부가 발생할 수 있습니다. 정규 요청-회신 메시지를 사용하는 경우에는 ReplyTo가 무시되고 원래 메시지가 들어온 채널에서 응답이 보내지므로 이러한 문제가 생기지 않습니다.

참고 항목