Programmer/WCF - 해당되는 글 2건

Windows Workflow Foundation 및 Windows Communication Foundation 통합

 

Jeremy Boyd
Intergen

2007년 1월

적용 대상: Windows Workflow Foundation,
                Windows Communication Foundation,
                Microsoft Visual Studio 2005

요약: 이 기사에서는 Windows WF(Workflow Foundation)를 사용하여 작성한 워크플로가 WCF(Windows Communication Foundation)를 사용하여 만든 서비스 내에서 어떻게 호스팅되는지에 대한 개요를 제공합니다. 또한 WCF에서 제공되는 광범위한 기능 중 일부를 활용하여 이중 채널을 통해 클라이언트-이벤트 콜백을 용이하게 하는 방법에 대해서도 설명합니다.

참고: 이 기사에 대한 의견은 Vistadev@microsoft.com으로 전자 메일을 보내 주십시오.

목차


"Windows Workflow Foundation Sample Integrating WF and WCF"를 다운로드하려면 여기 (영문)를 클릭하십시오.


소개

Microsoft는 Windows WF(Workflow Foundation) 출시에 맞춰 .NET 개발자 플랫폼에 워크플로 기능을 도입하고 있습니다. 개발자는 이 기능을 사용하여 간단한 순차 워크플로부터 정교한 사용자 상호 작용을 포함하는 복잡한 상태 컴퓨터 기반 워크플로에 이르기까지 광범위한 시나리오를 충족하는 워크플로를 구축할 수 있습니다.

이와 동시에 캡슐화된 서비스 끝점을 통해 비즈니스 기능을 제공하여 비즈니스 기능과 프로세스의 재사용 및 결합을 가능하게 함으로써 서비스 지향 아키텍처를 구성하는 경향이 늘어나고 있습니다. WCF(Windows Communication Foundation)는 일관성 있는 개발자 API, 강력한 호스팅 런타임, 그리고 배포 작업을 돕는 유연한 구성 기반 솔루션을 통해 개발자가 손쉽게 연결된 시스템을 개발할 수 있는 기능을 제공합니다.

이 문서의 마지막에는 WF 및 WCF에 대해 더 배우고자 할 때 참조할 수 있는 추가 리소스 목록이 있습니다.


비용 보고 샘플

이 기사의 코드 샘플은 직원의 비용 청구를 제출 및 승인하는 표준 비즈니스 프로세스를 모델링하는 비용 보고 워크플로 샘플을 기반으로 합니다. 이 원본 샘플은 WCF 및 .NET 3.0 Framework를 활용하여 이 시나리오를 더욱 효과적으로 호스팅하는 방법을 보여 주도록 업데이트되었습니다.

비용 보고 샘플의 첫 릴리스에서는 워크플로 런타임 인스턴스가 포함된 호스트 응용 프로그램과 클라이언트 응용 프로그램 간의 통신 기능을 제공하기 위해 .NET Remoting을 사용했습니다.

그러나 이번에는 비용 보고 구현을 리팩터링하여 클라이언트와 서비스 간 통신에 WCF를 사용하도록 만들었습니다. 또한 솔루션 내의 다양한 고려 사항을 분류하기 위해 논리적인 솔루션 구조를 사용했습니다.

그림 1. 리팩터링된 솔루션의 구조

설계에 메시지를 통합하기 위해서는 이러한 메시지가 비즈니스 프로세스 컨텍스트 내에서 어떻게 사용되는지 이해하는 것이 중요합니다. 비용 보고의 수명 주기에는 여러 개의 상호 작용 지점이 있습니다. 이러한 상호 작용 지점을 간단히 검토해 보겠습니다.

  • 프로세스에는 '클라이언트', '관리자'및 비용 보고 '호스트' 시스템이라는 세 가지 관계 요소가 있습니다.
  • '클라이언트'가 새 비용 청구를 제출하면 프로세스가 시작됩니다.
  • 규칙의 '정책'을 사용하여 비용 청구를 자동으로 승인할 수 있는지 판단합니다.
  • 비용 청구가 자동으로 승인되지 않은 경우 요청을 승인할 '관리자'가 필요합니다. 관리자는 승인해야 하는 새로운 보고가 있는지 확인하거나 알림을 받아야 합니다.
  • 관리자가 '대기' 시간(조정 가능) 동안 승인하지 않으면 자동으로 청구가 거부됩니다.
  • 청구를 검토한 후 '클라이언트'와 '관리자'는 검토 결과에 따라 업데이트되어야 합니다.

WF를 사용하면 프레임워크에서 제공하는 표준 작업을 사용하여 이러한 프로세스를 모델링할 수 있습니다. DelayActivity를 사용하면 일정 기간이 지난 뒤의 이벤트 트리거를 관리할 수 있고, 규칙 엔진 및 PolicyActivity를 사용하면 결과에 대한 질문을 받는 융통성 있는 규칙 집합을 관리할 수 있습니다.

이 프로세스는 사용자 지향 프로세스이므로 개발자는 최종 사용자와 상호 작용하고 이러한 상호 작용이 발생하도록 워크플로를 구성해야 합니다. WF는 로컬 서비스인 HandleExternalEventActivityCallExternalMethodActivity를 통해 호스트 및 워크플로 간 통신을 허용하는 포괄적인 프로그래밍 모델을 제공합니다.

이 부분은 대화형 워크플로를 구축하는 데 있어 중요한 개념이므로 WF 설계에 어떻게 반영되었는지 간략하게 살펴보겠습니다.

WF에서 상호 작용을 모델링하기 위해서는 여러 이벤트와 메서드를 제공하는 계약을 설계해야 합니다. 이 계약은 워크플로 및 호스트 프로세스 양쪽에서 모두 인식됩니다. 구축하려는 계약/인터페이스는 워크플로-데이터 교환을 위해 설계되었음을 식별하는 [ExternalDataExchange()] 특성으로 표시해야 합니다. 샘플에서는 워크플로에 IExpenseLocalService 인터페이스를 사용합니다.

그런 다음 워크플로 런타임으로 해당 인터페이스를 구현하는 클래스(로컬 서비스라고 함)를 등록합니다. 워크플로 작업은 이벤트에 등록하거나, 인터페이스 유형에 대해 정의된 메서드를 사용할 수 있으며, 등록한 로컬 서비스로 연결됩니다. 여기에서는 로컬 서비스의 기반 형식과 워크플로 간의 밀결합을 제거하는 제어 반전(Inversion of Control)이라고 하는 패턴을 사용합니다. 샘플에서는 ExpenseLocalService 클래스가 IExpenseLocalService 계약을 구현합니다.

워크플로는 처음 실행될 때 작업할 초기 데이터를 받을 수 있습니다. 워크플로가 외부 상호 작용이 필요한 지점에 이르면 워크플로 내에서 HandleExternalEventActivity에 바인딩할 수 있는 이벤트를 발생시킬 수 있습니다. 이 작업은 인터페이스 유형과 이벤트를 인수로 취하며, 이벤트가 발생하여 실행을 계속하도록 허용하면 워크플로가 가동을 시작합니다.

워크플로에서 로컬 서비스를 콜백해야 하는 경우 CallExternalMethodActivity를 사용하고 인터페이스 및 메서드 이름을 인수로 제공하면 됩니다.

이러한 작업을 사용하여 실행 중인 워크플로가 있는 호스트 프로세스 내에서 양방향 통신을 수행할 수 있으며 WF 내에서 제어 반전 패턴을 사용하여 워크플로와 로컬 서비스 간의 밀결합을 방지할 수 있습니다.

그러나 호스트 프로세스보다 범위를 넓혀 다른 시스템 또는 사용자에 의한 상호 작용을 허용해야 합니다. 다른 서비스나 사용자 기반 응용 프로그램에서 호출할 수 있는 모든 서비스에 대화식 작업을 분산하면 이러한 수준의 상호 작용을 달성할 수 있습니다. WCF는 이러한 메시징 기능을 유연하게 구축할 수 있는 프레임워크입니다.

이번 시나리오에서 WCF와의 통합이 주는 주요 이점은 다음과 같습니다.

  • 서비스 구현을 메시징 내부 작업 코드에서 분리할 수 있습니다.
  • 시스템 연결을 위한 코드 및 복잡성이 훨씬 줄어듭니다.
  • 배포 유연성을 확보할 수 있습니다.
  • 호스트에서 클라이언트로 직접 콜백을 사용할 수 있으므로 더 빠르고 오버헤드가 적은 방법으로 정보를 업데이트할 수 있습니다.

통합을 위한 검사 목록

WF와 WCF의 통합을 완료하려면 사용자가 워크플로를 시작하거나 실행 중인 워크플로와 상호 작용할 수 있는 여러 인터페이스 지점을 제공하는 서비스 인터페이스를 노출해야 합니다. 서비스는 비즈니스 프로세스가 외부 엔터티(예: 프로세스에 관련된 사용자)와 상호 작용하는 지점을 중심으로 모델링해야 합니다.

그림 2. 비용 보고 시나리오의 상호 작용 지점


이를 위해서는 다음을 수행해야 합니다.

  • 서비스 계약을 정의합니다.
  • 이벤트를 통해 새로운 워크플로를 만들거나 기존 워크플로와 상호 작용하는 서비스 작업을 구현합니다.
  • 서비스 호스트 내에서 워크플로 런타임 인스턴스를 호스팅합니다.

단순히 워크플로를 호스팅하는 것 이외에도 WCF 이중 채널을 활용하여 워크플로의 이벤트를 소비 클라이언트에서 발생시킬 수 있습니다. 비용 보고의 경우 솔루션이 정기적인 데이터 업데이트를 위해 서비스를 폴링하는 클라이언트에 의존하므로 이러한 기능이 도움이 됩니다. 클라이언트는 이러한 방법 대신 서비스에서 직접 알림을 받을 수 있습니다.

이를 위해서는 다음을 수행해야 합니다.

  • 콜백 계약을 정의합니다.
  • 이중 채널을 지원하는 바인딩을 사용합니다.

서비스 계약 정의

WCF(Windows Communication Foundation)는 서비스의 기능과 데이터 교환을 추상적으로 정의하는 공식 계약을 선언하도록 요구합니다. 이 계약은 코드에서 인터페이스 선언을 통해 정의합니다.

비즈니스 서비스를 설계할 때는 일반적으로 요청/응답 공동 작업 패턴을 사용하게 됩니다. 이 패턴을 사용하는 경우 제공하려는 계약에서 다음과 같은 세 가지 측면을 준비해야 합니다.

  • 게시되는 작업. 서비스가 해당 소비자에게 게시하는 기능이며 인터페이스상의 메서드입니다.
  • 각 요청 및 응답에 대해 구조화된 데이터를 캡슐화하는 메시지. 각 메서드에 대한 인수 및 반환 형식입니다. WCF 용어로는 대개 메시지 계약이지만 비교적 간단한 시나리오에서는 데이터 계약이 됩니다.
  • 서비스를 통해 교환할 수 있는 핵심 비즈니스 엔터티의 데이터 정의. 메시지의 일부를 구성하는 요소로, WCF 용어로는 데이터 계약이 됩니다.

서비스 계약은 작업을 노출하는 계약을 정의한 후 연결을 통해 게시되는 특정 작업을 정의하는 특성 기반 태그를 사용하여 정의됩니다.

각 서비스 계약은 [ServiceContract] 특성으로 명시적으로 표시됩니다. 이 특성은 다음과 같은 매개 변수와 함께 선언할 수 있습니다.

  • Name. WSDL <portType> 요소에 선언된 계약 이름을 제어합니다.
  • Namespace. WSDL <portType> 요소에 선언된 계약의 네임스페이스를 제어합니다.
  • SessionMode. 계약에 세션을 지원하는 바인딩이 필요한지 여부를 지정합니다.
  • CallbackContract. 클라이언트 콜백에 사용될 계약을 지정합니다.
  • ProtectionLevel. 계약에 ProtectionLevel 속성을 지원하는 바인딩이 필요한지 여부를 지정합니다. 이 속성은 암호화 및 디지털 서명을 위한 요구 사항을 선언하는 데 사용됩니다.

작업 선언

이제 서비스는 여러 개의 게시된 작업으로 구성됩니다. 작업은 [OperationContract] 특성으로 표시되어 명시적으로 계약에 포함됩니다. ServiceContract와 마찬가지로 OperationContract에는 끝점에 바인딩되는 방식을 제어하는 다음과 같은 여러 매개 변수가 있습니다.

  • Action. 이 작업을 고유하게 식별하는 이름을 제어합니다. 메시지가 끝점에 수신되면 발송자는 제어 및 작업을 사용하여 호출할 메서드를 결정합니다.
  • IsOneWay. 작업이 요청 메시지를 받지만 응답은 생성하지 않음을 나타냅니다. 이는 단순히 void 반환 형식을 반환하는 것(이 경우 결과 메시지가 생성됨)과는 다릅니다.
  • ProtectionLevel. 작업에 필요한 암호화 또는 서명 요구 사항을 지정합니다.

다음은 코드에서 서비스 계약 부분을 보여 주는 예제입니다.

[ServiceContract]
public interface IExpenseService
{
        [OperationContract]
        GetExpenseReportsResponse GetExpenseReports();

        [OperationContract]
        GetExpenseReportResponse GetExpenseReport(GetExpenseReportRequest 
getExpenseReportRequest);
}

메시지 및 데이터 엔터티 선언

메시지는 전송할 각 메시지에 대한 페이로드 또는 본문을 정의하는 클래스로 모델링하는 것이 좋습니다. 이는 ASP.NET을 사용하여 웹 서비스를 구축할 때 WSCF(WS Contract First)와 같은 도구를 사용하여 메시지를 모델링하는 방식과 비슷합니다.

WCF는 기본적으로 DataContractSerializer라는 serialization 엔진을 사용하여 데이터를 serialize(데이터를 XML로 변환) 및 deserialize(XML을 데이터로 변환)합니다. DataContractSerializer를 사용하기 위해 System.Runtime.Serialization 네임스페이스에 대한 참조를 추가한 후 클래스에 [DataContract] 특성을 표시하고 게시할 멤버를 [DataMember]로 표시합니다.

[DataContract]
    public class GetExpenseReportsResponse
    {
        private List<ExpenseReport> reports;

        [DataMember]
        public List<ExpenseReport> Reports
        {
            get { return reports; }
            set { reports = value; }
        }
    }

메시지 내에서 사용되는 데이터 엔터티는 비즈니스 영역 내의 엔터티를 나타냅니다. 메시지 계약과 마찬가지로 DataContractSerializer 및 특성을 사용하여 배포되는 멤버를 명시적으로 포함할 수 있습니다. 또는 데이터 모델링만 수행하려는 경우에는 공용 필드 방식을 사용하고 클래스를 serialize 가능한 것으로 표시할 수 있습니다.

샘플에서는 메시징 태그 처리를 위해 데이터 계약 방식을 사용했습니다. 실제 시나리오에서는 복잡한 스키마, 스키마에서의 속성 사용, 그리고 SOAP 헤더 사용 요구 사항을 처리해야 하는 경우가 많습니다. WCF는 이러한 극한의 상황을 위해 본문만이 아닌 전체 SOAP Envelope를 기술하는 [MessageContract] 특성으로 표시되는 클래스를 정의하는 기능을 제공합니다.

데이터 계약과 메시지 계약에 대한 자세한 내용은 이 기사의 마지막 부분에 있는 추가 정보에서 각 해당 MSDN Library 기사를 참조하십시오.


워크플로 런타임 호스팅

서비스에서는 일반적으로 서비스 형식의 새 인스턴스가 생성되고 세션 수명 주기 동안 유지 관리되는 동시 동작을 허용합니다. 이러한 상황에서 워크플로를 사용하려면 호출별로 실행하는 대신 워크플로 런타임의 인스턴스를 만들어 서비스-호스트 인스턴스의 수명 동안 이를 유지 관리해야 합니다.

이를 위해 권장되는 방식은 호스트 서비스 생성 시에 활성화되는 확장 클래스를 사용하는 것입니다. 이 확장은 워크플로 런타임의 전역 인스턴스를 만들고 유지 관리하며, 각 독립 서비스 인스턴스에서 이를 액세스할 수 있도록 허용합니다.

ServiceHost에 확장을 구현하려면 IExtension<ServiceHostBase>를 구현하는 클래스를 만듭니다. 솔루션에서는 WcfExtensions 코드 프로젝트 아래에 있는 WfWcfExtension 클래스를 통해 이에 대한 예제를 볼 수 있습니다.

여기에서는 두 가지 메서드, 즉 확장이 해당 부모 개체에 연결될 때 호출되는 Attach와 부모 개체가 언로드될 때 호출되는 Detach를 구현해야 합니다.

다음에서 볼 수 있듯이 Attach 메서드는 WorkflowRuntime의 새 인스턴스를 만들어 필요한 서비스로 인스턴스화합니다. 이 인스턴스는 workflowRuntime이라는 로컬 개인 필드에 저장합니다.

void IExtension<ServiceHostBase>.Attach(ServiceHostBase owner)
{
   workflowRuntime = new WorkflowRuntime(workflowServicesConfig);
   ExternalDataExchangeService exSvc = new ExternalDataExchangeService();
   workflowRuntime.AddService(exSvc);
   workflowRuntime.StartRuntime();
}

여기에서 볼 수 있듯이 워크플로 런타임의 초기화에는 시작하기 전에 서비스 인스턴스를 런타임에 추가하는 작업이 포함됩니다. 솔루션을 구축할 때는 일반적으로 런타임을 시작하기 전에 모든 서비스를 추가하는 것이 좋습니다. 그러나 결합이 문제시되는 경우에는 후기 바인딩 방식을 사용하는 것이 더 적합할 수 있습니다.

샘플에서는 WorkflowRuntime이 시작된 후에 ExpenseService 클래스에 있는 SetUpWorkflowEnvironment 메서드의 일부로 ExpenseLocalService 인스턴스를 ExternalDataExchangeService에 추가합니다.

다음에서 볼 수 있는 Detach 메서드는 StopRuntime을 호출하여 런타임을 종료합니다.

void IExtension<ServiceHostBase>.Detach(ServiceHostBase owner)
{
   workflowRuntime.StopRuntime();
}

