방법: 이중 계약 만들기
이 항목에서는 이중(양방향) 계약을 사용하는 메서드를 만드는 기본 단계를 보여 줍니다. 이중 계약을 사용하면 클라이언트와 서버가 각각 독립적으로 통신하므로 서로 호출을 시작할 수 있습니다. 이중 계약은 WCF(Windows Communication Foundation) 서비스에서 사용할 수 있는 세 가지 메시지 패턴 중 하나입니다. 다른 두 가지 메시지 패턴은 단방향 및 요청-회신입니다. 이중 계약은 클라이언트와 서버 간 두 개의 단방향 계약으로 구성되며, 메서드 호출을 상호 관련시키지 않아도 됩니다. 서비스가 클라이언트에 세부 정보를 쿼리하거나 클라이언트에서 이벤트를 명시적으로 발생시킬 때 이러한 종류의 계약을 사용합니다. 이중 계약을 위한 클라이언트 애플리케이션을 만드는 방법에 대한 자세한 내용은 방법: 이중 계약으로 서비스 액세스를 참조하세요. 작동하는 샘플은 이중 샘플을 참조하세요.
이중 계약을 만들려면
이중 계약의 서버 측을 구성하는 인터페이스를 만듭니다.
인터페이스에 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
인터페이스에 메서드 서명을 선언합니다.
공용 계약의 일부여야 하는 각 메서드 서명에 OperationContractAttribute 클래스를 적용합니다.
서비스가 클라이언트에서 호출할 수 있는 작업 집합을 정의하는 콜백 인터페이스를 만듭니다.
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
콜백 인터페이스에 메서드 서명을 선언합니다.
공용 계약의 일부여야 하는 각 메서드 서명에 OperationContractAttribute 클래스를 적용합니다.
기본 인터페이스의 CallbackContract 속성을 콜백 인터페이스의 형식으로 설정하여 이중 계약에 두 개의 인터페이스를 연결합니다.
클라이언트에서 메서드를 호출하려면
기본 계약의 서비스 구현에서 콜백 인터페이스에 대한 변수를 선언합니다.
변수를 GetCallbackChannel 클래스의 OperationContext 메서드에서 반환한 개체 참조로 설정합니다.
ICalculatorDuplexCallback callback = null;
Dim callback As ICalculatorDuplexCallback
callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
callback = OperationContext.Current.GetCallbackChannel(Of ICalculatorDuplexCallback)()
콜백 인터페이스에서 정의한 메서드를 호출합니다.
예시
다음 코드 예제에서는 이중 통신을 수행하는 방법을 보여 줍니다. 서비스의 계약에는 앞뒤로 이동하기 위한 서비스 작업이 포함됩니다. 클라이언트의 계약에는 해당 위치를 보고하는 서비스 작업이 포함됩니다.
// 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
ServiceContractAttribute 및 OperationContractAttribute 특성을 적용하면 WSDL(웹 서비스 기술 언어)에서 서비스 계약 정의를 자동으로 생성할 수 있습니다.
ServiceModel 메타데이터 유틸리티 도구(Svcutil.exe)를 사용하여 WSDL 문서와 코드(선택 사항) 및 클라이언트에 대한 구성을 검색합니다.
이중 서비스를 노출하는 엔드포인트를 보호해야 합니다. 서비스가 이중 메시지를 받으면 들어오는 해당 메시지에서 ReplyTo를 확인하여 회신을 보낼 위치를 결정합니다. 채널이 보안되지 않으면 신뢰할 수 없는 클라이언트가 대상 컴퓨터의 ReplyTo를 사용하여 악의적인 메시지를 보낼 수 있으므로 해당 대상 컴퓨터의 서비스 거부가 발생할 수 있습니다. 정규 요청-회신 메시지를 사용하는 경우에는 ReplyTo가 무시되고 원래 메시지가 들어온 채널에서 응답이 보내지므로 이러한 문제가 생기지 않습니다.