끝점 주소 지정
WCF(Windows Communication Foundation) 서비스와의 모든 통신은 해당 통신의 끝점을 통해 수행됩니다. 각 ServiceEndpoint에는 Address, Binding 및 Contract가 포함되어 있습니다. 계약은 사용할 수 있는 작업을 지정합니다. 바인딩은 서비스와 통신하는 방법을 지정하고 주소는 서비스를 찾을 위치를 지정합니다. 모든 끝점에는 고유한 주소가 있어야 합니다. 끝점 주소는 서비스 주소를 표시하는 URI(Uniform Resource Identifier)가 포함된 EndpointAddress 클래스, 서비스의 보안 ID를 표시하는 Identity 및 선택적 Headers의 컬렉션에 의해 표시됩니다. 선택적 헤더는 끝점을 확인하거나 상호 작용하는 데 필요한 자세한 주소 지정 정보를 제공합니다. 예를 들어 헤더는 들어오는 메시지를 처리하는 방법, 끝점이 회신 메시지를 보내야 하는 위치 또는 여러 인스턴스를 사용할 수 있는 경우 특정 사용자의 들어오는 메시지를 처리하는 데 사용할 서비스 인스턴스를 나타낼 수 있습니다.
끝점 주소 정의
WCF에서 EndpointAddress는 WS-Addressing 표준에 정의된 대로 끝점 참조(EPR)를 모델링합니다.
대부분 전송 주소 URI에는 네 가지 부분이 있습니다. 예를 들어 URI "http://www.fabrikam.com:322/mathservice.svc/secureEndpoint"에는 다음과 같이 네 개 부분이 포함됩니다.
스키마: http:
시스템: www.fabrikam.com
(선택적) 포트: 322
경로: /mathservice.svc/secureEndpoint
EPR 모델 일부에서는 각 끝점 참조에 추가 식별 정보를 추가하는 일부 참조 매개 변수를 포함할 수 있습니다. WCF에서 이러한 참조 매개 변수는 AddressHeader 클래스의 인스턴스로 모델링됩니다.
서비스의 끝점 주소는 코드를 사용하여 명령적으로 지정하거나 구성을 통해 선언적으로 지정할 수 있습니다. 일반적으로 배포된 서비스의 바인딩과 주소가 서비스를 배포할 때 사용된 바인딩 및 주소와 다르기 때문에 코드로 끝점을 정의하는 것은 효과적이지 않습니다. 일반적으로 코드 대신 구성을 사용하여 서비스 끝점을 정의하는 것이 좋습니다. 바인딩 및 주소 지정 정보를 코드와 구분하면 응용 프로그램을 다시 컴파일하여 재배포할 필요 없이 해당 정보를 변경할 수 있습니다. 코드 또는 구성에서 끝점을 지정하지 않으면 런타임이 서비스에서 구현되는 각 계약의 각 기본 주소에 대해 기본 끝점을 하나씩 추가합니다.
WCF에서 서비스의 대한 끝점 주소를 지정하기 위한 두 가지 방법이 있습니다. 서비스와 연결된 각 끝점에 대한 절대 주소를 지정하거나 서비스의 ServiceHost에 대한 기본 주소를 제공할 수 있으며 그런 다음 이 기본 주소를 기준으로 정의된 이 서비스와 연결된 각 끝점에 대한 주소를 지정할 수 있습니다. 이러한 각 절차를 사용하여 구성 또는 코드에서 서비스에 대한 끝점 주소를 지정할 수 있습니다. 상대 주소를 지정하지 않을 경우 서비스는 기본 주소를 사용합니다. 또한 하나의 서비스에 대해 여러 기본 주소를 사용할 수 있지만 각 서비스는 각 전송에 대해 하나의 기본 주소만 허용됩니다. 여러 끝점을 가진 경우 각 끝점은 서로 다른 바인딩으로 구성되며 해당 주소가 고유해야 합니다. 동일한 바인딩을 사용하지만 서로 다른 계약을 사용하는 끝점은 동일한 주소를 사용할 수 있습니다.
IIS를 사용하여 호스팅하는 경우 사용자는 ServiceHost 인스턴스를 직접 관리하지 않습니다. IIS에서 호스팅하는 경우 기본 주소는 항상 서비스의 .svc 파일에 지정된 주소입니다. 따라서 IIS에서 호스팅되는 서비스 끝점에는 상대 끝점 주소를 사용해야 합니다. 정규화된 끝점 주소를 제공할 경우 서비스 배포 시 오류가 발생할 수 있습니다. 자세한 내용은 다음 항목을 참조하십시오. 인터넷 정보 서비스에서 호스팅하는 WCF 서비스 배포.
구성에서 끝점 주소 정의
구성 파일에 끝점을 정의하려면 <endpoint> 요소를 사용합니다.
<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
<endpoint address="/Address1"
binding="basicHttpBinding"
contract="UE.Samples.IHello"/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Open 메서드를 호출하는 경우(즉, 호스팅 응용 프로그램이 서비스를 시작하려고 시도하는 경우) 시스템은 "UE.Samples.HelloService"를 지정하는 이름 특성을 가진 <service> 요소를 검색합니다. <service> 요소를 찾은 경우 시스템은 지정된 클래스를 로드하고 구성 파일에서 제공된 끝점 정의를 사용하여 끝점을 만듭니다. 이 메커니즘을 통해 두 개의 코드 줄에서 서비스를 로드하고 시작하는 동시에 해당 코드의 바인딩 및 주소 지정 정보를 유지할 수 있습니다. 이 접근 방식의 이점은 응용 프로그램을 다시 컴파일하거나 다시 배포할 필요 없이 이러한 변경 작업을 수행할 수 있다는 점입니다.
선택적 헤더는 <headers> element에서 선언됩니다. 다음은 두 가지 헤더(예: http://tempuri1.org/의 "Gold" 클라이언트 및 http://tempuri2.org/의 "Standard" 클라이언트) 간에 구분되는 구성 파일의 서비스에 대한 끝점을 지정하는 데 사용되는 요소의 예제입니다. 이 서비스를 호출하는 클라이언트의 구성 파일에는 적절한 <headers> element가 있어야 합니다.
<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
<endpoint address="/Address1"
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<headers>
<Member xmlns="http://tempuri1.org/">Gold</Member>
</headers>
</endpoint>
<endpoint address="/Address2"
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<headers>
<Member xmlns="http://tempuri2.org/">Silver</Member>
</headers>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
또한 헤더는 이전에 설명한 것처럼 끝점의 모든 메시지 대신 개별 메시지에서 설정될 수 있습니다. 이 작업은 다음 예제에서처럼 보내는 메시지에 사용자 지정 헤더를 추가하기 위해 OperationContextScope를 사용하여 클라이언트 응용 프로그램에서 새 컨텍스트를 만들어 수행합니다.
Dim wcfClient As New SampleServiceClient(New InstanceContext(Me))
Try
Using scope As New OperationContextScope(wcfClient.InnerChannel)
Dim header As MessageHeader = MessageHeader.CreateHeader("Service-Bound-CustomHeader", _
"http://Microsoft.WCF.Documentation", "Custom Happy Value.")
OperationContext.Current.OutgoingMessageHeaders.Add(header)
' Making calls.
Console.WriteLine("Enter the greeting to send: ")
Dim greeting As String = Console.ReadLine()
'Console.ReadLine();
header = MessageHeader.CreateHeader("Service-Bound-OneWayHeader", _
"http://Microsoft.WCF.Documentation", "Different Happy Value.")
OperationContext.Current.OutgoingMessageHeaders.Add(header)
' One-way
wcfClient.Push(greeting)
Me.wait.WaitOne()
' Done with service.
wcfClient.Close()
Console.WriteLine("Done!")
Console.ReadLine()
End Using
Catch timeProblem As TimeoutException
Console.WriteLine("The service operation timed out. " & timeProblem.Message)
Console.ReadLine()
wcfClient.Abort()
Catch commProblem As CommunicationException
Console.WriteLine("There was a communication problem. " & commProblem.Message)
Console.ReadLine()
wcfClient.Abort()
End Try
SampleServiceClient wcfClient = new SampleServiceClient(new InstanceContext(this));
try
{
using (OperationContextScope scope = new OperationContextScope(wcfClient.InnerChannel))
{
MessageHeader header
= MessageHeader.CreateHeader(
"Service-Bound-CustomHeader",
"http://Microsoft.WCF.Documentation",
"Custom Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// Making calls.
Console.WriteLine("Enter the greeting to send: ");
string greeting = Console.ReadLine();
//Console.ReadLine();
header = MessageHeader.CreateHeader(
"Service-Bound-OneWayHeader",
"http://Microsoft.WCF.Documentation",
"Different Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// One-way
wcfClient.Push(greeting);
this.wait.WaitOne();
// Done with service.
wcfClient.Close();
Console.WriteLine("Done!");
Console.ReadLine();
}
}
catch (TimeoutException timeProblem)
{
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (CommunicationException commProblem)
{
Console.WriteLine("There was a communication problem. " + commProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
메타데이터의 끝점 주소
끝점 주소는 해당 끝점의 wsdl:port 요소 내에서 WS-Addressing EndpointReference(EPR) 요소로서 WSDL(웹 서비스 기술 언어)로 표시됩니다. EPR에는 끝점 주소와 주소 속성이 포함되어 있습니다. wsdl:port 내의 EPR은 다음 예제에 표시된 것처럼 soap:Address로 바뀝니다.
코드에서 끝점 주소 정의
끝점 주소는 EndpointAddress 클래스를 사용하여 코드에 만들 수 있습니다. 끝점 주소에 대해 지정된 URI는 정규화된 경로 또는 서비스 기본 주소에 상대적인 경로일 수 있습니다. 다음 코드에서는 EndpointAddress 클래스의 인스턴스를 만들어 서비스를 호스팅하는 ServiceHost 인스턴스에 추가하는 방법을 보여 줍니다.
다음 예제에서는 전체 끝점 주소를 코드에서 지정하는 방법을 보여 줍니다.
Uri baseAddress = new Uri("https://localhost:8000/HelloService");
string address = "https://localhost:8000/HelloService/MyService";
using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), address);
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
Console.ReadLine();
serviceHost.Close();
}
다음 예제에서는 상대 주소("MyService")를 서비스 호스트의 기본 주소에 추가하는 방법을 보여 줍니다.
Uri baseAddress = new Uri("https://localhost:8000/HelloService");
using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), "MyService");
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
Console.ReadLine();
serviceHost.Close();
}
참고: |
---|
ServiceHostBase의 OnOpening 메서드 다음에 나오는 서비스 응용 프로그램의 ServiceDescription 속성은 수정하면 안 됩니다. ServiceHostBase 및 ServiceHost에서 Credentials 속성과 AddServiceEndpoint 메서드와 같은 일부 멤버는 해당 지점을 지나서 수정할 경우 예외를 throw합니다. 다른 멤버에서는 이를 수정할 수 있지만 그 결과는 예측할 수 없습니다. 마찬가지로 클라이언트에서 ChannelFactory의 OnOpening을 호출한 이후에는 ServiceEndpoint 값을 수정해서는 안 됩니다. Credentials 속성은 해당 지점을 지나서 수정할 경우 예외를 throw합니다. 다른 클라이언트 설명 값은 수정해도 오류가 발생하지 않지만 결과가 정의되어 있지 않습니다. 서비스와 클라이언트 모두에 대해 Open을 호출하기 이전에 설명을 수정하는 것이 좋습니다. |
기본 끝점 사용
코드 또는 구성에서 끝점을 지정하지 않으면 런타임이 서비스에서 구현되는 각 서비스 계약의 각 기본 주소에 대해 기본 끝점을 하나씩 추가하여 기본 끝점을 제공합니다. 기본 주소는 코드 또는 구성에서 지정할 수 있으며 기본 끝점은 ServiceHost에서 Open을 호출하면 추가됩니다.
끝점을 명시적으로 제공하는 경우에도 Open을 호출하기 전에 ServiceHost에서 AddDefaultEndpoints를 호출하여 기본 끝점을 추가할 수 있습니다. 기본 끝점, 바인딩 및 동작에 대한 자세한 내용은 단순화된 구성 및 Simplified Configuration for WCF Services을 참조하십시오.