WorkflowRuntime이 서비스-호스트 시작의 일부로 생성 및 초기화되므로 모든 기존 워크플로는 서비스 호출이 수행되기 전에 진행할 수 있게 됩니다. 서비스 호스트가 종료되면 워크플로 런타임도 깔끔하게 종료됩니다.

참고   워크플로를 호스팅하고 장시간 실행되는 워크플로를 모델링하는 경우에는 일반적인 방법인 워크플로 지속성 서비스(예: SqlWorkflowPersistenceService)를 사용하는 것이 좋습니다. 이는 응용 프로그램이나 프로세스가 다시 시작되더라도 상태 지속성을 유지하는 메커니즘을 제공합니다.

서비스 작업 만들기

서비스 동작을 포함하는 클래스를 만들려면 서비스 계약을 정의하는 인터페이스를 한 개 이상 구현해야 합니다.

public class ExpenseService :
        IExpenseService,
        IExpenseServiceClient,
        IExpenseServiceManager

워크플로와의 통합을 위해 서비스 메서드는 비즈니스 논리를 포함하지 않지만 대신 이벤트를 제어하거나 비즈니스 프로세스를 캡슐화하는 실행 중인 워크플로에 이벤트를 발생시키는 코드를 포함합니다.

워크플로를 처리하는 작업에서는 새 워크플로를 시작하거나 이미 실행 중인 워크플로와 상호 작용하게 됩니다.

새 워크플로 인스턴스를 만들려면 WorkflowRuntime을 사용하여 원하는 워크플로 유형의 새 인스턴스를 인스턴스화해야 합니다. ServiceHost 확장 클래스에서 이미 이러한 인스턴스를 만들었습니다. 이 인스턴스에 대한 참조를 얻으려면 OperationContext를 사용하여 사용자 지정 확장을 찾아야 합니다.

WfWcfExtension extension = 
OperationContext.Current.Host.Extensions.Find<WfWcfExtension>();
workflowRuntime = extension.WorkflowRuntime;

OperationContext는 서비스 메서드의 실행 컨텍스트에 대한 액세스를 제공하는 클래스입니다. 앞에 있는 코드를 보면 알 수 있듯이 이 클래스는 현재 서비스 메서드에 대한 컨텍스트를 제공하는 Current라는 단일 항목을 제공합니다. Host 속성을 호출하여 실행 중인 ServiceHost로 인스턴스를 가져온 다음 그 유형을 기반으로 확장을 찾습니다.

확장 인스턴스에 대한 참조를 확보한 다음에는 공용 속성을 통해 WorkflowRuntime을 반환하고 이를 사용하여 SequentialWorkflow의 새 인스턴스를 만들 수 있습니다.

Guid workflowInstanceId = 
submitExpenseReportRequest.Report.ExpenseReportId;

Assembly asm = Assembly.Load("ExpenseWorkflows");
Type workflowType = asm.GetType("ExpenseWorkflows.SequentialWorkflow");

WorkflowInstance workflowInstance =
   workflowRuntime.CreateWorkflow(workflowType, null, workflowInstanceId);
workflowInstance.Start();

expenseLocalService.RaiseExpenseReportSubmittedEvent(
   workflowInstanceId, submitExpenseReportRequest.Report);

위의 코드에서는 미리 정의된 유형을 바탕으로 새 워크플로 인스턴스를 만듭니다. 이는 직접적인 유형 인스턴스화를 통해서도 가능하지만 여기에서는 엄격하게 형식이 지정된 바인딩 대신 런타임에 동적인 규칙을 바탕으로 워크플로를 만드는 유연성을 발휘할 수 있음을 보여 줍니다.

마지막 줄은 워크플로의 첫 번째 HandleExternalEventActivity에서 처리되는 이벤트를 발생시켜 워크플로의 시작을 알립니다. 이 이벤트는 ExpenseLocalService 클래스의 인스턴스를 통해 발생시킵니다. 샘플에서는 ExpenseLocalService를 사용하여 새 워크플로를 시작하거나 기존 워크플로에 이벤트를 발생시켜 워크플로와 상호 작용합니다. 이 클래스는 비즈니스 프로세스를 캡슐화하는 메커니즘으로 사용되며 내부적으로는 WF를 사용하여 구현됩니다.

그림 3. 워크플로는 HandleExternalEventActivity로 시작됩니다.


처리해야 할 다른 유형의 상황은 기존 워크플로로 콜백하고 이벤트를 발생시키는 것입니다. 워크플로 엔진으로 이벤트를 발생시켜 기존 워크플로가 이벤트를 받고 처리를 계속할 수 있도록 해야 합니다.

비용 보고 흐름 내에서 이러한 상황이 발생하는 예로는 관리자 승인이 필요한 경우를 들 수 있습니다. 워크플로는 RequestManagerApproval에 대한 외부 메서드를 호출하고 이 메서드는 관리자에게 새 비용 보고서를 승인하거나 거부해야 한다는 알림을 생성합니다.

워크플로에는 가능한 이벤트 중 하나가 발생할 때까지 차단하는 ListenActivity가 포함되어 있습니다. 이 경우에는 관리자가 보고서를 검토했거나 DelayActivity에 따라 시간이 초과되었음을 알리는 이벤트를 수신하게 됩니다.

그림 4. ManagerApproval 사용자 지정 작업 흐름


Guid workflowInstanceId = 
submitReviewedExpenseReportRequest.Report.ExpenseReportId;

ExpenseReportReviewedEventArgs e =
   new ExpenseReportReviewedEventArgs(workflowInstanceId, report, review);

if (ExpenseReportReviewed != null)
{
   ExpenseReportReviewed(null, e);
}

관리자가 ManagerApplication을 사용하여 보고서를 검토하면 호스트로 서비스 호출이 다시 수행되어 ExpenseReportReviewed 이벤트를 발생시키는 SubmitReviewedExpenseReport 메서드가 호출됩니다.

워크플로에서 HandleExternalEventActivity로 이벤트를 발생시키는 경우 이벤트를 라우팅할 수 있도록 현재 처리하고 있는 워크플로 인스턴스의 GUID를 알아야 합니다.

각 이벤트는 EventArgs와 함께 생성되는데, EventArgs를 사용하면 이벤트 모델을 통해 워크플로로 데이터를 다시 전달할 수 있습니다. 이 예에서는 검토 작업의 컨텍스트를 제공하는 데이터와 보고서의 현재 상태에 대한 세부 정보를 모두 전달할 수 있습니다.

워크플로에서 이벤트는 HandleExternalEventActivity의 속성을 통해 자동으로 워크플로에 연결됩니다.

그림 5. HandleExternalEventActivity를 IExpenseLocalService 인터페이스에 연결합니다.


[ExternalDataExchange] 특성으로 표시해야 하는 인터페이스 유형을 지정한 후 HandleExternalEventActivity에서 구독할 해당 인터페이스의 이벤트를 지정합니다.

이벤트 인수는 ExternalDataEventArgs 클래스에서 파생되어야 합니다. 이는 최소한 각 이벤트가 워크플로의 InstanceId와 같은 컨텍스트를 포함하게 된다는 것을 의미합니다. 그러면 워크플로 런타임은 올바른 워크플로 인스턴스로 이벤트를 라우팅하여 계속 진행되도록 합니다. 지속성 서비스를 사용하는 경우에는 런타임은 실행 기간 동안 워크플로에 대한 실행 상태의 하이드레이션 및 리하이드레이션 작업도 관리하게 됩니다.


서비스 호스팅

WCF 서비스를 호스팅하려면 ServiceHost 컨테이너 내에서 실행해야 합니다.

WCF를 사용하여 호스팅하는 방법을 검토하기에 앞서 선택할 수 있는 대안에 대해 살펴보겠습니다.

  • 표준 Windows 프로세스에서는 ServiceHost 인스턴스를 수동으로 만들고 열 수 있습니다.
  • Microsoft 인터넷 정보 서비스(IIS) 6.0을 통해 웹 끝점(웹 서비스)을 호스팅하는 경우 System.ServiceModel 네임스페이스에서 제공되는 사용자 지정 HttpHandler를 사용합니다.
  • IIS 7에서 호스팅하는 경우에는 WAS(Windows Activation Service)를 사용하여 끝점을 호스팅할 수 있습니다.

일반적으로 웹 서비스를 구축하는 경우에는 인터넷 정보 서비스를 사용하여 호스팅하는 방법을 선택하고, 디먼 역할을 하는 단일 인스턴스 끝점을 구축하는 경우에는 Windows 서비스를 사용하여 호스팅하는 방법을 선택합니다.

예제에서는 Windows 콘솔 응용 프로그램 내에서 주 서비스 인스턴스를 호스팅하는데, 이는 Windows 서비스를 호스팅하는 방식과 비슷합니다.

서비스를 배포하려면 ServiceHost 클래스의 인스턴스를 만들고 게시하려는 각 서비스 유형에 대해 이 인스턴스의 끝점을 엽니다. ServiceHost는 생성자의 일부로 여러 인수를 취하지만 가장 중요한 인수는 Type 인수 또는 ServiceContract를 구현하는 클래스의 인스턴스입니다.

  • PerCall 또는 PerSession 인스턴스를 사용하려는 경우에는 Type을 사용합니다.
  • Single 인스턴스를 사용하는 경우에는 단일 인스턴스를 사용하십시오.

WCF 내의 인스턴스 및 동시성에 대한 자세한 내용은 MSDN Library의 Sessions, Instancing, and Concurrency (영문)를 참조하십시오.

호스트가 설정된 후에는 사용할 수 있는 모든 구성을 구문 분석하고(이에 대한 자세한 내용은 배포 구성 섹션 참조) 이를 명시적으로 추가된 구성과 병합하여 사용할 수 있는 끝점을 확인한 다음 게시를 위해 이 끝점을 엽니다. 클라이언트에서 호출을 수신하면 요청은 새로운 백그라운드 작업자 스레드에서 처리되며, 메시지의 SOAP 계약 이름 및 작업에서 지정된 대로 적절한 서비스 작업으로 라우팅됩니다.

using (ServiceHost serviceHost = new ServiceHost(new ExpenseService()))
{
   WfWcfExtension wfWcfExtension =
      new WfWcfExtension("WorkflowRuntimeConfig");
   serviceHost.Extensions.Add(wfWcfExtension);
   serviceHost.Open();

   // 이 시점에서 프로세스를 차단합니다(예:Console.ReadLine();).

   serviceHost.Close();
}

ServiceHost 구성은 연결에 대한 끝점을 열기 전에 수행해야 합니다. 앞에서 보았듯이 이를 위해서는 .Open()을 호출하기 전에 호스트 개체와 상호 작용합니다. using 범위를 사용하여 ServiceHost를 사용하기 전에 삭제되도록 하고, 이 범위 끝에 명시적으로 Close()를 호출하여 모든 활성 연결 및 끝점을 깔끔하게 종료하는 것이 좋습니다.


배포 구성

WCF는 XML 구성을 통해 끝점을 구성할 수 있도록 함으로써 구현에서 배포 문제를 분리하는 메커니즘을 제공합니다. 이로써 관리자는 코드를 다시 개발하지 않고도 서비스 정책을 수정할 수 있습니다.

각 서비스는 한 개 이상의 끝점에 배포됩니다. 간단히 말해 끝점은 클라이언트가 서비스를 사용할 수 있는, 주소 지정이 가능한 연결 지점입니다. WCF에서 각 끝점은 WCF의 기초로 잘 알려진 세 가지 특성으로 선언됩니다.

이 세 특성은 Address, BindingContract입니다.

