사용자 지정 서비스 호스트
CustomServiceHost 샘플에서는 ServiceHost 클래스의 사용자 지정 파생 항목을 사용하여 서비스의 런타임 동작을 변경하는 방법을 보여 줍니다. 이 접근 방식을 사용하면 일반적인 방법으로 여러 서비스를 구성하는 대신 재사용 가능한 대체 방법이 제공됩니다. 또한 샘플에서는 ServiceHostFactory 클래스를 사용하여 IIS(인터넷 정보 서비스) 또는 WAS(Windows Process Activation Service) 호스팅 환경에서 사용자 지정 ServiceHost를 사용하는 방법을 보여 줍니다.
시나리오 정보
잠재적으로 중요한 서비스 메타데이터가 의도하지 않게 공개되는 것을 방지하기 위해 WCF(Windows Communication Foundation) 서비스의 기본 구성은 메타데이터 게시를 사용하지 않도록 설정합니다. 이 동작은 기본적으로 안전하지만 구성에서 서비스의 메타데이터 게시 동작이 명시적으로 사용하도록 설정되어 있지 않은 경우 Svcutil.exe 등의 메타데이터 가져오기 도구를 사용하여 서비스를 호출하는 데 필요한 클라이언트 코드를 생성할 수 없습니다.
여러 서비스에 메타데이터 게시를 사용하도록 설정하면 각각의 개별 서비스에 동일한 구성 요소가 추가되어 기본적으로 동일한 구성 정보가 많이 생성될 수 있습니다. 각 서비스를 개별적으로 구성하는 대신 메타데이터 게시를 한 번 사용한 다음 여러 가지 다른 서비스에서 해당 코드를 다시 사용하도록 하는 명령 코드를 작성할 수 있습니다. 이 작업은 새 클래스를 만들어 수행합니다. 새 클래스는 ServiceHost에서 파생되며 ApplyConfiguration
() 메서드를 재정의하여 메타데이터 게시 동작을 명령적으로 추가합니다.
Important
쉽게 구별할 수 있도록 이 샘플에서는 보안이 설정되지 않은 메타데이터 게시 엔드포인트를 만드는 방법을 보여 줍니다. 이러한 엔드포인트는 인증되지 않은 익명의 소비자가 사용할 수 있으므로 이러한 엔드포인트를 배포하기 전에 서비스의 메타데이터를 공개하는 것이 적절한지 주의를 기울여야 합니다.
사용자 지정 ServiceHost 구현
ServiceHost 클래스는 상속자가 서비스의 런타임 동작을 변경하기 위해 재정의할 수 있는 여러 가지 유용한 가상 메서드를 노출합니다. 예를 들어, ApplyConfiguration
() 메서드는 구성 저장소에서 서비스 구성 정보를 읽고 그에 따라 호스트의 ServiceDescription을 변경합니다. 기본 구현에서는 애플리케이션의 구성 파일에서 구성을 읽습니다. 사용자 지정 구현에서는 명령 코드를 사용하여 ApplyConfiguration
을 추가로 변경하거나 기본 구성 저장소를 완전히 바꾸도록 ServiceDescription()을 재정의할 수 있습니다. 예를 들어, 애플리케이션의 구성 파일 대신 데이터베이스에서 서비스의 엔드포인트 구성을 읽을 수 있습니다.
이 샘플에서는 메타데이터 게시를 사용하도록 설정하는 ServiceMetadataBehavior가 서비스의 구성 파일에 명시적으로 추가되지 않은 경우에도 이 동작을 추가하는 사용자 지정 ServiceHost를 빌드합니다. 이 작업을 수행하려면 ServiceHost에서 상속되며 ApplyConfiguration
()을 재정의하는 새 클래스를 만듭니다.
class SelfDescribingServiceHost : ServiceHost
{
public SelfDescribingServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses) { }
//Overriding ApplyConfiguration() allows us to
//alter the ServiceDescription prior to opening
//the service host.
protected override void ApplyConfiguration()
{
//First, we call base.ApplyConfiguration()
//to read any configuration that was provided for
//the service we're hosting. After this call,
//this.Description describes the service
//as it was configured.
base.ApplyConfiguration();
//(rest of implementation elided for clarity)
}
}
애플리케이션의 구성 파일에 제공된 구성을 무시하지 않으므로 ApplyConfiguration
()을 재정의하는 경우 제일 먼저 기본 구현이 호출됩니다. 이 메서드가 완료되면 다음 명령 코드를 사용하여 ServiceMetadataBehavior를 명령적으로 설명에 추가할 수 있습니다.
ServiceMetadataBehavior mexBehavior = this.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (mexBehavior == null)
{
mexBehavior = new ServiceMetadataBehavior();
this.Description.Behaviors.Add(mexBehavior);
}
else
{
//Metadata behavior has already been configured,
//so we do not have any work to do.
return;
}
마지막으로 ApplyConfiguration
()을 재정의하기 위해 기본 메타데이터 엔드포인트를 추가합니다. 규칙에 따라 서비스 호스트의 BaseAddresses 컬렉션에 각 URI마다 메타데이터 엔드포인트가 하나씩 생성됩니다.
//Add a metadata endpoint at each base address
//using the "/mex" addressing convention
foreach (Uri baseAddress in this.BaseAddresses)
{
if (baseAddress.Scheme == Uri.UriSchemeHttp)
{
mexBehavior.HttpGetEnabled = true;
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeHttps)
{
mexBehavior.HttpsGetEnabled = true;
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpsBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeNetPipe)
{
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexNamedPipeBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeNetTcp)
{
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
"mex");
}
}
자체 호스팅 환경에서 사용자 지정 ServiceHost 사용
이제 사용자 지정 ServiceHost 구현을 완료했으므로 SelfDescribingServiceHost
의 인스턴스 내부에 해당 서비스를 호스트하여 모든 서비스에 메타데이터 게시 동작을 추가할 수 있습니다. 다음 코드에서는 자체 호스팅 시나리오에서 해당 서비스를 사용하는 방법을 보여 줍니다.
SelfDescribingServiceHost host =
new SelfDescribingServiceHost( typeof( Calculator ) );
host.Open();
사용자 지정 호스트는 기본 ServiceHost 클래스를 사용하여 서비스를 호스트한 경우처럼 애플리케이션 구성 파일에서 서비스의 엔드포인트 구성을 계속 읽습니다. 그러나 사용자 지정 호스트의 내부에서 메타데이터 게시를 사용하도록 설정하는 논리를 추가했으므로 구성에서 메타데이터 게시 동작을 더 이상 명시적으로 사용하도록 설정할 필요가 없습니다. 이 접근 방식을 사용하면 여러 서비스가 포함된 애플리케이션을 빌드할 때 같은 구성 요소를 반복해서 작성하지 않고도 각 서비스에서 메타데이터 게시를 사용하도록 설정할 수 있다는 장점이 있습니다.
IIS 또는 WAS 환경에서 사용자 지정 ServiceHost 사용
자체 호스팅 시나리오에서는 결국 애플리케이션 코드를 통해 서비스 호스트 인스턴스를 만들고 여는 작업을 수행하므로 사용자 지정 서비스 호스트 사용이 간단합니다. 그러나 IIS 또는 WAS 호스팅 환경에서는 WCF 인프라가 들어오는 메시지에 대한 응답으로 서비스의 호스트를 동적으로 인스턴스화합니다. 이 호스팅 환경에서 사용자 지정 서비스 호스트를 사용할 수도 있지만 ServiceHostFactory 형식의 추가 코드가 필요합니다. 다음 코드에서는 사용자 지정 ServiceHostFactory의 인스턴스를 반환하는 SelfDescribingServiceHost
의 파생 항목을 보여 줍니다.
public class SelfDescribingServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType,
Uri[] baseAddresses)
{
//All the custom factory does is return a new instance
//of our custom host class. The bulk of the custom logic should
//live in the custom host (as opposed to the factory)
//for maximum
//reuse value outside of the IIS/WAS hosting environment.
return new SelfDescribingServiceHost(serviceType,
baseAddresses);
}
}
이 샘플에서 볼 수 있듯이 사용자 지정 ServiceHostFactory 구현은 간단합니다. 모든 사용자 지정 논리는 ServiceHost 구현 내에 있고 팩터리는 파생 클래스의 인스턴스를 반환합니다.
서비스 구현에서 사용자 지정 팩터리를 사용하려면 서비스의 .svc 파일에 일부 메타데이터를 추가해야 합니다.
<% @ServiceHost Service="Microsoft.ServiceModel.Samples.CalculatorService"
Factory="Microsoft.ServiceModel.Samples.SelfDescribingServiceHostFactory"
language=c# Debug="true" %>
여기서는 @ServiceHost
지시문에 추가 Factory
특성을 추가하고 사용자 지정 팩터리의 CLR 형식 이름을 특성의 값으로 전달했습니다. IIS나 WAS에서 이 서비스에 대한 메시지를 받으면 WCF 호스팅 인프라에서는 먼저 ServiceHostFactory의 인스턴스를 만든 다음 ServiceHostFactory.CreateServiceHost()
를 호출하여 서비스 호스트 자체를 인스턴스화합니다.
샘플 실행
이 샘플에서는 완전한 기능을 갖춘 클라이언트 및 서비스 구현을 제공하지만 샘플의 핵심은 사용자 지정 호스트를 사용하여 서비스의 런타임 동작을 변경하는 방법을 보여 주는 것이므로 다음 단계를 수행합니다.
사용자 지정 호스트의 효과 확인
서비스의 Web.config 파일을 열고 서비스에서 메타데이터를 사용하도록 명시적으로 설정하는 구성이 없는지 확인합니다.
서비스의 .svc 파일을 열고 @ServiceHost 지시문에 사용자 지정 ServiceHostFactory의 이름을 지정하는 Factory 특성이 포함되어 있는지 확인합니다.
샘플 설치, 빌드 및 실행
Windows Communication Foundation 샘플의 일회 설치 절차를 수행했는지 확인합니다.
솔루션을 빌드하려면 Windows Communication Foundation 샘플 빌드의 지침을 따릅니다.
솔루션을 빌드한 후 Setup.bat를 실행하여 IIS 7.0에 ServiceModelSamples 애플리케이션을 설치합니다. 이제 ServiceModelSamples 디렉터리가 IIS 7.0 애플리케이션으로 나타납니다.
단일 컴퓨터 또는 다중 컴퓨터 구성에서 샘플을 실행하려면 Windows Communication Foundation 샘플 실행의 지침을 따릅니다.
IIS 7.0 애플리케이션을 제거하려면 Cleanup.bat를 실행합니다.