Address: 주소 지정이 가능한 이 끝점의 고유한 위치입니다. 일반적으로 서비스가 요청을 수신하는 위치의 절대 주소를 가리키는 URI입니다(예: http://myhost/myservice 또는 net.tcp://myhost:400/myservice).

Binding: 서비스와 소비자 간의 통신을 위한 프로토콜을 결정하는 정책입니다. Binding은 사용되는 전송 유형, 메시지 인코딩 방법 및 데이터를 serialize하는 방법과 같은 측면을 지정합니다. WCF에는 대부분의 일반적인 시나리오를 지원하는 즉시 사용 가능한 바인딩이 다수 포함되어 있습니다.

Contract: 코드에서 인터페이스를 통해 정의한 대로 게시되는 작업 및 데이터입니다.

서비스를 구성하려면 서비스를 선언하는 구성을 선언하고 해당 서비스에 대한 끝점을 모두 구성해야 합니다. 서비스에서 구현할 수 있는 계약의 수에는 제한이 없기 때문에 사용자가 게시해야 하는 끝점의 수도 여기에 맞춰 결정됩니다.

다음은 구성 예제입니다.

<services>
   <service name="ExpenseServices.ExpenseService">
      <endpoint
         address="http://localhost:8081/ExpenseService/Manager"
         binding="wsHttpBinding"
         contract="ExpenseContracts.IExpenseServiceManager" />
<endpoint
         address="http://localhost:8081/ExpenseService/Client"
         binding="wsDualHttpBinding"
         contract="ExpenseContracts.IExpenseServiceClient" />
   </service>
</services>

이 구성 예제에서는 ExpenseServices.ExpenseService 유형의 서비스에 대해 구성을 선언합니다. 이렇게 하면 이 유형을 기반으로 새 ServiceHost를 인스턴스화할 때 런타임에서 구성을 찾을 수 있습니다. 바인딩에 대한 자세한 내용은 MSDN Library의 WCF Bindings (영문)를 참조하십시오.


서비스 사용

WCF를 통한 서비스 사용은 ChannelFactory 클래스를 사용하여 수행됩니다. ChannelFactory는 구성에 지정된 끝점에 연결하는 서비스 계약의 프록시 인스턴스를 제공하기 위해 팩토리 패턴을 사용합니다. 메시지 암호화를 위한 보안 자격 증명 및 인증서와 같은 런타임 정보를 사용하거나 동적으로 끝점 정보를 확인하도록 팩토리를 구성할 수 있습니다.

private IExpenseServiceManager CreateChannelExpenseServiceManager()
{
   ChannelFactory<IExpenseServiceManager> factory = new
ChannelFactory<IExpenseServiceManager>("ExpenseServiceManager");
   IExpenseServiceManager proxy = factory.CreateChannel();

   return proxy;
}

여기에서 볼 수 있듯이 처음에 팩토리의 인스턴스를 만듭니다. 이 인스턴스는 서비스 계약에 대한 제네릭 인수를 사용하므로 원하는 계약의 인스턴스만 반환하는 더 정확한 팩토리를 만들 수 있습니다. 끝점에 사용될 구성을 결정하는 인수도 지정합니다. 이 경우에는 응용 프로그램 구성 파일에 있는 구성을 참조하는 ExpenseServiceManager라는 이름의 끝점 구성을 사용합니다.

<system.serviceModel>
   <client>
         <endpoint name="ExpenseServiceManager"
            address="http://localhost:8081/ExpenseService/Manager"
            binding="wsHttpBinding"
            contract="ExpenseContracts.IExpenseServiceManager" />
   </client>
</system.serviceModel>

끝점 정의가 호스트의 구성에 선언된 정의와 정확하게 일치하는 것을 알 수 있습니다. 일반적으로 구성이 다른 유일한 경우는 네트워크 구성이나 사용자 지정 동작이 구현되고 있어 클라이언트와 서버 간의 주소가 다를 때입니다.

Windows SDK를 설치했다면 프록시 클래스 및 끝점 구성 생성을 자동화하며 사용자의 솔루션으로 통합 가능한 도구(svcutil)를 사용할 수 있습니다. 이 도구를 활용하려면 대상 서비스가 WSDL 또는 WS-MetadataExchange를 통해 메타데이터 설명을 게시해야 합니다.


이중 채널 구성

지금까지는 통신 흐름이 소비자가 메시지를 보내고 서비스가 이에 응답하는 요청 응답 공동 작업 패턴을 사용한다고 가정했습니다. WCF는 이외에도 단방향(전송한 후 더 이상 추적하지 않음) 또는 양방향 이중 통신과 같은 여러 가지 다른 메시지 흐름을 지원합니다. 어느 쪽에서든 대화를 시작할 수 있는 메시지 흐름을 다루는 경우에는 이중 또는 양방향 채널을 사용해야 합니다. 이중 채널은 어느 쪽에서든 데이터를 전송할 수 있는 강력하게 연결된 시스템에서 매우 효과적입니다. 이 채널을 유용하게 활용할 수 있는 예는 이벤트에서 콜백을 제공하는 경우입니다.


클라이언트 콜백 구현

WCF에서 클라이언트 콜백은 CallbackContracts라고 하는 개념을 통해 구현됩니다. 여기서 게시하는 계약의 경우 클라이언트가 게시할 작업을 정의하는 두 번째 계약을 지명할 수 있으며, 이는 서비스에서 실행되는 코드를 사용하여 콜백할 수 있습니다.

CallbackContract를 선언하려면 인터페이스 유형을 콜백하려는 서비스 계약의 일부로 지정합니다.

[ServiceContract(CallbackContract = 
typeof(IExpenseServiceClientCallback))]

또한 netTcpBinding 또는 wsDualHttpBinding과 같이 이중 채널을 지원하는 바인딩을 사용해야 합니다. TCP를 통한 이중 통신은 메시지 교환이 이루어지는 동안 설정 및 유지되는 양방향 연결을 통해 이루어집니다. HTTP를 통한 통신은 클라이언트 수신기에 대한 콜백에 의해 수행됩니다. 클라이언트가 반환 경로를 인식하지 못하는 경우도 있고, 사용자가 구성을 통해 이를 엄격하게 정의하려는 경우도 있으므로 사용자 지정 바인딩 구성을 사용하여 대체 clientBaseAddress를 선언할 수 있습니다.

<endpoint binding="wsDualHttpBinding" 
bindingConfiguration="AlternativeClientCallback"/>
<bindings>
   <wsDualHttpBinding>
      <binding name="AlternativeClientCallback" 
clientBaseAddress="http://localhost:8082/ExpenseService/ClientCallback"/>
   </wsDualHttpBinding>
</bindings>

클라이언트에서 콜백 구현

콜백 계약 구현은 서비스 계약 구현과 완전히 동일합니다. 정의한 인터페이스의 구현을 제공해야 합니다.

class CallbackHandler : IExpenseServiceClientCallback
{
   public void ExpenseReportReviewed(
ExpenseReportReviewedRequest expenseReportReviewedRequest)
        {
            // 여기에서 콜백에 응답하기 위한 클라이언트 논리를 구현합니다.
        }
}

호스트가 콜백할 CallbackHandler 클래스 인스턴스를 갖도록 하려면 연결의 이중 특성을 인식하도록 클라이언트 채널을 설정해야 합니다.

우선 앞서 설명한 대로 이중 채널을 지원하는 바인딩을 사용합니다. 다음으로, 서비스 끝점에 대한 연결을 초기화할 때 서비스에 대한 이중 연결을 만드는 DuplexChannelFactory라는 ChannelFactory의 하위 클래스 버전을 사용합니다.

private IExpenseServiceClient CreateChannelExpenseServiceClient()
{
   InstanceContext context = new InstanceContext(new CallbackHandler());

   DuplexChannelFactory<IExpenseServiceClient> factory =
new DuplexChannelFactory<IExpenseServiceClient>(context, 
"ExpenseServiceClient");
   IExpenseServiceClient proxy = factory.CreateChannel();

   return proxy;
}

DuplexChannelFactory를 사용할 때 중요한 차이점은 CallbackHandler 클래스의 인스턴스를 초기화하고 이를 팩토리의 생성자에 전달하여 콜백에 사용될 컨텍스트를 초기화한다는 것입니다.


호스트에서 콜백 구현

호스트의 관점에서는 IExpenseServiceClient 계약에 정의된 콜백 채널을 통해 클라이언트로의 콜백에 대한 참조를 얻을 수 있습니다.

[ServiceContract(CallbackContract = 
typeof(IExpenseServiceClientCallback))]
public interface IExpenseServiceClient : IExpenseService

CallbackContract 특성은 호스트에서 이루어지는 콜백에 대한 계약을 정의하는 인터페이스를 선언합니다.

콜백을 수행하려면 다음과 같이 OperationContext.Current.GetCallbackChannel을 호출하여 콜백 계약에 대한 참조를 가져옵니다.

IExpenseServiceClientCallback callback =
                   OperationContext.Current.GetCallbackChannel
<IExpenseServiceClientCallback>();
callback.ExpenseReportReviewed(new 
ExpenseReportReviewedRequest(e.Report));

콜백 채널에 대한 참조를 가져온 다음에는 정상적으로 이를 호출할 수 있습니다.


결론

Windows Workflow Foundation은 워크플로 정의를 위한 범용 프레임워크와 실행 중인 워크플로를 호스팅하고 이 워크플로와 상호 작용할 수 있는 강력한 런타임 엔진을 제공합니다.

Windows Communication Foundation은 연결된 시스템을 구축하기 위한 범용 프레임워크를 제공하며, 통신 방법을 정의하기 위한 일관성 있는 API와 광범위한 기능 집합을 개발자에게 제공합니다.

이 두 가지 프레임워크를 함께 사용하면 현재 환경 내에서 분산 비즈니스 프로세스를 구축 및 배포하기 위한 유연하고 포괄적인 응용 프로그램 플랫폼을 제공할 수 있습니다. WF는 비즈니스 논리 및 프로세스를 모델링하고 캡슐화할 수 있도록 하며 WCF는 시스템 분산의 매개체가 되는 메시징 인프라를 제공합니다.

다음은 서비스를 설계할 때 기억해야 할 몇 가지 지침입니다.

  • 장시간 실행되는 워크플로는 지속성 서비스를 사용하여 제공해야 합니다.
  • 서비스 작업은 이벤트 발생을 통해 실행 중인 워크플로에서 상호 작용이 가능합니다. 워크플로는 사용자의 주의가 필요할 때 이벤트를 발생시키고, 외부(예: 외부 서비스 또는 사용자)와 상호 작용할 때 이벤트에 응답하도록 설계되어야 합니다.
  • 워크플로는 서비스 호출과 비동기적으로 실행되므로 어느 시점에 서비스 데이터를 반환해야 하고 해당 시점에서의 데이터 상태는 어떠한지 고려하여 이에 맞게 적절히 설계해야 합니다. 동기적 방식을 원하는 경우에는 ManualWorkflowSchedulerService 클래스를 사용하여 워크플로 실행을 수동으로 예약하도록 할 수 있습니다.

추가 정보

  1. Sessions, Instancing, and Concurrency (영문)
  2. WCF Bindings (영문)
  3. Using Data Contracts (영문)
  4. Using Message Contracts (영문)
  5. .NET Framework 3.0 커뮤니티 사이트 (영문)
  6. Windows Workflow Foundation 포럼 (영문)

감사의 글

다음의 기고가 및 검토자 분들의 노고에 감사드립니다.

  • Christian Weyer, thinktecture
  • Paul Andrew, Microsoft Corporation
  • Khalid Aggag, Microsoft Corporation
  • Patrice Manac'h, Microsoft Corporation

저자 소개

Jeremy Boyd는 뉴질랜드 소재의 솔루션 공급업체이자 Microsoft Gold Certified Partner인 Intergen에서 선임 기술 컨설턴트로 근무하고 있으며 뉴질랜드 커뮤니티의 MSDN 지역 책임자이기도 합니다. Jeremy는 지난 12개월 동안 고객과 함께 WF 및 WCF 기반 솔루션을 구현하는 작업을 진행해 왔으며, 이러한 기술의 장점을 배우려는 다른 개발자들을 자신의 블로그 (영문)를 통해 돕고 있습니다.


|
Windows Communication Foundation과의 관계로 보는 ASP.NET 웹 서비스의 미래

Craig McMurtry
기술 전도사(Technical Evangelist)
Microsoft Corporation

업데이트한 날짜: 2006년 7월

적용 대상:
Microsoft ASP.NET 2.0
Windows Communication Foundation
인터넷 정보 서비스(IIS)
웹 서비스 사양

목차

의사 결정권자를 위한 조언
기술 비교: 목적
기술 비교: 표준
기술 비교: 개발
내부 아키텍처
Windows Communication Foundation 채택을 위한 사전 준비: 향후 통합 간소화
Windows Communication Foundation 채택을 위한 사전 준비: 향후 마이그레이션 간소화
Windows Communication Foundation 채택
요약

요약:이 기사에서는 ASP.NET 웹 서비스와 Windows Communication Foundation을 비교하며, Windows Communication Foundation의 발표를 앞둔 시점에서 이미 사용 중이거나 계획 단계에 있는 ASP.NET 웹 서비스를 어떻게 처리해야 하는지에 대해 설명합니다.

ASP.NET은 웹 서비스를 빌드하기 위한 .NET Framework 클래스 라이브러리와 도구뿐만 아니라 인터넷 정보 서비스(IIS) 내에서 이러한 웹 서비스를 호스트하기 위한 기능도 제공합니다. Indigo라는 코드명의 Windows Communication Foundation은 소프트웨어 엔터티가 웹 서비스에서 사용되는 프로토콜을 포함한 모든 프로토콜을 사용하여 통신할 수 있도록 하는 .NET 클래스 라이브러리, 도구 및 호스팅 기능을 제공합니다. 이처럼 웹 서비스 빌드를 위한 더욱 새롭고 포괄적인 기술이 등장하고 있는 시점에서 ASP.NET 웹 서비스에 대한 전망을 알아보도록 하겠습니다.

이 문서에서는 두 가지 기술을 비교하고, ASP.NET 웹 서비스 응용 프로그램을 Windows Communication Foundation 응용 프로그램과 함께 사용할 수 있는 방법에 대해 설명합니다. 또한 ASP.NET 웹 서비스를 Windows Communication Foundation으로 마이그레이션하기 위한 준비 방법과 실제로 마이그레이션을 수행하는 방법을 설명합니다.

이 문서에서는 ASP.NET에서 웹 서비스를 빌드하기 위해 제공하는 기능과 Microsoft .NET용 Web Services Enhancements(WSE)를 별개로 취급합니다. WSE를 사용하여 개발된 응용 프로그램에 대한 전망은 다른 곳에서 살펴볼 것입니다.

의사 결정권자를 위한 조언

Windows Communication Foundation은 2006년 하반기에 발표될 예정입니다. Windows Communication Foundation에는 이전 기술인 ASP.NET 웹 서비스와 비교하여 중요한 몇 가지 이점이 있습니다. ASP .NET 웹 서비스를 사용하는 조직에서는 이러한 이점을 고려해야 합니다.

ASP.NET 웹 서비스 도구는 단지 웹 서비스를 빌드하기 위한 것이지만, Windows Communication Foundation은 소프트웨어 엔터티들이 서로 통신하도록 설정되어야 하는 모든 환경에서 사용할 수 있는 도구를 제공합니다. 이는 개발자가 다양한 소프트웨어 통신 시나리오를 적용하기 위해 알아야 하는 기술의 가짓수를 줄여 주며, 따라서 소프트웨어 개발 리소스 비용과 소프트웨어 개발 프로젝트를 완성하는 데 소요되는 시간도 줄여 줍니다.

웹 서비스 개발 프로젝트의 경우에도 Windows Communication Foundation은 ASP.NET 웹 서비스에서 지원하는 것보다 훨씬 많은 웹 서비스 프로토콜을 지원합니다. 이러한 프로토콜은 신뢰할 수 있는 세션과 트랜잭션을 비롯한 여러 가지 장점을 수반하는, 더욱 정교한 솔루션을 제공합니다.

Windows Communication Foundation은 ASP.NET 웹 서비스에서 지원하는 것보다 훨씬 많은 메시지 전송 프로토콜을 지원합니다. ASP.NET 웹 서비스는 HTTP(Hypertext Transfer Protocol)를 통한 메시지 전송만 지원합니다. 그러나 Windows Communication Foundation은 HTTP뿐만 아니라 TCP(Transmission Control Protocol), 명명된 파이프 및 MSMQ(Microsoft Message Queuing)를 통한 메시지 전송도 지원합니다. 더욱 중요한 사실은 Windows Communication Foundation은 추가되는 전송 프로토콜을 지원하도록 즉시 확장 가능하다는 점입니다. 따라서 Windows Communication Foundation을 사용하여 개발된 소프트웨어는 다양한 다른 소프트웨어와 함께 작동하도록 손쉽게 확장할 수 있어 잠재적 투자 수익을 높여 줍니다.

Windows Communication Foundation은 ASP.NET 웹 서비스에서 제공하는 것보다 훨씬 더 풍부한 응용 프로그램 배포 및 관리 기능을 제공합니다. ASP.NET에도 있는 구성 시스템 외에도 Windows Communication Foundation은 구성 편집기, 원하는 수의 중간 단계를 통한 송수신자 간 활동 추적, 추적 뷰어, 메시지 로깅, 많은 수의 성능 카운터 및 WMI(Windows Management Instrumentation) 지원을 제공합니다. 이처럼 풍부한 관리 도구를 사용하면 운영 비용, 실패 위험 및 실제 가동 중단 시간을 줄일 수 있습니다.

ASP.NET 웹 서비스에 대한 Windows Communication Foundation의 이러한 잠재적 이점을 고려할 때, ASP.NET 웹 서비스를 사용하고 있거나 사용할 예정인 조직에서는 다음과 같은 선택을 할 수 있습니다.

  • ASP.NET 웹 서비스를 계속 사용하고 Windows Communication Foundation에서 제공하는 이점은 무시합니다. Microsoft의 현재 지원 주기 정책 하에서 ASP.NET 웹 서비스에 대한 기본 지원은 2011년까지, 확장 지원은 2016년까지 제공됩니다. 따라서 ASP.NET 웹 서비스를 계속 사용하더라도 큰 위험은 없습니다.
  • 미래의 어느 시점에 Windows Communication Foundation을 채택할 의향을 갖고 ASP.NET 웹 서비스를 계속 사용합니다. 이 문서에서는 새로운 ASP.NET 웹 서비스 응용 프로그램을 미래의 Windows Communication Foundation 응용 프로그램과 함께 사용할 수 있는 가능성을 최대화하는 방법에 대해 설명합니다. 또한 Windows Communication Foundation으로 더 쉽게 마이그레이션할 수 있도록 새 ASP.NET 웹 서비스를 빌드하는 방법도 설명합니다. 그러나 서비스 보안이 중요하거나 신뢰성 또는 트랜잭션 보증이 필요하거나 사용자 지정 관리 기능을 구성해야 한다면 Windows Communication Foundation 채택을 연기하는 것은 잘못된 결정입니다. Windows Communication Foundation은 정확히 이러한 시나리오를 위해 설계되었으며, 기술에 대한 생산 라이선스는 이미 제공되고 있습니다.
  • 기존 ASP.NET 웹 서비스 응용 프로그램을 계속 유지하면서 새로운 개발에는 Windows Communication Foundation을 채택합니다. 대부분의 경우 이것이 최적의 선택입니다. Windows Communication Foundation의 이점을 누리면서 이를 사용하기 위해 기존 응용 프로그램을 수정해야 하는 비용은 절약할 수 있기 때문입니다. 이 시나리오에서는 새 Windows Communication Foundation 응용 프로그램과 기존 ASP.NET 응용 프로그램이 공존할 수 있습니다. 또한 새 Windows Communication Foundation 응용 프로그램에서 기존 ASP.NET 웹 서비스를 사용할 수 있으며, Windows Communication Foundation의 ASP.NET 호환 모드를 통해 Windows Communication Foundation을 사용하여 기존 ASP.NET 응용 프로그램에 새 작업 기능을 프로그래밍할 수도 있습니다.
  • Windows Communication Foundation을 채택하고 기존 ASP.NET 웹 서비스 응용 프로그램을 Windows Communication Foundation으로 마이그레이션합니다. 조직에서는 개발자들이 ASP.NET 웹 서비스에 대해 알아야 할 필요가 없도록 하기 위해 이 옵션을 선택할 수 있습니다. 그러나 최신 기술 외의 다른 기술에 대한 지원을 배제한다는 것은 비현실적이며, 따라서 이 옵션을 선택하는 이유로는 적절하지 않습니다. Windows Communication Foundation에서 제공되는 기능으로 기존 응용 프로그램이 향상되거나, 기존 ASP.NET 웹 서비스의 기능을 더욱 강력한 새 Windows Communication Foundation 응용 프로그램으로 다시 만드는 경우에만 마이그레이션을 하는 것이 좋습니다. 이 문서에서는 마이그레이션 방법에 대해 설명합니다.
기술 비교: 목적

ASP.NET 웹 서비스 기술은 SOAP(Simple Object Access Protocol) over HTTP를 통해 메시지를 송수신하는 응용 프로그램을 빌드하기 위해 개발되었습니다. 메시지의 구조는 XML 스키마를 사용하여 정의할 수 있으며 .NET 개체와 주고 받는 메시지를 용이하게 serialize할 수 있는 도구가 제공됩니다. 이 기술을 사용하면 웹 서비스를 WSDL(Web Services Description Language)로 설명하는 메타데이터를 자동으로 생성할 수 있으며, WSDL에서 웹 서비스용 클라이언트를 생성하는 보조 도구가 제공됩니다.

Windows Communication Foundation은 .NET 응용 프로그램에서 다른 소프트웨어 엔터티와 메시지를 교환할 수 있도록 하기 위한 것입니다. 기본적으로 SOAP가 사용되지만 메시지는 모든 형식을 가질 수 있으며 모든 전송 프로토콜을 통해 전달될 수 있습니다. 메시지의 구조는 XML 스키마를 사용하여 정의할 수 있으며 .NET 개체와 주고 받는 메시지를 serialize할 수 있는 다양한 옵션이 제공됩니다. Windows Communication Foundation은 이 기술을 사용하여 빌드되는 웹 서비스를 WSDL로 설명하는 메타데이터를 자동으로 생성할 수 있으며, WSDL에서 그러한 응용 프로그램을 위한 클라이언트를 생성하는 도구도 제공합니다.

기술 비교: 표준

ASP.NET 웹 서비스에서 지원되는 표준 목록은 XML Web Services Created Using ASP.NET (영문)을 참조하십시오.

Windows Communication Foundation에서 지원되는 표준에 대한 자세한 목록은 Web Services Protocols Supported in WCF (영문)를 참조하십시오.

기술 비교: 개발

ASP.NET 호환 모드

Windows Communication Foundation에는 특정 Windows Communication Foundation 응용 프로그램을 ASP.NET 웹 서비스처럼 프로그래밍하고 구성하며 동작을 모방할 수 있는 ASP.NET 호환 모드 옵션이 있습니다. 아래에서는 ASP.NET 호환 모드를 채택하는 방법에 대해 설명하며, 이러한 옵션이 정확히 어떤 효과를 내는지에 대한 자세한 정보를 제공합니다.

데이터 표현

ASP.NET으로 웹 서비스를 개발하는 경우 일반적으로 서비스에서 사용할 복합 데이터 형식을 정의하는 것부터 시작합니다. ASP.NET에서는 System.Xml.Serialization.XmlSerializer를 사용하여 .NET 개체로 표현된 데이터를 서비스와 주고 받을 XML로 변환하고 XML로 수신된 데이터를 .NET 개체로 변환합니다. 따라서 ASP.NET 서비스에서 사용할 복합 데이터 형식을 정의할 경우 System.Xml.Serialization.XmlSerializer를 통해 XML로 또는 XML에서 serialize할 수 있는 .NET 클래스에 대한 정의가 필요합니다. 물론 이러한 클래스를 수동으로 작성하거나 명령줄 XML 스키마/데이터 형식 지원 유틸리티인 xsd.exe를 사용하여 XML 스키마의 형식 정의에서 생성할 수 있습니다.

System.Xml.Serialization.XmlSerializer를 통해 XML로, 또는 XML에서 serialize할 수 있는 .NET 클래스의 정의에 대해 알아야 하는 주요 사항은 다음과 같습니다.

  • .NET 개체의 공용 필드와 속성만 XML로 변환됩니다.
  • 클래스에서 IEnumerable 또는 ICollection 인터페이스를 구현하는 경우에만 컬렉션 클래스의 인스턴스를 serialize할 수 있습니다.
  • 그 결과 System.Collections.Hashtable과 같은 System.Collections.IDictionary 인터페이스를 구현하는 클래스는 XML로 serialize할 수 없습니다.
  • 클래스의 인스턴스가 XML로 표현되는 방식을 정확히 제어하기 위해 System.Xml.Serialization 네임스페이스의 많은 특성 형식을 .NET 클래스 및 그 구성원에 추가할 수 있습니다.

Windows Communication Foundation 응용 프로그램 개발 역시 대개 복합 형식을 정의하는 것부터 시작합니다. Windows Communication Foundation은 ASP.NET 웹 서비스와 같은 .NET 형식을 사용하도록 만들 수 있지만 더 나은 다른 방법이 제공됩니다.

Windows Communication Foundation System.Runtime.Serialization 어셈블리의 System.Runtime.Serialization.DataContractSystem.Runtime.Serialization.DataMember 특성을 .NET 형식에 추가하여 해당 형식의 인스턴스가 XML로 serialize된다는 점을 표시하고 이 형식에서 serialize되는 특정 필드 또는 속성을 표시할 수 있습니다. 다음의 세 가지 예제는 모두 유효합니다.

//예제 1: 
[DataContract]
public class LineItem
{
    [DataMember]
    public string ItemNumber;
    [DataMember]
    public decimal Quantity;
    [DataMember]
    public decimal UnitPrice;
}

//예제 2: 
public class LineItem
{
    [DataMember]
    private string itemNumber;
    [DataMember]
    private decimal quantity;
    [DataMember]
    private decimal unitPrice;

    public string ItemNumber
    {
        get
        {
            return this.itemNumber;
        }

        set
        {
            this.itemNumber = value;
        }
    }

    public decimal Quantity
    {
        get
        {
            return this.quantity;
        }

        set
        {
            this.quantity = value;
        }
    }

    public decimal UnitPrice
    {
        get
        {
            return this.unitPrice;
        }

        set
        {
            this.unitPrice = value;
        }
    }
}

//예제 3: 
public class LineItem
{
    private string itemNumber;
    private decimal quantity;
    private decimal unitPrice;

    [DataMember]
    public string ItemNumber
    {
        get
        {
            return this.itemNumber;
        }

        set
        {
            this.itemNumber = value;
        }
    }

    [DataMember]
    public decimal Quantity
    {
        get
        {
            return this.quantity;
        }

        set
        {
            this.quantity = value;
        }
    }

    [DataMember]
    public decimal UnitPrice
    {
        get
        {
            return this.unitPrice;
        }

        set
        {
            this.unitPrice = value;
        }
    }
}

System.Runtime.Serialization.DataContract 특성은 형식의 필드 또는 속성을 0개 이상 serialize한다고 표시하지만 System.Runtime.Serialization.DataMember 특성은 특정 필드 또는 속성을 serialize한다고 표시합니다. System.Runtime.Serialization.DataContract 특성은 클래스 또는 구조체에 적용될 수 있습니다. System.Runtime.Serialization.DataMember 특성은 필드 또는 속성에 적용될 수 있으며, 이 특성이 적용되는 필드 및 속성은 공개 필드 및 속성이거나 개인 필드 및 속성일 수 있습니다. System.Runtime.Serialization.DataContract 특성을 가진 형식의 인스턴스는 Windows Communication Foundation 용어로 데이터 계약이라고 합니다. 이러한 인스턴스는 Windows Communication Foundation의 System.Runtime.Serialization.DataContractFormatter를 사용하여 XML로 serialize됩니다.

System.Runtime.Serialization.DataContractFormatter, System.Runtime.Serialization.DataContract, System.Runtime.Serialization.DataMember 특성은 System.Xml.Serialization.XmlSerializer와, 그리고 System.Xml.Serialization 네임스페이스의 다양한 특성과 어떻게 다를까요? 중요한 차이점이 많이 있습니다.

  1. System.Xml.Serialization.XmlSerializer와 System.Xml.Serialization 네임스페이스의 특성은 XML 스키마에 정의된 유효 형식에 .NET 형식을 매핑할 수 있도록 디자인되었으므로 .NET 형식의 XML 표현 방식을 매우 정확하게 제어할 수 있습니다. System.Runtime.Serialization.DataContractFormatter, System.Runtime.Serialization.DataContract, System.Runtime.Serialization.DataMember 특성은 .NET 형식의 XML 표현 방식에 대한 제어를 극히 제한적으로 제공합니다. 형식 및 해당 필드 또는 속성을 XML로 표현하는 데 사용되는 네임스페이스와 이름, 그리고 필드와 속성이 XML로 나타나는 순서만 지정할 수 있습니다.
    [DataContract(
    Namespace="urn:Woodgrove:2006:January:29",
    Name="LineItem")]
    public class LineItem
    {
        [DataMember(Name="ItemNumber",IsRequired=true,Order=0)]
        public string itemNumber;
        [DataMember(Name="Quantity",IsRequired=false,Order = 1)]
        public decimal quantity;
        [DataMember(Name="Price",IsRequired=false,Order = 2)]
        public decimal unitPrice;
    }

    .NET 형식을 표현하는 데 사용되는 XML 구조에 관한 다른 모든 요소는 System.Runtime.Serialization.DataContractFormatter로 결정됩니다.

  2. .NET 형식을 XML로 표현하는 방식에 대해 많은 제어를 허용하지 않기 때문에 System.Runtime.Serialization.DataContractFormatter에 대해 serialize 프로세스의 예측이 매우 쉽고, 따라서 최적화가 더 용이합니다. 결과적으로 System.Runtime.Serialization.DataContractFormatter 디자인의 실질적 이점은 약 10% 정도의 성능 향상에 있습니다.
  3. 다음의 두 형식을 비교해 보십시오. 아래의 첫 번째 형식에는 System.Xml.Serialization.XmlSerializer에 의한 serialize 특성이 있습니다.
    [Serializable]
    [XmlRoot(Namespace="urn:Woodgrove:2006:January:29")]
    public class LineItem
    {
        public string ItemNumber;
        public decimal Quantity;
        public decimal UnitPrice;
    } 

    아래의 두 번째 형식에는 System.Runtime.Serialization.DataContractFormatter에서 사용하는 특성이 있습니다.

    [DataContract(Namespace="urn:Woodgrove:2006:January:29")]
    public class LineItem
    {
        [DataMember]
        public string ItemNumber;
        [DataMember]
        public decimal Quantity;
        [DataMember]
        public decimal UnitPrice;
    } 

    System.Xml.Serialization.XmlSerializer에서 사용하는 특성은 XML로 serialize될 형식의 필드 또는 속성을 표시하지 않지만, System.Runtime.Serialization.DataContractFormatter에서 사용하는 System.Runtime.Serialization.DataMember 특성은 serialize될 필드 또는 속성을 명시적으로 보여 줍니다. 따라서 데이터 계약은 응용 프로그램에서 송수신할 데이터의 구조에 관한 명시적 계약이라고도 할 수 있습니다.

  4. System.Xml.Serialization.XmlSerializer는 .NET 개체의 공개 구성원만 XML로 변환할 수 있지만 System.Runtime.Serialization.DataContractFormatter는 .NET 개체의 구성원에 대한 액세스 한정자와 관계없이 이러한 구성원을 XML로 변환할 수 있습니다.
  5. 형식의 비공개 구성원을 XML로 serialize할 수 있기 때문에 System.Runtime.Serialization.DataContractFormatter에는 XML로 serialize할 수 있는 .NET 형식의 다양성에 대한 제한이 더 적습니다. 특히 Systems.Collections.IDictionary 인터페이스를 구현하는 System.Collections.Hashtable과 같은 XML 형식으로 변환할 수 있습니다. 일반적으로 System.Runtime.Serialization.DataContractFormatter는 형식의 정의를 수정하거나 형식을 위한 래퍼를 개발하지 않고도 기존 .NET 형식의 인스턴스를 serialize할 수 있는 가능성이 훨씬 더 높습니다.
  6. 그러나 System.Runtime.Serialization.DataContractFormatter가 형식의 비공개 구성원에 액세스할 수 있다는 점에 기인한 또 다른 결과는 System.Xml.Serialization.XmlSerializer와 달리 완전 신뢰가 필요하다는 점입니다.
  7. System.Runtime.Serialization.DataContractFormatter는 버전 관리를 위한 일부 지원을 통합하고 있습니다.
    • System.Runtime.Serialization.DataMember 특성에는 IsRequired 속성이 있습니다. 이 속성에는 새 버전의 데이터 계약에 추가된, 이전 버전에는 없었던 구성원에 대해 false 값을 지정할 수 있기 때문에 새 버전의 데이터 계약이 있는 응용 프로그램에서 이전 버전을 처리할 수 있습니다.
    • 데이터 계약에서 간단한 System.Runtime.Serialization.IExtensibleDataObject 인터페이스를 구현하도록 함으로써 System.Runtime.Serialization.DataContractFormatter가 새 버전의 데이터 계약에 정의된 구성원을 이전 버전의 데이터 계약을 사용하는 응용 프로그램을 통해 전달하도록 허용할 수 있습니다.

이러한 모든 차이점에도 불구하고 System.Xml.Serialization.XmlSerializer에서 기본적으로 형식을 serialize하는 XML은 해당 XML에 대한 네임스페이스가 명시적으로 정의되어 있는 경우 System.RuntimeSerialization.DataContractFormatter에서 형식을 serialize하는 XML과 의미상 동일합니다. 따라서 다음과 같이 두 serializer에서 사용하는 특성을 가지고 있는 클래스는 System.Xml.Serialization.XmlSerializer와 System.RuntimeSerialization.DataContractFormatter에서 의미상 동일한 XML로 변환됩니다.

[Serializable]
[XmlRoot(Namespace="urn:Woodgrove:2006:January:29")]
[DataContract(Namespace="urn:Woodgrove:2006:January:29")]
public class LineItem
{
    [DataMember]
    public string ItemNumber;
    [DataMember]
    public decimal Quantity;
    [DataMember]
    public decimal UnitPrice;
}

Windows Communication Foundation을 포함하고 있는 소프트웨어 개발 키트에는 서비스 모델 메타데이터 도구라고 하는 svcutil.exe 명령줄 도구가 있습니다. svcutil.exe는 ASP.NET 웹 서비스에서 사용되는 xsd.exe 도구와 마찬가지로 XML 스키마에서 .NET 데이터 형식의 정의를 생성할 수 있습니다. System.Runtime.Serialization.DataContractFormatter에서 XML 스키마에 의해 정의된 형식의 XML을 내보낼 수 있으면 이러한 .NET 데이터 형식은 데이터 계약이 됩니다. 그렇지 않으면 이러한 형식은 System.Xml.Serialization.XmlSerializer를 통해 seriallize됩니다. 또한 svcutil.exe 도구와 /dataContractOnly 스위치를 사용하여 데이터 계약에서 XML 스키마를 생성할 수도 있습니다.

ASP.NET 웹 서비스에서 System.Xml.Serialization.XmlSerializer를 사용하고, Windows Communication Foundation의 ASP.NET 호환 모드를 통해 Windows Communication Foundation 서비스에서 ASP.NET 웹 서비스의 동작을 모방하는 경우에도 ASP.NET 호환 옵션에서 System.Xml.Serialization.XmlSerializer를 사용하도록 제한되지는 않습니다. ASP.NET 호환 모드에서 실행하는 서비스에서 System.Runtime.Serialization.DataContractFormatter도 계속 사용할 수 있습니다.

서비스 개발

다음 예에서 볼 수 있는 것처럼, ASP.NET을 사용하여 서비스를 개발하는 통상적인 방법은 단순히 클래스에 System.Web.Services.WebService 특성을, 서비스의 작업이 되는 해당 클래스의 메서드에 System.Web.Services.WebMethod 특성을 추가하는 것입니다.

[WebService]
public class Service : System.Web.Services.WebService
{
    [WebMethod]
    public string Echo(string input) 
    {
        return input;
    }
}

ASP.NET 2.0에서는 다음과 같이 클래스가 아니라 인터페이스에 System.Web.Services.WebServiceSystem.Web.Services.WebMethod 특성을 추가하고 해당 인터페이스를 구현하는 클래스를 작성하는 옵션이 새로 제공됩니다.

[WebService]
public interface IEcho
{
    [WebMethod]
    string Echo(string input);
}

public class Service : IEcho
{

    public string Echo(string input)
    {
        return input;
    }
}

System.Web.Services.WebService 특성을 가진 인터페이스는 서비스에 의해 수행되는 작업에 대한 계약을 설정하며, 같은 계약을 다른 방식으로 구현하는 다양한 클래스에서 동일한 서비스를 다시 사용할 수 있으므로 이 옵션을 사용하는 것이 좋습니다.

Windows Communication Foundation 서비스는 Windows Communication Foundation 끝점을 하나 이상 정의함으로써 제공됩니다. 끝점은 주소, 바인딩 및 서비스 계약으로 정의됩니다. 주소는 서비스가 있는 위치를 정의합니다. 바인딩은 서비스와 통신하는 방법을 지정합니다. 서비스 계약은 서비스에서 수행할 수 있는 작업을 정의합니다.

일반적으로 서비스 계약은 다음과 같이 .NET 인터페이스에 System.ServiceModel.ServiceContractSystem.ServiceModel.OperationContract 특성을 추가함으로써 처음으로 정의됩니다.

[ServiceContract]
public interface IEcho
{
    [OperationContract]
    string Echo(string input);
}

System.ServiceModel.ServiceContract 특성은 인터페이스에서 Windows Communication Foundation 서비스 계약을 정의하도록 지정하고, System.ServiceModel.OperationContract 특성은 서비스 계약의 작업을 정의하는 인터페이스의 메서드가 있는 경우 해당 메서드를 나타냅니다.

서비스 계약은 일단 정의되면 다음과 같이 클래스가 서비스 계약을 정의하는 인터페이스를 구현하도록 함으로써 클래스에서 구현됩니다.

public class Service : IEcho
{
    
    public string Echo(string input)
    {
        return input;
    }
}

서비스 계약을 구현하는 클래스는 Windows Communication Foundation 용어로 서비스 형식이라고 합니다.

다음 단계는 주소와 바인딩을 서비스 형식과 연결하는 것입니다. 이 작업은 일반적으로 파일을 직접 편집하거나 Windows Communication Foundation에서 제공되는 구성 편집기를 사용하여 구성 파일에서 수행됩니다. 다음은 구성 파일 예제입니다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.serviceModel>
      <services>
         <service name="Service ">
            <endpoint 
               address="EchoService"
               binding="basicHttpBinding"
               contract="IEchoService "/>
         </service>
      </services>
   </system.serviceModel>
</configuration>

바인딩은 응용 프로그램과 통신하기 위한 프로토콜 집합을 지정합니다. 다음과 같이 일반 옵션을 나타내는 미리 정의된 여러 가지 바인딩이 있습니다.

이름 목적
BasicHttpBinding WS-Basic Profile 1.1과 Basic Security Profile 1.0을 지원하는 웹 서비스 및 클라이언트와의 상호 운용성
WSHttpBinding HTTP를 통한 WS-* 프로토콜을 지원하는 웹 서비스 및 클라이언트와의 상호 운용성
WSDualHttpBinding 이중 HTTP 통신(초기 메시지의 수신자가 초기 송신자에게 직접 응답하지 않고, 일정 기간에 걸쳐 WS-* 프로토콜을 따르는 HTTP를 통해 원하는 수의 응답을 전송할 수 있음)
WSFederationBinding HTTP 통신(명시적으로 식별된 자격 증명 제공자가 발행한 자격 증명에 따라 서비스의 리소스에 대한 액세스를 제어할 수 있음)
NetTcpBinding Windows Communication Foundation 소프트웨어 엔터티 간의 네트워크를 통한 안전하고 신뢰성 있는 고성능 통신
NetNamedPipeBinding 같은 컴퓨터에 있는 Windows Communication Foundation 소프트웨어 엔터티 간의 안전하고 신뢰할 수 있는 고성능 통신
NetMsmqBinding Windows Communication Foundation 소프트웨어 엔터티 간의 MSMQ를 통한 통신
MsmqIntegrationBinding Windows Communication Foundation 소프트웨어 엔터티와 다른 소프트웨어 엔터티 간의 MSMQ를 통한 통신
NetPeerTcpBinding Windows Communication Foundation 소프트웨어 엔터티 간의 피어-투-피어 네트워킹을 통한 통신

미리 정의된 바인딩인 System.ServiceModel.BasicHttpBinding은 ASP.NET 웹 서비스에서 지원되는 프로토콜 집합을 통합하고 있습니다.

Windows Communication Foundation 응용 프로그램용 사용자 지정 바인딩은 Windows Communication Foundation에서 개별 프로토콜을 구현하는 데 사용하는 바인딩 요소 클래스들의 컬렉션으로 간단히 정의할 수 있습니다. 새 바인딩 요소를 작성하여 추가 프로토콜을 나타낼 수 있습니다.

서비스 형식의 내부 동작은 behaviors라는 클래스 모음의 속성을 사용하여 조정할 수 있습니다. 다음 예제에서는 System.ServiceModel.ServiceBehavior 클래스를 사용하여 서비스 형식이 멀티스레드 형식이 되도록 지정합니다.

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple]
public class DerivativesCalculatorServiceType: IDerivativesCalculator

System.ServiceModel.ServiceBehavior와 같이 프로그래머가 설정할 수 있는 속성이 있는 일부 동작은 특성입니다. 관리자가 설정할 수 있는 속성이 있는 다른 동작은 응용 프로그램의 구성에서 수정할 수 있습니다.

서비스 형식 프로그래밍에서는 System.ServiceModel.OperationContext 클래스가 자주 사용됩니다. 이 클래스의 정적 Current 속성은 작업이 실행되고 있는 컨텍스트에 대한 정보로의 액세스를 제공합니다. 따라서 System.ServiceModel.OperationContext는 System.Web.HttpContext 및 System.EnterpriseServices.ContextUtil 클래스 모두와 비슷합니다.

호스팅

ASP.NET 웹 서비스는 클래스 라이브러리 어셈블리로 컴파일됩니다. 확장명이 .asmx인 서비스 파일이라는 파일이 제공됩니다. 이 파일에는 서비스에 대한 코드를 포함하고 있는 클래스 및 이 클래스가 있는 어셈블리를 식별하는 @ WebService 지시문이 있습니다.

<%@ WebService Language="C#" Class="Service,ServiceAssembly" %>

서비스 파일은 IIS의 ASP.NET 응용 프로그램 루트에 복사되며, 어셈블리는 이 응용 프로그램 루트의 \bin 하위 디렉터리에 복사됩니다. 그런 다음 응용 프로그램 루트에 있는 서비스 파일의 URL(Uniform Resource Locator)을 통해 이 응용 프로그램에 액세스할 수 있습니다.

Aaron Skonnard는 자신의 칼럼 (영문)에서 .NET Framework 2.0에서 제공되는 HttpListener 클래스를 사용하여 어떤 .NET 응용 프로그램에서든 IIS 외부에서 ASP.NET 웹 서비스를 호스트하는 방법에 대해 설명했습니다. 그러나 Skonnard는 이를 위한 작업은 '간단하지 않다'고 설명하고 있습니다. (영문)

Windows Communication Foundation 서비스는 IIS 5.1이나 6.0, IIS 7의 일부로 제공될 WAS(Windows Activation Service), 그리고 모든 .NET 응용 프로그램 내에서 즉시 호스트가 가능합니다. IIS 5.1 또는 6.0에서 서비스를 호스트하려면 이 서비스가 HTTP를 통신 전송 프로토콜로 사용해야 합니다.

IIS 5.1, IIS 6.0 또는 WAS에서 서비스를 호스트하려면 다음 단계를 따릅니다.

  1. 서비스 형식을 클래스 라이브러리 어셈블리로 컴파일합니다.
  2. 다음과 같은 서비스 형식을 식별하는 @ ServiceHost 지시문을 포함하는 서비스 파일을 확장명 .svc로 만듭니다.
    <%@ServiceHost language="c#" Service="MyService" %>
    
  3. 서비스 파일을 가상 디렉터리에 복사하고 어셈블리를 이 가상 디렉터리의 \bin 하위 디렉터리에 복사합니다.
  4. 구성 파일을 가상 디렉터리에 복사하고 파일 이름을 Web.config로 지정합니다.

그러면 응용 프로그램 루트에 있는 서비스 파일의 URL을 통해 해당 응용 프로그램에 액세스할 수 있습니다.

.NET 응용 프로그램에서 Windows Communication Foundation 서비스를 호스트하려면 서비스 형식을 이 응용 프로그램에서 참조하는 클래스 라이브러리 어셈블리로 컴파일하고, Windows Communication Foundation의 System.ServiceModel.ServiceHost 클래스를 사용하여 해당 서비스를 호스트하는 응용 프로그램을 프로그래밍합니다. 다음은 필요한 간단한 프로그래밍 예제입니다.

string httpBaseAddress = "http://www.woodgrove.com:8000/";
string tcpBaseAddress = "net.tcp://www.woodgrove.com:8080/";

Uri httpBaseAddressUri = new Uri(httpBaseAddress);
Uri tcpBaseAddressUri = new Uri(tcpBaseAddress);

Uri[] baseAdresses = new Uri[] { 
    httpBaseAddressUri,
    tcpBaseAddressUri};

using(ServiceHost host = new ServiceHost(
typeof(Service), //"Service" is the name of the service type    baseAdresses))
{
    host.Open();

    [...] //Wait to receive messages
    host.Close();
}

이 예제에서는 Windows Communication Foundation System.ServiceModel.ServiceHost 생성에서 하나 이상의 전송 프로토콜에 대한 주소가 지정되는 방식을 보여 줍니다. 이러한 주소를 기준 주소라고 합니다.

Windows Communication Foundation 서비스의 끝점에 제공되는 주소는 끝점의 호스트에 대한 기준 주소를 기준으로 하는 상대 주소입니다. 호스트에는 통신 전송 프로토콜당 하나의 기준 주소가 있을 수 있습니다. 끝점의 주소는 호스트의 기준 주소 중 끝점의 통신 전송 프로토콜에 대한 기준 주소의 상대 주소입니다. 위에 있는 구성 파일의 예제에서 끝점으로 선택된 System.ServiceModel.BasicHttpBinding은 HTTP를 전송 프로토콜로 사용하므로 EchoService 끝점의 주소는 호스트의 HTTP 기준 주소의 상대 주소입니다. 위 예제에서 호스트의 경우 HTTP 기준 주소는 http://www.woodgrove.com:8000/입니다. IIS 또는 WAS에서 호스트되는 서비스의 기준 주소는 해당 서비스에 대한 서비스 파일의 URL입니다.

IIS 또는 WAS에서 호스트되고 전송 프로토콜로 HTTP만 사용하도록 구성된 서비스만 Windows Communication Foundation의 ASP.NET 호환 모드 옵션을 사용하도록 만들 수 있습니다. 이 옵션을 사용하려면 다음의 두 단계가 필요합니다.

  1. 프로그래머는 다음과 같이 System.ServiceModel.AspNetCompatbilityRequirements 특성을 서비스 형식에 추가하여 ASP.NET 호환 모드가 허용되는지 또는 필수인지 지정해야 합니다.
    [System.ServiceModel.AspNetCompatibilityRequirements(
            RequirementsMode=AspNetCompatbilityRequirementsMode.Require)]
    public class DerivativesCalculatorServiceType: IDerivativesCalculator
  2. 관리자는 다음과 같이 ASP.NET 호환 모드를 사용하도록 응용 프로그램을 구성해야 합니다.
    <configuration>
       <system.serviceModel>
          <services>
             [...]
          </services>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
       </system.serviceModel>
    </configuration>

또한 Windows Communication Foundation 응용 프로그램은 서비스 파일의 확장명을 .svc가 아닌 .asmx를 사용하도록 구성할 수 있습니다.

<system.web>
   <compilation>
      <compilation debug="true">
         <buildProviders>
            <remove extension=".asmx"/>
            <add extension=".asmx" 
               type="System.ServiceModel.ServiceBuildProvider, 
               Systemm.ServiceModel, 
               Version=3.0.0.0, 
               Culture=neutral, 
               PublicKeyToken=b77a5c561934e089" />
         </buildProviders>
      </compilation>
   </compilation>
</system.web>

이 옵션을 사용하면 Windows Communication Foundation을 사용하도록 서비스를 수정할 때 .asmx 서비스 파일의 URL을 사용하도록 구성된 클라이언트를 수정하지 않아도 됩니다.

클라이언트 개발

ASP.NET 웹 서비스용 클라이언트는 .asmx 파일의 URL을 입력으로 제공하는 wsdl.exe 명령줄 도구를 사용하여 생성됩니다. Windows Communication Foundation에서 제공되는 이와 유사한 도구는 svcutil.exe입니다. 이 도구는 서비스 계약과 프록시 클래스에 대한 정의를 포함한 코드 모듈을 생성합니다. 또한 서비스의 주소와 바인딩을 포함한 구성 파일도 생성합니다.

원격 서비스의 클라이언트를 프로그래밍할 때 일반적으로 비동기 패턴에 따라 프로그래밍하는 것이 좋습니다. wsdl.exe 도구로 생성되는 코드는 기본적으로 항상 동기 패턴과 비동기 패턴을 모두 제공합니다. svcutil.exe 도구로 생성되는 코드는 둘 중 한 패턴을 제공할 수 있습니다. 이 도구는 기본적으로 동기 패턴을 제공합니다. 이 도구를 /async 스위치와 함께 실행하면 생성된 코드에서 비동기 패턴을 제공합니다.

ASP.NET의 wsdl.exe 도구로 생성되는 프록시 클래스의 이름이 기본적으로 Windows Communication Foundation의 svcutil.exe 도구로 생성되는 프록시 클래스의 이름과 일치할 것이라는 보장은 없습니다. 특히 System.Xml.Serialization.XmlSerializer를 사용하여 serialize되어야 하는 클래스의 속성 이름에는 기본적으로 svcutil.exe 도구로 생성되는 코드에서 Property 접미사가 제공되지만 wsdl.exe 도구에서는 그렇지 않습니다.

메시지 표현

ASP.NET 웹 서비스에서 송수신되는 SOAP 메시지 헤더는 사용자 지정할 수 있습니다. System.Web.Services.Protocols에서 클래스가 파생되어 헤더의 구조가 정의된 다음 System.Web.Services.SoapHeader 특성이 헤더의 존재를 나타내는 데 사용됩니다.

public class SomeProtocol : SoapHeader
{
    public long CurrentValue;
    public long Total;
}

[WebService]
public interface IEcho
{
    SomeProtocol ProtocolHeader
    {
       get;
   set;
    }

    [WebMethod]
    [SoapHeader("ProtocolHeader")]
    string PlaceOrders(PurchaseOrderType order);
}

public class Service: WebService, IEcho
{
    private SomeProtocol protocolHeader;
    
    public SomeProtocol ProtocolHeader
    {
      get
      {
        return this.protocolHeader;
      }
      
      set
      {
        this.protocolHeader = value;
      }
    }
    
    string PlaceOrders(PurchaseOrderType order)
    {
      long currentValue = this.protocolHeader.CurrentValue;
    }
}

Windows Communication Foundation에서는 다음과 같이 System.ServiceModel.MessageContract, System.ServiceModel.MessageHeader, System.ServiceModel.MessageBody 특성을 제공하여 서비스에서 송수신되는 SOAP 메시지의 구조를 설명합니다.

[DataContract]
public class SomeProtocol
{
    [DataMember]
    public long CurrentValue;
    [DataMember]
    public long Total;
}

[DataContract]
public class Item
{
    [DataMember]
    public string ItemNumber;
    [DataMember]
    public decimal Quantity;
    [DataMember]
    public decimal UnitPrice;
}

[MessageContract]
public class ItemMesage
{
    [MessageHeader]
    public SomeProtocol ProtocolHeader;
    [MessageBody]
    public Item Content;
}

[ServiceContract]
public interface IItemService
{
    [OperationContract]
    public void DeliverItem(ItemMessage itemMessage);
}

이 구문은 메시지 구조의 명시적인 표현을 나타내지만 메시지의 구조는 ASP.NET 웹 서비스 코드로 암시될 뿐입니다. 또한 ASP.NET 구문에서는 메시지 헤더가 위 예제의 ProtocolHeader 속성과 같은 서비스 속성으로 나타나지만 Windows Communication Foundation 구문에서는 메시지 속성으로 더욱 정확하게 나타납니다. Windows Communication Foundation에서는 끝점 구성에 메시지 헤더를 추가할 수도 있습니다.

<service name="Service ">
   <endpoint 
      address="EchoService"
      binding="basicHttpBinding"
      contract="IEchoService ">
      <headers>
         <dsig:X509Certificate 
            xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
               ...
         </dsig:X509Certificate>
      </headers>
   </endpoint>
</service>

이 옵션을 사용하면 클라이언트 또는 서비스에 대한 코드에서 기반 프로토콜 헤더를 참조할 필요가 없습니다. 끝점 구성 방식에 의해 헤더가 메시지에 간단히 추가됩니다.

서비스 설명

wsdl 쿼리를 사용하여 ASP.NET 웹 서비스의 .asmx 파일에 대해 HTTP GET 요청을 발행하면 ASP.NET에서 해당 서비스를 설명하는 WSDL을 생성하게 됩니다. 이 WSDL이 요청에 대한 응답으로 반환됩니다.

ASP.NET 2.0을 통해 서비스가 WS-I(Web Services-Interoperability Organization) Basic Profile 1.1과 호환되는지 확인하고 서비스가 WSDL과 호환된다는 문구를 넣을 수 있게 되었습니다. 다음과 같이 System.Web.Services.WebServiceBinding 특성의 ConformsTo와 EmitConformanceClaims 매개 변수를 사용하면 됩니다.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(
    ConformsTo = WsiProfiles.BasicProfile1_1,
    EmitConformanceClaims=true)]
public interface IEcho

ASP.NET에서 서비스에 대해 생성하는 WSDL은 사용자 지정할 수 있습니다. System.Web.Services.Description.ServiceDescriptionFormatExtension의 하위 클래스를 만들어 WSDL에 항목을 추가함으로써 사용자 지정할 수 있습니다.

IIS 5.1, 6.0 또는 WAS에서 호스트되는 HTTP 끝점이 있는 Windows Communication Foundation 서비스의 .svc 파일에 대해 wsdl 쿼리를 사용하여 HTTP GET 요청을 발행하면 Windows Communication Foundation에서 해당 서비스를 설명하는 WSDL로 응답하게 됩니다. .NET 응용 프로그램에서 호스트되는 서비스의 HTTP 기준 주소에 대해 wsdl 쿼리를 사용하여 HTTP GET 요청을 발행해도 같은 효과가 있습니다.

Windows Communication Foundation은 WS-MetadataExchange 요청에 대해서도 서비스를 설명하기 위해 생성하는 WSDL로 응답합니다. ASP.NET 웹 서비스는 WS-MetadataExchange 요청에 대한 지원을 기본적으로 제공하지 않습니다.

Windows Communication Foundation에서 생성하는 WSDL은 광범위하게 사용자 지정할 수 있습니다. System.ServiceModel.ServiceMetadataBehavior 클래스는 WSDL을 사용자 지정하기 위한 몇 가지 기능을 제공하며 System.ServiceModel.Design.IWsdlExporter 구현을 개발하여 완벽하게 제어할 수 있습니다. 또한 다음과 같이 WSDL을 생성하지 않고 지정된 URL에서 정적 WSDL 파일을 사용하도록 Windows Communication Foundation을 구성할 수도 있습니다.

<behaviors>
   <serviceBehaviors>
      <behavior name="DescriptionBehavior">
        <metadataPublishing 
        enableMetadataExchange="true" 
        enableGetWsdl="true" 
        enableHelpPage="true" 
        metadataLocation=
        "http://localhost/DerivativesCalculatorService/Service.wsdl"/>
      </behavior>
   </serviceBehaviors>
</behaviors>

예외 처리

ASP.NET 웹 서비스에서는 처리되지 않는 예외는 클라이언트에 SOAP 오류로 반환됩니다. 또한 System.Web.Services.Protocols.SoapException 클래스의 인스턴스를 명시적으로 발생시켜 클라이언트에 전송되는 SOAP 오류의 내용에 대한 제어 범위를 넓힐 수 있습니다.

Windows Communication Foundation 서비스에서는 중요한 정보가 예외를 통해 우발적으로 노출되지 않도록, 처리되지 않은 예외가 클라이언트에 SOAP 오류로 반환되지 않습니다. 디버깅을 위해 처리되지 않은 예외가 클라이언트에 반환되도록 하는 구성 설정이 제공됩니다.

Windows Communication Foundation 프로그래머는 의도적으로 클라이언트에 SOAP 오류를 반환하기 위해 generic 형식의 System.ServiceModel.FaultException<T> 인스턴스를 발생시킬 수 있습니다. 여기서 T는 데이터 계약이어야 합니다. 또한 프로그래머는 다음과 같이 System.ServiceModel.FaultContract 특성을 작업에 추가하여 작업에서 발생할 수도 있는 오류를 지정할 수 있습니다.

[DataContract]
public class MathFault
{    
    [DataMember]
    public string operation;
    [DataMember]
    public string problemType;
}

[ServiceContract]
public interface ICalculator
{
    [OperationContract]
    [FaultContract(typeof(MathFault))]
    int Divide(int n1, int n2);
}

이렇게 하면 가능한 오류가 서비스에 대한 WSDL에 알려지기 때문에 클라이언트 프로그래머가 작업에서 발생할 수 있는 오류를 정확히 예상하고 다음과 같이 적절한 catch 문을 작성할 수 있습니다.

try
{
    result = proxy.Divide(value1, value2);
}
catch (FaultException<MathFault> e)
{
    Console.WriteLine("FaultException<MathFault>: Math fault while doing " 
      + e.Detail.operation 
      + ". Problem: " 
      + e.Detail.problemType);
}

상태 관리

ASP.NET 웹 서비스를 구현하는 데 사용되는 클래스는 다음과 같이 System.Web.Services.WebService에서 파생될 수 있습니다.

public class Service : WebService, IEcho
{

    public string Echo(string input)
    {
        return input;
    }
}

이러한 경우 System.Web.Services.WebService 기본 클래스의 Context 속성을 사용하여 System.Web.HttpContext 개체에 액세스하도록 클래스를 프로그래밍할 수 있습니다. System.Web.HttpContext 개체를 사용하여 Application 속성을 통해 응용 프로그램 상태 정보를, Session 속성을 통해 세션 상태 정보를 업데이트하고 검색할 수 있습니다.

ASP.NET에서는 System.Web.HttpContext의 Session 속성을 통해 액세스되는 세션 상태 정보가 실제로 저장되는 위치를 세부적으로 제어할 수 있습니다. 세션 상태 정보는 쿠키, 데이터베이스, 현재 서버의 메모리 또는 지정된 서버의 메모리에 저장될 수 있습니다. 저장 위치는 서비스의 구성 파일에서 선택됩니다.

Windows Communication Foundation은 상태 관리를 위한 확장 가능한 개체를 제공합니다. 확장 가능한 개체는 System.ServiceModel.IExtensibleObject<T>를 구현하는 개체입니다. 가장 중요한 확장 가능한 개체는 System.ServiceModel.ServiceHostBaseSystem.ServiceModel.InstanceContext입니다. 전자를 사용하면 같은 호스트에 있는 모든 서비스 형식의 모든 인스턴스에서 액세스 가능한 상태를 유지할 수 있으며, 후자를 사용하면 서비스 형식의 같은 인스턴스 내에서 실행되는 코드로 액세스 가능한 상태를 유지할 수 있습니다.

여기서 TradingSystem 서비스 형식에는 같은 프록시 인스턴스의 모든 호출이 서비스 형식의 같은 인스턴스로 라우팅되도록 지정하는 System.ServiceModel.ServiceBehavior 특성이 있습니다.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class TradingSystem: ITradingService

DealData 클래스는 다음과 같이 서비스 형식의 같은 인스턴스 내에서 실행되는 코드로 액세스할 수 있는 상태를 정의합니다.

internal class DealData: IExtension<InstanceContext>
{
    public string DealIdentifier = null;
    public Trade[] Trades = null;
}

서비스 계약의 작업 중 하나를 구현하는 서비스 형식의 코드에서 DealData 상태 개체는 다음과 같이 서비스 형식의 현재 인스턴스에 대한 상태에 추가됩니다.

string ITradingService.BeginDeal()
{
    string dealIdentifier = Guid.NewGuid().ToString();
    DealData state = new DealData(dealIdentifier);
    OperationContext.Current.InstanceContext.Extensions.Add(state);
    return dealIdentifier;
}

그런 다음 이 상태 개체는 다음과 같이 서비스 계약의 작업 중 다른 하나를 구현하는 코드로 검색 및 수정이 가능하게 됩니다.

void ITradingService.AddTrade(Trade trade)
{
    DealData dealData =      OperationContext.Current.InstanceContext.Extensions.Find<DealData>();
    dealData.AddTrade(trade);
}

ASP.NET에서 System.Web.HttpContext 클래스의 상태 정보가 실제로 저장되는 위치를 세부적으로 제어할 수 있지만, 적어도 초기 버전의 Windows Communication Foundation에서는 확장 가능한 개체가 저장되는 위치를 제어할 수 없습니다. 이러한 점이 Windows Communication Foundation 서비스를 위해 ASP.NET 호환 모드를 선택하는 가장 정당한 이유가 됩니다. 구성 가능한 상태 관리가 필수적인 경우 ASP.NET 호환 모드를 채택함으로써 System.Web.HttpContext 클래스의 기능을 ASP.NET에서와 똑같은 방식으로 사용할 수 있으며 System.Web.HttpContext 클래스를 통해 관리되는 상태 정보가 저장되는 위치를 구성할 수도 있습니다.

보안

ASP.NET 웹 서비스의 보안을 유지하기 위한 옵션은 대개 IIS 응용 프로그램의 보안을 유지하는 옵션과 같습니다. Windows Communication Foundation 응용 프로그램은 IIS뿐만 아니라 .NET 실행 파일 내에서도 호스트될 수 있기 때문에 Windows Communication Foundation 응용 프로그램의 보안을 유지하기 위한 옵션은 IIS의 기능에 독립적으로 만들어야 했습니다. 그러나 ASP.NET 웹 서비스에 제공되는 기능은 ASP.NET 호환 모드에서 실행되는 Windows Communication Foundation 서비스에서도 사용할 수 있습니다.

보안: 인증

IIS는 응용 프로그램에 대한 액세스를 제어하는 기능을 제공하므로 이 기능을 통해 익명 액세스 또는 Windows 인증, 다이제스트 인증, 기본 인증, .NET Passport 인증 등 다양한 모드의 인증을 선택할 수 있습니다. Windows 인증 옵션을 사용하면 ASP.NET 웹 서비스에 대한 액세스를 제어할 수 있습니다. Windows Communication Foundation 응용 프로그램이 IIS 내에서 호스트되는 경우에는 이 응용 프로그램에 대한 익명 액세스를 허용하도록 IIS를 구성하여 다양한 다른 옵션과 함께 Windows 인증을 지원하는 Windows Communication Foundation 자체에서 인증을 관리할 수 있도록 해야 합니다. 기본 제공되는 다른 옵션에는 사용자 이름 토큰, X.509 인증서, SAML 토큰 및 InfoCard가 있으며 사용자 지정 인증 메커니즘도 정의할 수 있습니다.

ASP.NET 2.0의 System.Web.HttpContext 클래스에는 특정 종류의 저장소에서 인증된 사용자에 대한 정보를 읽는 방법을 아는 System.Web.Profile.Provider 클래스를 통해 이러한 정보를 저장소에서 자동으로 검색할 수 있는 Profile 속성이 있습니다. 사용자 지정 동작에서 System.Web.Profile.Provider 클래스를 사용하여 프로필 정보를 검색할 수 있지만 이러한 ASP.NET 2.0 메커니즘은 Windows Communication Foundation에서 ASP.NET 호환 모드인 경우를 제외하면 지원되지 않습니다.

보안: 가장

ASP.NET에서는 ASP.NET 웹 서비스가 특정 사용자로, 또는 현재 요청에서 제공된 사용자의 자격 증명으로 가장할 수 있도록 하는 ID 요소를 제공합니다. 이 요소를 사용하면 ASP.NET 호환 모드에서 실행되고 있는 Windows Communication Foundation 응용 프로그램에서 가장을 구성할 수 있습니다.

Windows Communication Foundation의 구성 시스템은 가장할 특정 사용자를 지정하기 위한 자체 ID 요소를 제공합니다. 또한 Windows Communication Foundation 클라이언트 및 서비스는 가장을 위해 별도로 구성할 수 있습니다. 클라이언트는 요청을 전송할 때 현재 사용자로 가장하도록 다음과 같이 구성할 수 있습니다.

<behaviors>
   <endpointBehaviors>
      <behavior name="DerivativesCalculatorClientBehavior">
         <clientCredentials>
            <windows allowedImpersonationLevel="Impersonation"/>
         </clientCredentials>
      </behavior>
   </endpointBehaviors>
</behaviors>

서비스 작업은 현재 요청에서 제공된 사용자의 자격 증명으로 가장하도록 다음과 같이 구성할 수 있습니다.

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void Receive(Message input)

보안: ACL을 사용한 인증

ACL(액세스 제어 목록)을 사용하면 .asmx 파일에 대한 액세스를 제한할 수 있습니다. 그러나 Windows Communication Foundation .svc 파일에 대한 ACL은 ASP.NET 호환 모드인 경우를 제외하고는 무시됩니다.

보안: 역할 기반 인증

IIS Windows 인증 옵션을 ASP.NET 구성 언어로 제공되는 인증 요소와 함께 사용하면 사용자에게 지정된 Windows 그룹 기반의 ASP.NET 웹 서비스에 대한 역할 기반 인증을 쉽게 수행할 수 있습니다. ASP.NET 2.0에는 더 포괄적인 역할 기반 인증 메커니즘인 역할 공급자가 도입되었습니다.

모든 역할 공급자는 사용자에게 지정된 역할을 쿼리하기 위한 간단한 인터페이스를 구현하는 클래스이지만, 각 역할 공급자는 서로 다른 출처에서 해당 정보를 검색하는 방법을 인식하고 있습니다. ASP.NET 2.0은 Microsoft SQL Server 데이터베이스에서 역할 지정을 검색할 수 있는 역할 공급자와 Windows Server 2003 권한 부여 관리자에서 역할 지정을 검색할 수 있는 역할 공급자를 제공합니다.

실제로 역할 공급자 메커니즘은 Windows Communication Foundation 응용 프로그램을 포함한 모든 .NET 응용 프로그램에서 ASP.NET과 별개로 사용할 수 있습니다. 다음은 System.ServiceModel.ServiceAuthorization 동작을 통해 ASP.NET 역할 공급자를 사용하는 옵션이 선택되는 방식을 보여 주는 Windows Communication Foundation 응용 프로그램의 샘플 구성입니다.

<system.serviceModel>
  <services>
    <service name="Service.ResourceAccessServiceType" 
     behaviorConfiguration="ServiceBehavior">
     <endpoint 
       address="ResourceAccessService" 
      binding="wsHttpBinding" 
      contract="Service.IResourceAccessContract"/>
    </service>
  </services>
  <behaviors>
   <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <serviceAuthorization principalPermissionMode="UseAspNetRoles"/>
        </behavior>
      </serviceBehaviors>
   </behaviors>
</system.serviceModel>

보안: 클래임 기반 인증

Windows Communication Foundation의 가장 중요한 기술 혁신 중 하나는 클래임에 기반하여 보호되는 리소스에 대한 액세스 인증을 완벽하게 지원한다는 것입니다. 클래임은 형식, 권한 및 값으로 구성됩니다. 예를 들어 운전 면허증을 생각해 보십시오. 운전 면허증은 소지인에 대한 클래임 집합으로 구성되는데, 그 중 하나는 소지인의 생년월일입니다. 이 클래임의 형식은 생년월일이며, 값은 운전자의 생년월일입니다. 클래임이 소지인에게 부여하는 권한은 소지인이 클래임 값으로 수행할 수 있는 작업을 지정합니다. 운전자의 생년월일에 대한 클래임의 경우 권한은 단순한 소유입니다. 운전자는 해당 생년월일을 소유하고 있지만 변경하는 등의 작업은 할 수 없습니다. 역할은 단순히 클래임의 한 형식이기 때문에 클래임 기반 인증은 역할 기반 인증을 포함합니다.

클래임 기반 인증은 클래임 집합을 작업의 액세스 요구 사항과 비교하여 그 결과에 따라 작업에 대한 액세스 권한을 부여하거나 거부함으로써 수행됩니다. Windows Communication Foundation에서는 다음과 같이 System.ServiceModel.Description.ServiceAuthorizationBehaviorServiceAuthorizationManager 속성에 값을 다시 한 번 지정함으로써 클래임 기반 인증을 실행하는 데 사용할 클래스를 지정할 수 있습니다.

<behaviors>
  <serviceBehaviors>
    <behavior name='ServiceBehavior'>
   <serviceAuthorization 
        serviceAuthorizationManagerType='Service.AccessChecker, Service' />
    </behavior>
  </serviceBehaviors>
</behaviors>

클래임 기반 인증을 실행하는 데 사용되는 클래스는 System.ServiceModel.ServiceAuthorizationManager에서 파생되어야 하며, 여기에서 다시 정의할 유일한 메서드는 AccessCheck() 메서드입니다. Windows Communication Foundation에서는 서비스의 작업이 호출될 때마다 이 메서드를 호출하여 System.ServiceModel.OperationContext 개체를 제공하며, 이 개체의 ServiceSecurityContext.AuthorizationContext 속성에는 사용자에 대한 클래임이 있습니다. 따라서 Windows Communication Foundation에서는 사용자가 인증을 위해 제공한 보안 토큰이 어떤 것이든 이 토큰으로부터 사용자에 대한 클래임을 조합하는 작업을 이미 완료한 상태이며, 이러한 클래임이 요청한 작업에 충분한지 여부를 평가하는 간단한 작업만 남게 됩니다.

Windows Communication Foundation이 어떤 종류의 보안 토큰으로든 자동으로 클래임을 조합한다는 점은 매우 중요한 혁신입니다. 클래임 기반 인증을 위한 코드를 인증 메커니즘과는 완전히 별개로 만들어 주기 때문입니다. 반면 ASP.NET에서 ACL 또는 역할을 사용하는 인증은 Windows 인증과 밀접하게 연결됩니다.

보안: 기밀성

ASP.NET 웹 서비스와 교환되는 메시지의 기밀성은 IIS의 응용 프로그램에서 HTTPS(Secure Hypertext Transfer Protocol)를 사용하도록 구성함으로써 전송 수준에서 보장할 수 있습니다. IIS에서 호스트되는 Windows Communication Foundation 응용 프로그램에 대해서도 마찬가지입니다. 한편 IIS의 외부에서 호스트되는 Windows Communication Foundation 응용 프로그램도 보안 전송 프로토콜을 사용하도록 구성할 수 있습니다. 더 중요한 것은 메시지가 WS-Security 프로토콜을 사용하여 전송되기 전에 메시지의 보안을 유지하도록 Windows Communication Foundation 응용 프로그램을 구성할 수 있다는 점입니다. WS-Security를 사용하여 메시지 본문의 보안만 유지하면 메시지가 기밀을 유지한 상태로 중간 단계를 거쳐 최종 목적지에 도달하도록 할 수 있습니다.

세계화

ASP.NET 구성 언어를 사용하면 개별 서비스의 culture를 지정할 수 있습니다. Windows Communication Foundation에서는 ASP.NET 호환 모드인 경우를 제외하고 이러한 구성 설정을 지원하지 않습니다. ASP.NET 호환 모드를 사용하지 않는 Windows Communication Foundation 서비스를 지역화하려면 서비스 형식을 culture별 어셈블리로 컴파일하고 각 culture별 어셈블리가 별도의 culture별 끝점을 갖도록 합니다.

내부 아키텍처

ASP.NET 웹 서비스

최신 ASP.NET 구현에서 HTTP 요청은 http.sys라는 Windows 커널의 HTTP 구현에서 System.Web.HttpWorkerRequest 개체 형식으로 수신됩니다. System.Web.HttpWorkerRequest 개체는 System.Web.HttpRuntime 개체에 수신되며, 이 개체는 System.Web.HttpWorkerRequest의 데이터로 System.Web.HttpContext 개체를 채웁니다. 요청은 System.Web.HttpRequest 개체인 Request 속성으로 System.Web.HttpContext 개체에 통합됩니다.

.asmx 파일로 배달된 HTTP POST 요청을 나타내는 System.Web.HttpRequest 개체는 기본적으로 System.Web.IHttpHandler 인터페이스를 구현하는 개체에 전달됩니다(Skonnard 2003, 2004). 이 개체는 System.Web.Services.Protocols.WebServiceHandlerFactory 클래스를 사용하여 만들어지며, ASP.NET 웹 서비스 요청 처리기라고도 합니다. Windows Communication Foundation은 ASP.NET 호환 모드로 구성되면 ASP.NET 웹 서비스 요청 처리기의 동작을 모방하는 System.Web.IHttpHandler의 구현을 제공합니다.

ASP.NET 웹 서비스 요청 처리기는 적어도 4가지 작업을 수행해야 합니다. 첫째, HTTP 요청에 통합된 SOAP 메시지를 개발자가 제공하는 SOAP E\extensions의 인스턴스에 전달해야 합니다(Meier, Vasireddy, Babbar 및 Mackman 2004). 둘째, 요청을 처리하기 위해 .asmx 파일에 참조된 클래스의 메서드 중 호출할 메서드를 결정해야 합니다. 셋째, 메서드에서 매개 변수로 예상하는 형식의 인스턴스로 요청이 deserialize되도록 해야 합니다. 넷째, 실제로 메서드를 호출하여 요청으로부터 deserialize한 매개 변수를 이 메서드에 전달해야 합니다.

SOAP 확장은 System.Web.Services.Protocols.SoapExtension에서 파생된 형식입니다. 이 확장은 SOAP 메시지가 처리를 위해 .asmx 파일에서 참조되는 클래스의 메서드로 전달되기 전에 요청에 있는 SOAP 메시지를 액세스하거나 수정하는 데 사용됩니다. 또한 이 확장은 응답 메시지를 액세스 및 수정할 수 있으며 서버뿐만 아니라 클라이언트에도 배포될 수 있습니다. SOAP 확장의 일반적 용도는 메시지 로깅 및 암호화입니다. SOAP 확장은 컴퓨터에 배포된 모든 서비스 또는 개별 서비스에 적용되거나, 사용자 지정 System.Web.Services.SoapExtension 특성을 사용하여 서비스의 특정 작업에 적용될 수 있습니다.

ASP.NET 웹 서비스 요청 처리기는 기본적으로 SOAPAction 헤더를 사용하여 요청을 처리하기 위해 호출할 클래스의 메서드를 결정합니다. 기본적으로 요청 처리기는 서비스의 네임스페이스와 작업의 이름 순서로 구성된 SOAPAction HTTP 헤더를 예상합니다. 서비스의 기본 네임스페이스는 http://tempuri.org/이며, 작업의 기본 이름은 해당 작업을 정의하는 메서드의 이름입니다. 다음은 HTTP 요청을 처리하는 예제입니다.

POST /asmxservice/service.asmx HTTP/1.1
User-Agent: Mozilla/4.0 
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/Echo"
Host: localhost
Content-Length: 314
Expect: 100-continue
Connection: Keep-Alive

<?xml version="1.0" encoding="UTF-8" ?> 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<Echo xmlns="http://tempuri.org/">
<input>Hello, World
</input> 
</Echo>
</soap:Body>
</soap:Envelope>

예제에서 HTTP 요청을 처리할 때 요청 처리기는 http://localhost/asmxservice/service.asmx에 있는 파일의 @_WebService 지시문에서 참조되는 클래스가 작업 이름이 Echo인 기본 네임스페이스를 가진 서비스를 정의한다고 예상합니다. 또한 이 요청 처리기는 기본적으로 해당 작업이 Echo라는 클래스의 메서드로 구현된다고 예상하며, 해당 메서드를 호출하여 요청을 처리하려고 합니다. 이러한 모든 동작은 다음과 같이 사용자 지정할 수 있습니다.

요청 처리기에서 SOAPAction HTTP 헤더를 사용하지 않고 SOAP 메시지 본문 요소의 정규화된 요소 이름을 사용하여 호출할 메서드를 식별하도록 할 수 있습니다. 앞의 HTTP 요청 예제에서 본문 요소는 다음과 같습니다.

<Echo xmlns="http://tempuri.org/">
[...]
</soap:Body>

정규화된 요소 이름은 http://tempuri.org/Echo입니다. 이 요소 이름은 SOAPAction HTTP 헤더와 같기 때문에 ASP.NET 웹 서비스 요청 처리기에서 메시지를 라우팅하는 방법을 결정하기 위해 이 이름을 어떻게 사용할 것인지는 명백합니다. 요청 처리기에서 SOAPAction HTTP 헤더가 아닌 SOAP 메시지 본문 요소의 정규화된 이름을 사용하도록 하려면 서비스를 구현하는 클래스에 System.Web.Services.Protocols.SoapDocumentService 특성을 적용하고 RequestElement를 라우팅 스타일로 지정합니다. 즉 다음과 같습니다.

[SoapDocumentService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)]
public class Service : WebService, IEcho

또한 다음과 같이 System.Web.Services.Protocols.SoapDocumentMethod 특성의 RequestElementName 매개 변수를 사용하여 메서드 이름과는 다른 SOAP 메시지 본문 요소의 로컬 이름을 만들 수도 있습니다.

[WebMethod]
[SoapDocumentMethod(RequestElementName="OtherName")]
string Echo(string input);

그러면 ASP.NET 웹 서비스 요청 처리기에서 SOAP 메시지 본문 요소의 로컬 이름을 메서드 이름에 직접 일치시키지 않고 해당 메서드에 적용된 System.Web.Services.Protocols.SoapDocumentMethod 특성의 RequestElementName 매개 변수 값에 일치시킵니다.

다음과 같이 System.Web.Services.WebService 특성의 Namespace 매개 변수를 사용하여 ASP.NET 웹 서비스의 네임스페이스에 대한 기본값을 수정할 수 있습니다.

[WebService(Namespace = "http://www.woodgrove.com/2006/01/29/")]
public interface IEcho

여기서는 이 매개 변수의 값이 인터페이스에 적용된 System.Web.Services.WebService 특성에 대해 수정된 것으로 보이지만, 유감스럽게도 버그로 인해 실제로 매개 변수의 값을 변경해도 클래스가 아닌 인터페이스에 이 특성이 적용될 때는 아무런 효과가 없습니다.

작업 이름은 해당 작업을 구현하는 메서드의 이름과 다르게 만들 수 있습니다. 다음과 같이 System.Web.Services.WebMethod 특성의 MessageName 매개 변수 값을 지정하면 됩니다.

[WebMethod(MessageName="OtherName")]
string Echo(string input);

이 기능은 다음과 같이 ASP.NET 웹 서비스 요청 처리기의 다형적 메서드를 구별하는 데 사용할 수 있습니다.

[WebMethod(MessageName="OtherName")]
string Echo(string input);
[WebMethod]
string[] Echo(string[] inputs);

다음과 같이 System.Web.Services.Protocols.SoapDocumentMethod 특성을 메서드에 추가하여 이 특성의 Action 매개 변수에 대한 값을 제공할 수 있습니다.

[WebMethod]
[SoapDocumentMethod(Action="urn:echoing:echo")]
string Echo(string input);

이러한 모든 메서드에 대해 ASP.NET 웹 서비스 요청 처리기는 SOAPAction HTTP 헤더를 서비스의 네임스페이스와 작업 이름으로 분해하여 대상 메서드를 식별하려고 시도하지 않고, 단지 SoapDocumentMethod 특성의 Action 매개 변수에 대해 지정된 값과 일치시킵니다.

일단 ASP.NET 웹 서비스 요청 처리기에서 요청을 처리하기 위해 .asmx 파일에서 참조된 클래스의 메서드 중 호출할 메서드를 식별하면 해당 요청은 이 메서드에서 매개 변수로 예상하는 형식의 인스턴스로 deserialize되어야 합니다. 이를 위해 System.Xml.Serialization.XmlSerializer가 사용됩니다.

기본적으로 요청 처리기는 요청에 통합된 SOAP 메시지가 WSDL 1.1 사양의 문서 스타일과 일치한다고 가정합니다. 이러한 스타일의 메시지에는 임의의 스키마에 따라 구조화된 본문 요소가 있으며, 요청 처리기는 System.Xml.Serialization.XmlSerializer를 사용하여 해당 본문 요소를 .NET 형식으로 deserialize합니다. 다음은 작업 예제입니다.

[WebMethod]
PurchaseOrderConfirmationType PlaceOrders(PurchaseOrderType order); 

위 작업에서 ASP.NET 웹 서비스 요청 처리기는 다음과 같은 문서 스타일의 SOAP 메시지를 예상합니다.

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:s1="urn:Woodgrove:2006:January:29" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:tns="http://tempuri.org/" 
xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <tns:PlaceOrders>
         <s1:PurchaseOrder>
            <s1:Date>2006-01-31</s1:Date>
            <s1:LineItems>
               <s1:LineItem>
                  <s1:ItemNumber>1</s1:ItemNumber>
                  <s1:Quantity>1</s1:Quantity>
                  <s1:UnitPrice>50.00</s1:UnitPrice>
               </s1:LineItem>
            </s1:LineItems>
            <s1:Total>50.00</s1:Total>
         </s1:PurchaseOrder>
      </tns:PlaceOrders>
   </soap:Body>
</soap:Envelope>

여기서 요소 이름은 deserialize될 형식의 이름을 식별합니다. 이 메커니즘도 다음과 같이 사용자 지정할 수 있습니다.

  1. 형식의 이름이 SOAP 메시지의 구성 요소에 매핑되는 방식은 System.Xml.XmlElementSystem.Xml.XmlAttribute 특성을 메서드의 매개 변수에 적용함으로써 사용자 지정할 수 있습니다. System.Xml.XmlElement 특성은 다음과 같이 ASP.NET 웹 서비스 요청 처리기에서 형식을 deserialize할 것이라고 예상하는 XML 요소의 이름을 제어합니다.
    [WebMethod]
    PurchaseOrderType PlaceOrders
    (
        [XmlElement("OrderParameter")]
        PurchaseOrderType order
    );

    System.Xml.XmlAttribute 특성이 매개 변수에 추가된 경우 요청 처리기는 해당 매개 변수를 XML 요소가 아닌 XML 특성에서 deserialize할 것이라고 예상합니다.

  2. 요청에 통합된 SOAP 메시지가 문서 스타일과 일치할 것이라는 ASP.NET 웹 서비스 요청 처리기의 기본 예상을 변경하여 해당 SOAP 메시지가 WSDL 1.1 사양의 RPC 스타일과 일치할 것이라고 예상하도록 만들 수 있습니다. 전체 서비스에 대해 SoapRpcService 특성을 사용하거나, 개별 메서드에 대해 SoapRpcMethod 특성을 사용하여 이를 수행할 수 있습니다. 그러나 RPC 스타일 사용은 WS-I Basic Profile 1.1에 포함되지 않고, 따라서 상호 운용성을 낮추기 때문에 이 옵션은 사용하지 않는 것이 좋습니다.

Windows Communication Foundation

Windows Communication Foundation 클라이언트에 사용되는 서비스의 프록시 클래스는 이 클래스의 메서드로 전달되는 매개 변수를 System.ServiceModel.Channels.Message 개체로 serialize합니다. 그러면 해당 개체는 선택한 바인딩으로 수 및 성격이 결정되는 일련의 채널을 통해 전달됩니다. 이 채널은 일반적으로 해당 채널에서 구현하는 프로토콜에 따라 System.ServiceModel.Channels.Message 개체의 Headers 컬렉션에 System.ServiceModel.Channels.MessageHeader 개체를 추가합니다. 일련의 채널에서 마지막 채널은 항상 전송 채널입니다. 전송 채널은 바인딩으로도 성격이 결정되는 인코더를 사용하여 System.ServiceModel.Channels.Message 개체를 전송 채널에서 서버로 전송하는 바이트 스트림으로 serialize합니다. 서버의 수신기는 바이트 스트림을 받은 다음 인코더를 사용하여 바이트 스트림을 System.ServiceModel.Channels.Message 개체로 deserialize합니다. 그 다음 일반적으로 클라이언트의 채널과 일치하는 일련의 채널을 통해 해당 개체가 전달됩니다. 그런 다음 System.ServiceModel.Channels.Message 개체가 System.ServiceModel.Dispatcher.DispatchRuntime 개체로 전달됩니다. System.ServiceModel.Dispatcher.DispatchRuntime 개체는 호출될 서비스 형식의 메서드를 결정하고 System.ServiceModel.Channels.Message 개체의 데이터를 해당 메서드에서 매개 변수로 예상하는 형식의 인스턴스로 deserialize하고 해당 메서드를 호출합니다.

Windows Communication Foundation에서 데이터 전송을 전달하게 되는 채널의 선택과 작업을 서비스 바인딩을 통해 사용자 지정할 수 있을 뿐만 아니라 사용자 지정 채널도 손쉽게 추가할 수 있습니다. 또한 프록시 및 System.ServiceModel.Dispatcher.DispatchRuntime 작업도 이러한 동작을 통해 조정하거나 전체적으로 사용자 지정할 수 있습니다. 즉, ASP.NET에서는 웹 서비스 요청 처리기를 제어하기 위해 많은 특성을 제공하는 반면, Windows Communication Foundation에서는 이와 비슷한 특성 집합뿐만 아니라 프록시 및 System.ServiceModel.Dispatcher.DispatchRuntime을 제어하기 위한 사용자 지정 코드 형식의 스와핑 옵션도 제공합니다.

System.ServiceModel.Dispatcher.DispatchRuntime은 요청을 처리하기 위해 호출되는 서비스 형식의 메서드를 결정할 때 SOAPAction 헤더를 사용합니다. 기본적으로 Windows Communication Foundation 작업에 대한 SOAPAction 헤더는 서비스의 네임스페이스, 서비스 계약 이름, 작업 이름 순서로 구성됩니다. 서비스 계약의 기본 네임스페이스는 http://tempuri.org/입니다. 서비스 계약의 기본 이름은 해당 서비스 계약을 정의하는 데 사용되는 인터페이스 또는 클래스의 이름이며, 작업의 기본 이름은 해당 작업을 구현하는 메서드의 이름입니다. 다음은 작업 예제입니다.

[ServiceContract]
public interface IDerivativesCalculator
{
    [OperationContract]
    decimal CalculateDerivative(
        string[] symbols,
        decimal[] parameters,
        string[] functions);

}

위 작업의 경우 SOAPAction 헤더는 http://tempuri.org/IDerivativesCalculator/CalculateDerivative가 됩니다. 다음과 같이 네임스페이스와 서비스 계약의 이름은 System.ServiceModel.ServiceContract 특성의 Namespace 및 Name 매개 변수를 사용하여 기본 이름을 변경할 수 있으며, 작업 이름은 System.ServiceModel.OperationContract 특성의 Name 매개 변수를 사용하여 기본 이름을 변경할 수 있습니다.

[ServiceContract(Namespace="OtherNamespace",Name="OtherContractName"]
public interface IDerivativesCalculator
{
    [OperationContract(Name="OtherOperationName")]
    decimal CalculateDerivative(
        string[] symbols,
        decimal[] parameters,
        string[] functions);
}

System.ServiceModel.Message 개체의 데이터를 deserialize할 때 System.ServiceModel.Dispatcher.DispatchRuntime은 기본적으로 System.Runtime.Serialization.DataContractFormatter를 사용합니다. XML 요소의 이름을 deserialize되는 클래스와 일치시키기 위한 System.ServiceModel.DataContractSystem.ServiceModel.DataMember 특성의 Namespace 및 Name 매개 변수의 메커니즘에 관해서는 이미 설명했습니다.

다음과 같이 System.ServiceModel.XmlSerializerFormat 특성을 적용함으로써 System.ServiceModel.Dispatcher.DispatchRuntime에서 System.Xml.Serialization.XmlSerializer를 사용하도록 만들 수 있습니다.

[ServiceContract, XmlSerializerFormat]
public interface IEcho

이 특성은 서비스의 개별 작업에도 적용할 수 있습니다.

deserialization에 System.Runtime.Serialization.DataContractFormatter가 사용되고 있는 경우 System.ServiceModel.DataContractFormat 특성을 사용하여 데이터가 문서 스타일 과 RPC 스타일 중 어느 것으로 예상되는지 제어할 수 있습니다. 이 특성은 다음과 같이 서비스 계약 전체 또는 서비스 계약의 개별 작업에 적용할 수 있습니다.

[ServiceContract]
public interface IItemService
{
    [OperationContract]
    [DataContractFormat(Style=OperationFormatStyle.Rpc)]
    public void DeliverItem(ItemMessage itemMessage);
}

Windows Communication Foundation 채택을 위한 사전 준비: 향후 통합 간소화

현재 ASP.NET을 사용 중이고 앞으로 Windows Communication Foundation을 사용할 예정이라면 새 ASP.NET 웹 서비스가 Windows Communication Foundation 응용 프로그램과 올바르게 작동하도록 하기 위해 다음과 같은 지침을 따릅니다.

일반 권장 사항

새로운 모든 서비스에 대해 ASP.NET 2.0을 채택합니다. ASP.NET 2.0을 채택하면 물론 새 버전의 개선된 기능과 향상된 기능을 사용할 수 있으며 같은 응용 프로그램에서 ASP.NET 2.0 구성 요소를 Windows Communication Foundation 구성 요소와 함께 사용할 수 있게 됩니다.

프로토콜

WS-I Basic Profile 1.1에 대한 부합 여부를 검증하기 위한 ASP.NET 2.0의 새로운 기능을 사용합니다.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(
    ConformsTo = WsiProfiles.BasicProfile1_1,
    EmitConformanceClaims=true)]
public interface IEcho

이 프로필을 따르는 ASP.NET 웹 서비스는 일반적으로 상호 운용성이 더 높고, 미리 정의된 Windows Communication Foundation 바인딩인 System.ServiceModel.BasicHttpBinding을 통해 Windows Communication Foundation 클라이언트와 상호 운용이 가능합니다.

서비스 개발

메시지를 SOAPAction HTTP 헤더가 아닌 SOAP 메시지 본문 요소의 정규화된 이름을 기반으로 발송하려면 System.Web.Services.Protocols.SoapDocumentService 특성을 사용하지 마십시오. Windows Communication Foundation은 SOAPAction HTTP 헤더를 사용하여 메시지를 메서드로 발송합니다.

데이터 표현

System.Xml.Serialization.XmlSerializer에서 기본적으로 형식을 serialize하는 XML은 해당 XML의 네임스페이스가 명시적으로 정의되어 있는 경우 System.RuntimeSerialization.DataContractFormatter에서 형식을 serialize하는 XML과 의미상 동일하다는 점을 상기하십시오. 따라서 앞으로 Windows Communication Foundation을 채택할 예정이면서 현재 ASP.NET 웹 서비스에 사용할 데이터 형식을 정의하는 경우에는 다음을 수행하십시오.

  1. XML 스키마가 아닌 .NET 클래스를 사용하여 데이터 형식을 정의합니다.
  2. System.Serializable 특성 및 System.Xml.Serialization.XmlRoot 특성만 클래스에 추가하고, 후자를 사용하여 형식에 대한 네임스페이스를 명시적으로 정의합니다. .NET 클래스가 XML로 변환되는 방식을 제어하기 위해 System.Xml.Serialization 네임스페이스의 다른 특성을 추가하지 않습니다.

이러한 접근 방식을 채택하면 .NET 클래스가 전송을 위해 serialize되는 XML을 많은 부분 변경하지 않고도 System.Runtime.Serialization.DataContractSystem.Runtime.Serialization.DataMember 특성을 추가하여 나중에 .NET 클래스를 데이터 계약으로 만들 수 있습니다. 그러면 ASP.NET 웹 서비스에서 메시지에 사용되는 동일한 형식이 Windows Communication Foundation 응용 프로그램에서 데이터 계약으로 처리될 수 있으며, 이는 다른 이점과 함께 Windows Communication Foundation 응용 프로그램의 성능 향상이라는 이점을 제공합니다.

보안

IIS의 인증 옵션을 사용하지 마십시오. Windows Communication Foundation 클라이언트에서 지원하지 않습니다. Windows Communication Foundation은 표준 프로토콜에 기반한 더욱 풍부한 옵션을 제공하므로 서비스를 보안해야 하는 경우 즉시 Windows Communication Foundation을 채택해야 합니다.


Windows Communication Foundation 채택을 위한 사전 준비: 향후 마이그레이션 간소화

앞으로 새로운 ASP.NET 응용 프로그램을 Windows Communication Foundation으로 더 쉽게 마이그레이션하려면 앞서 설명한 권장 사항과 다음 권장 사항을 모두 따르십시오.

프로토콜

SOAP 1.2에 대한 ASP.NET 2.0 지원을 사용하지 않습니다.

<configuration>
    <system.web>
        <webServices >
            <protocols>
                <remove name="HttpSoap12"/>
            </protocols>      
        </webServices>
    </system.web>   
</configuration>

Windows Communication Foundation에서는 SOAP 1.1, SOAP 1.2와 같은 별개의 프로토콜을 따르는 메시지가 각각 별개의 끝점을 거치도록 요구하기 때문에 SOAP 1.2에 대한 ASP.NET 2.0 지원은 사용하지 않는 것이 좋습니다. ASP.NET 2.0 웹 서비스가 기본 구성대로 SOAP 1.1과 SOAP 1.2를 모두 지원하도록 구성되면 ASP.NET 웹 서비스의 기존 클라이언트 모두와 호환되는 원래 주소의 단일 Windows Communication Foundation 끝점으로 마이그레이션할 수 없습니다.

서비스 개발

  • Windows Communication Foundation을 사용하면 인터페이스 또는 클래스에 System.ServiceModel.ServiceContract 특성을 적용하여 서비스 계약을 정의할 수 있습니다. 이 특성을 인터페이스에 적용하면 원하는 수의 클래스에서 다양하게 구현할 수 있는 데이터 계약 정의가 생성되므로 클래스보다는 인터페이스에 적용하는 것이 좋습니다. ASP.NET 2.0은 클래스뿐만 아니라 인터페이스에도 System.Web.Services.WebService 특성을 적용하는 옵션을 지원합니다. 그러나 앞서 설명했듯이 ASP.NET 2.0에는 System.Web.Services.WebService 특성이 클래스가 아닌 인터페이스에 적용될 때는 이 특성의 Namespace 매개 변수가 아무런 효과도 없다는 결점이 있습니다. 일반적으로 System.Web.Services.WebService 특성의 Namespace 매개 변수를 사용하여 서비스의 네임스페이스에 대한 기본값(http://tempuri.org)을 수정하는 것이 좋기 때문에 인터페이스 또는 클래스에 System.ServiceModel.ServiceContract 특성을 적용하여 ASP.NET 웹 서비스를 계속 정의해야 합니다.
  • 인터페이스를 정의하는 메서드에 최소한의 코드만 사용합니다. 메서드의 작업을 다른 클래스에 위임하도록 합니다. 그러면 새로운 Windows Communication Foundation 서비스 형식에서도 상당한 작업을 해당 클래스로 간단하게 위임할 수 있습니다.
  • System.Web.Services.WebMethod 특성의 MessageName 매개 변수를 사용하여 서비스 작업에 명시적 이름을 제공합니다.
    [WebMethod(MessageName="ExplicitName")]
    string Echo(string input);

    ASP.NET에서 작업의 기본 이름은 Windows Communication Foundation에서 제공하는 기본 이름과 다르기 때문에 이렇게 하는 것이 중요합니다. 명시적 이름을 제공함으로써 기본 이름을 사용하지 않아도 됩니다.

  • 다형적 메서드로 ASP.NET 웹 서비스 작업을 구현하지 마십시오. Windows Communication Foundation에서는 다형적 메서드로 작업을 구현하는 것을 지원하지 않습니다.
  • System.Web.Services.Protocols.SoapDocumentMethod 특성을 사용하여 HTTP 요청을 메서드로 라우팅할 SOAPAction HTTP 헤더에 명시적 값을 제공합니다.
    [WebMethod]
    [SoapDocumentMethod(RequestElementName="ExplicitAction")]
    string Echo(string input);
    
  • 이 접근 방식을 취할 경우 ASP.NET에서 사용되는 기본 SOAPAction 값을 사용하지 않아도 되며 Windows Communication Foundation에서도 마찬가지입니다.
  • SOAP 확장을 사용하지 마십시오. SOAP 확장이 필요한 경우에는 고려하고 있는 SOAP 확장의 목적이 이미 Windows Communication Foundation에서 제공되는 기능인지 확인하십시오. 이 경우 당장은 Windows Communication Foundation을 채택하지 않는다는 방침을 재고하십시오.

상태 관리

서비스의 상태를 유지하지 마십시오. 상태를 유지하는 것은 응용 프로그램의 확장성을 떨어뜨리는 경향이 있을 뿐만 아니라, Windows Communication Foundation에서 ASP.NET 호환 모드를 통해 ASP.NET 메커니즘을 지원하지만 ASP.NET과 Windows Communication Foundation의 상태 관리 메커니즘은 매우 다릅니다.

예외 처리

서비스에서 송수신할 데이터 형식의 구조를 디자인할 때 클라이언트로 전달하려는 서비스에서 발생할 수 있는 다양한 종류의 예외를 표시하기 위한 구조도 디자인합니다.

[Serializable]
[XmlRoot(
    Namespace="ExplicitNamespace", IsNullable=true)]
public partial class AnticipatedException {
    
    private string anticipatedExceptionInformationField;
    
    public string AnticipatedExceptionInformation {
        get {
            return this.anticipatedExceptionInformationField;
        }
        set {
            this.anticipatedExceptionInformationField = value;
        }
    }

}

다음과 같이 해당 클래스에 자신을 XML로 serialize할 수 있는 기능을 부여합니다.

public XmlNode ToXML()
{
    XmlSerializer serializer = new XmlSerializer(
        typeof(AnticipatedException));
    MemoryStream memoryStream = new MemoryStream();
    XmlTextWriter writer = new XmlTextWriter(
        memoryStream, UnicodeEncoding.UTF8);
    serializer.Serialize(writer, this);
    XmlDocument document = new XmlDocument();
    document.LoadXml(new string(
        UnicodeEncoding.UTF8.GetChars(
memoryStream.GetBuffer())).Trim());
    return document.DocumentElement;
}

그러면 해당 클래스를 사용하여 명시적으로 발생된 System.Web.Services.Protocols.SoapException 인스턴스에 자세한 내용을 제공할 수 있습니다.

AnctipatedException exception = new AnticipatedException();
exception.AnticipatedExceptionInformation = "...";
throw new SoapException(
   "Fault occurred",
   SoapException.ClientFaultCode,
   Context.Request.Url.AbsoluteUri,
   exception.ToXML());

이러한 예외 클래스는 다음과 같이 Windows Communication Foundation의 System.ServiceModel.FaultContract<T>에서 즉시 다시 사용할 수 있습니다.

throw new FaultException<AnticipatedException>(anticipatedException);

보안

  • ASP.NET 2.0 프로필을 사용하지 마십시오.
  • 서비스에 대한 액세스를 제어하기 위해 ACL을 사용하지 마십시오.
  • ASP.NET 2.0 역할 공급자를 사용하여 서비스의 리소스에 대한 액세스를 인증하는 방법을 고려합니다.
Windows Communication Foundation 채택

ASP.NET 웹 서비스와의 공존

ASP.NET으로 개발된 기존 응용 프로그램을 계속 유지하면서 새로운 개발에는 Windows Communication Foundation을 사용하는 방법을 선택할 수 있습니다. Windows Communication Foundation은 모든 시나리오에서 .NET 응용 프로그램과의 원활한 통신을 위한 최적의 선택이 되도록 고안되었기 때문에 ASP.NET으로는 수행할 수 없었던 방식으로 다양한 소프트웨어 통신 문제를 해결하는 표준 도구로 사용할 수 있습니다.

새로운 Windows Communication Foundation 응용 프로그램은 기존 ASP.NET 웹 서비스와 동일한 컴퓨터에 배포될 수 있습니다. 이러한 ASP.NET 웹 서비스에서 버전 2.0 이전의 .NET 버전을 사용하는 경우 ASP.NET IIS 등록 도구를 사용하여 새 Windows Communication Foundation 응용 프로그램을 호스트할 IIS 응용 프로그램에 .NET Framework 2.0을 선택적으로 배포할 수 있습니다. ASP.NET IIS Registration Tool (Aspnet_regiis.exe) (영문) 문서를 참조하십시오. 이 도구에는 IIS 6 관리 콘솔에 기본적으로 제공되는 직관적인 사용자 인터페이스가 있습니다.

Windows Communication Foundation은 사용하여 ASP.NET 호환 모드에서 실행되도록 구성된 Windows Communication Foundation 서비스를 IIS의 기존 ASP.NET 웹 서비스 응용 프로그램에 추가함으로써 기존 ASP.NET 웹 서비스에 새 기능을 추가할 수 있습니다. ASP.NET 호환 모드 덕분에 새로운 Windows Communication Foundation 서비스의 코드는 System.Web.HttpContext 클래스를 통해 기존 ASP.NET 코드와 동일한 응용 프로그램 상태 정보를 액세스 및 업데이트할 수 있으며 동일한 클래스 라이브러리를 공유할 수 있습니다.

ASP.NET 웹 서비스와 클라이언트를 Windows Communication Foundation으로 마이그레이션

Windows Communication Foundation 클라이언트는 ASP.NET 웹 서비스를 사용할 수 있습니다. System.ServiceModel.BasicHttpBinding으로 구성되는 Windows Communication Foundation 서비스는 ASP.NET 웹 서비스 클라이언트에서 사용할 수 있습니다. ASP.NET 웹 서비스는 Windows Communication Foundation 응용 프로그램과 공존할 수 있으며, Windows Communication Foundation을 사용하여 기존 ASP.NET 웹 서비스에 기능을 추가할 수도 있습니다. Windows Communication Foundation과 ASP.NET 웹 서비스를 함께 사용할 수 있는 이러한 모든 방식을 고려해 보면 ASP.NET 웹 서비스를 Windows Communication Foundation으로 마이그레이션해야 하는 필연적인 이유는 거의 없습니다.

마이그레이션이 필요한 것으로 보이는 일부 경우에서도, 단순히 한 기술에서 다른 기술로 코드를 마이그레이션하는 것은 대부분 올바른 접근 방식이 아니라는 점을 신중하게 고려하십시오. 새로운 기술을 채택하는 이유는 이전 기술로는 따라갈 수 없는 새로운 요구 사항을 충족하기 위한 것이며, 이러한 경우 새로 확장된 요구 사항을 충족하는 새로운 솔루션을 디자인하는 것이 올바른 방법입니다. 새 디자인은 기존 시스템에서의 경험과 해당 시스템이 디자인된 이후 축적된 지식을 활용할 수 있습니다. 또한 새 디자인은 단순히 새 플랫폼에서 이전 디자인을 재생산하는 것이 아니라 새 기술의 완전한 기능을 충분히 고려할 것입니다. 새 디자인의 주요 요소를 프로토타이핑하면 대개 새 시스템에서 기존 시스템의 코드를 다시 사용하는 방법을 명확하게 알 수 있습니다.

단순히 ASP.NET 웹 서비스에서 Windows Communication Foundation으로 이식하는 것이 올바른 솔루션으로 생각되는 일부 경우에 대한 몇 가지 진행 방법 지침이 있습니다. 서비스를 마이그레이션하는 방법과 클라이언트를 마이그레이션하는 방법에 대한 권장 사항이 있습니다.

ASP.NET 웹 서비스를 Windows Communication Foundation으로 마이그레이션

  1. 서비스에 대한 포괄적인 테스트 집합이 있는지 확인합니다.
  2. 서비스에 대한 WSDL을 생성하고 해당 서비스의 .asmx 파일과 같은 폴더에 복사본을 저장합니다.
  3. .NET 2.0을 사용하도록 ASP.NET 웹 서비스를 업그레이드합니다. 먼저 .NET Framework 2.0을 IIS의 응용 프로그램에 배포한 다음 Visual Studio 2005를 사용하여 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/webprojectsVS05.asp?frame=true(영문) 문서의 설명에 따라 코드 변환 프로세스를 자동화함으로써 업그레이드를 수행합니다. 테스트 집합을 실행합니다.
  4. System.Web.Services.WebService 특성의 Namespace 및 Name 매개 변수의 값이 아직 제공되지 않았으면 이 매개 변수들에 명시적 값을 제공합니다. System.Web.Services.WebMethod 특성의 MessageName 매개 변수에도 같은 작업을 수행합니다. 또한 요청을 메서드로 라우팅하는 SOAPAction HTTP 헤더에 명시적 값이 아직 제공되지 않았으면 다음과 같이 System.Web.Services.Protocols.SoapDocumentMethod 특성으로 Action 매개 변수의 기본값을 명시적으로 지정합니다.
    [WebService(Namespace = "http://tempuri.org/", Name = "Adder")]
    public class Adder
    {
        [WebMethod(MessageName = "Add")]
        [SoapDocumentMethod(Action = "http://tempuri.org/Add")]
        public double Add(SumInput input)
        {
            double sum = 0.00;
            foreach (double inputValue in input.Input)
            {
                sum += inputValue;
            }
            return sum;
        }
    }
  5. 테스트 집합을 실행합니다.
  6. 클래스의 메서드 본문에 있는 코드를 원래 클래스에서 사용하도록 만들어진 별개의 클래스로 옮깁니다.
    [WebService(Namespace = "http://tempuri.org/", Name = "Adder")]
    public class Adder
    {
        [WebMethod(MessageName = "Add")]
        [SoapDocumentMethod(Action = "http://tempuri.org/Add")]
        public double Add(SumInput input)
        {
            return new ActualAdder().Add(input);
        }
    }
    
    internal class ActualAdder
    {
        internal double Add(SumInput input)
        {
            double sum = 0.00;
            foreach (double inputValue in input.Input)
            {
                sum += inputValue;
            }
            return sum;
        }
    }
  7. 테스트 집합을 실행합니다.
  8. Windows Communication Foundation 어셈블리인 System.ServiceModelSystem.Runtime.Serialization에 대한 참조를 ASP.NET 웹 서비스 프로젝트에 추가합니다.
  9. Windows Communication Foundation의 svcutil.exe 도구를 실행하여 WSDL에서 Windows Communication Foundation 프록시 클래스를 생성합니다. 생성된 클래스 모듈을 솔루션에 추가합니다.
  10. 앞 단계에서 생성된 클래스 모듈에는 인터페이스 정의가 포함됩니다.
    [System.ServiceModel.ServiceContractAttribute()]
    public interface AdderSoap
    {
        [System.ServiceModel.OperationContractAttribute(
          Action="http://tempuri.org/Add", 
          ReplyAction="http://tempuri.org/Add")]
        AddResponse Add(AddRequest request);
    }
    Modify the definition of the ASP.NET Web service class so that the class is defined as implementing that interface: 
    [WebService(Namespace = "http://tempuri.org/", Name = "Adder")]
    public class Adder: AdderSoap
    {
        [WebMethod(MessageName = "Add")]
        [SoapDocumentMethod(Action = "http://tempuri.org/Add")]
        public double Add(SumInput input)
        {
            return new ActualAdder().Add(input);
        }
    
        
        public AddResponse Add(AddRequest request)
        {
            return new AddResponse(
    new AddResponseBody(
    this.Add(request.Body.input)));
        }
    }
  11. 프로젝트를 컴파일합니다. 9단계에서 생성된 코드 때문에 일부 형식 정의가 중복되는 오류가 있을 수 있습니다. 일반적으로 형식에 대한 기존 정의를 삭제하여 이러한 오류를 수정합니다. 테스트 집합을 실행합니다.
  12. System.Web.Services.WebService, System.Web.Services.WebMethod, System.Web.Services.Protocols.SoapDocumentMethod 특성 등 ASP.NET 고유의 특성을 제거합니다.
    public class Adder: AdderSoap
    {
        public double Add(SumInput input)
        {
            return new ActualAdder().Add(input);
        }
    
        
        public AddResponse Add(AddRequest request)
        {
            return new AddResponse(
    new AddResponseBody(
    this.Add(request.Body.input)));
        }
    }
  13. Windows Communication Foundation 서비스 형식이 될 클래스를 구성하여 ASP.NET 웹 서비스가 다음 항목을 사용하는 경우 Windows Communication Foundation의 ASP.NET 호환 모드를 요구하도록 합니다.
    • System.Web.Services.HttpContext 클래스
    • ASP.NET 프로필
    • .asmx 파일의 ACL
    • IIS 인증 옵션
    • ASP.NET 가장 옵션
    • ASP.NET 전역화
    [System.ServiceModel.AspNetCompatibilityRequirements(
           RequirementsMode=AspNetCompatbilityRequirementsMode.Require)]
    public class Adder: AdderSoap
  14. 원래의 .asmx 파일 이름을 .asmx.old로 바꿉니다.
  15. 서비스에 대한 Windows Communication Foundation 서비스 파일을 만들고, 이 파일의 확장명을 .asmx로 지정한 다음 IIS의 응용 프로그램 루트에 저장합니다.
    <%@Service Class="MyOrganization.Adder" %>
    <%@Assembly Name="MyServiceAssembly" %>  
  16. 서비스에 대한 Windows Communication Foundation 구성을 Web.config 파일에 추가합니다. BasicHttpBinding을 사용하고, 앞 단계에서 만든 .asmx 확장명의 서비스 파일을 사용하고, 자체적으로 WSDL을 생성하지 않고 2단계에서 생성된 WSDL을 사용하도록 서비스를 구성합니다. 또한 위 10단계에서 필요하다고 판단된 경우 ASP.NET 호환 모드를 사용하도록 서비스를 구성합니다.
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
       <system.web>
          <compilation>
             <buildProviders>
    <remove extension=".asmx" />
                <add extension=".asmx" 
                   type=
    "System.ServiceModel.ServiceBuildProvider,             System.ServiceModel, Version=2.0.0.0, 
                Culture=neutral, 
                PublicKeyToken=b77a5c561934e089" />
             </buildProviders>
          </compilation>
       </system.web>
       <system.serviceModel>
          <services>
             <service name="MyOrganization.Adder "
                      behaviorConfiguration="AdderBehavior">
    <endpoint 
    address=""
    binding="basicHttpBinding"
    contract="AdderSoap "/>
             </service>
          </services>
          <behaviors>
               <serviceBehaviors>
             <behavior name="AdderBehavior">
                <metadataPublishing 
                   enableMetadataExchange="true" 
                   enableGetWsdl="true" 
                   enableHelpPage="true" 
    metadataLocation=
    "http://MyHost.com/AdderService/Service.wsdl"/>
             </behavior>
            </serviceBehaviors>
          </behaviors>
          <serviceHostingEnvironment 
    aspNetCompatibilityEnabled ="true"/>
       </system.serviceModel>
    </configuration>
    
  17. 구성을 저장합니다.
  18. 프로젝트를 컴파일합니다.
  19. 테스트 집합을 실행합니다.

ASP.NET 웹 서비스 클라이언트를 Windows Communication Foundation으로 마이그레이션

  1. 클라이언트에 대한 포괄적인 테스트 집합이 있는지 확인합니다.
  2. Visual Studio 2005를 사용하여 클라이언트 응용 프로그램을 .NET 2.0으로 업그레이드합니다. 테스트 집합을 실행합니다.
  3. 클라이언트 프로젝트에서 ASP.NET 프록시 코드를 제거합니다. 이 코드는 대개 wsdl.exe 도구를 사용하여 생성된 모듈에 있습니다.
  4. svcutil.exe 도구를 사용하여 Windows Communication Foundation 프록시 코드를 생성합니다. 이 코드를 클라이언트 프로젝트에 추가하고 구성 출력을 클라이언트의 기존 구성 파일에 병합합니다.
  5. 응용 프로그램을 컴파일합니다. 기존 ASP.NET 프록시 형식에 대한 참조를 새 Windows Communication Foundation 프록시 형식에 대한 참조로 바꾸어 컴파일 오류를 수정합니다.
  6. 테스트 집합을 실행합니다.
요약

ASP.NET 웹 서비스 도구는 단지 웹 서비스를 빌드하기 위한 것이지만, Windows Communication Foundation은 소프트웨어 엔터티들이 서로 통신하도록 설정되어야 하는 모든 환경에서 사용할 수 있는 도구를 제공합니다. 웹 서비스 개발 프로젝트에서도 Windows Communication Foundation은 ASP.NET 웹 서비스에서 지원하는 것보다 더 많은 웹 서비스 프로토콜을 지원합니다. 이러한 프로토콜은 신뢰할 수 있는 세션과 트랜잭션을 비롯한 여러 가지 장점을 수반하는, 더욱 정교한 솔루션을 제공합니다. 대부분의 경우 권장되는 작업 과정은 기존 ASP.NET 웹 서비스 응용 프로그램을 계속 유지하면서 새로운 개발에는 Windows Communication Foundation을 채택하는 것입니다. 이러한 작업 과정은 Windows Communication Foundation의 이점을 누리면서 기존 응용 프로그램을 마이그레이션해야 하는 비용을 절약해 줍니다. 새 Windows Communication Foundation 응용 프로그램은 기존 ASP.NET 웹 서비스를 사용할 수 있으며 기존 ASP.NET 응용 프로그램과 공존할 수 있습니다. Windows Communication Foundation의 ASP.NET 호환 모드 덕분에 Windows Communication Foundation을 사용하여 기존 ASP.NET 응용 프로그램에 새로운 작업 기능을 프로그래밍할 수도 있습니다


|

No7Do's Blog is powered by Daum & tistory