Service Station

WCF를 사용한 RESTful 서비스 소개

Jon Flanders

코드는 MSDN 코드 갤러리에서 다운로드할 수 있습니다.
온라인으로 코드 찾아보기

목차

REST에 대해 알아보기
간단한 예
REST를 사용하는 이유
WCF와 REST
WebGetAttribute와 WebInvokeAttribute
UriTemplate과 UriTemplateTable
WebHttpBinding과 WebHttpBehavior
WebServiceHost와 WebServiceHostFactory
코드 예 사용

이 기사는 REST(Representational State Transfer)라고 하는 아키텍처 스타일을 사용하여 WCF(Windows Communication Foundation) 서비스를 작성하는 방법을 다루는 칼럼 시리즈 중 첫 번째 기사입니다. 사실 늦은 감이 없지 않지만 2009년 Service Station 칼럼에서는 REST가 주인공이 될 것입니다. REST는 2000년에 소개된 이후로 몇 년 동안 많은 인기를 얻은 스타일입니다.

첫 번째 칼럼에서는 REST의 몇 가지 기본적인 특성에 대해 살펴보고 WCF를 사용한 RESTful 서비스 구현을 소개하겠습니다. 향후 칼럼에서는 REST에 대한 기본적인 개념을 더 자세히 살펴보고 이러한 기반에 바탕을 둔 기술을 설명할 것입니다.

REST에 대해 알아보기

아키텍처 스타일이란 어떤 것을 작성할 때 적용할 수 있는 제약 조건의 집합입니다. 소프트웨어의 아키텍처 스타일은 소프트웨어 시스템의 구현을 안내하는 데 사용될 수 있는 기능을 설명합니다. REST는 클라이언트(사용자 에이전트)가 서비스(끝점)에 요청을 수행하는 소프트웨어를 작성하는 데 사용되는 아키텍처 스타일입니다. REST는 클라이언트 서버 아키텍처 스타일을 구현하는 한 가지 방법이며 실제로 REST는 클라이언트-서버 아키텍처 스타일에 기반을 두고 있습니다.

REST라는 용어는 Roy Thomas Fielding이 그의 박사 논문("Architectural Styles and the Design of Network-based Software Architectures")에서 처음 사용했습니다. 이 사람은 현재 인터넷을 주도하고 있는 거의 모든 HTTP(Hypertext Transfer Protocol) 규약을 개발하는 데 참여하기도 했습니다. 일반적으로 아키텍처 스타일에 대한 설명에서 한 인물의 배경 소개는 스타일과는 관련이 없어 보이지만 REST에 대한 기본적인 이해를 얻는 가장 좋은 방법은 웹 자체와 웹의 작동 방식을 살펴보는 것이 가장 좋은 방법이기 때문에 의미가 있습니다.

여기에서는 여러분이 개발자로서 웹에 매우 익숙하다고 가정하고 있습니다(아니면 필자처럼 매일 웹을 사용 또는 중독 상태). 논쟁의 여지가 있지만 웹은 가장 크고 확장성이 우수하며 가장 인기 있는 분산 응용 프로그램이라고 할 수 있습니다. REST의 제약 조건은 웹의 기본 원칙에 마찬가지로 기반을 두고 있습니다. 이러한 원칙은 다음과 같습니다.

  • 사용자 에이전트는 리소스와 상호 작용하며 이름을 지정하고 제공할 수 있는 모든 것이 리소스가 될 수 있습니다. 각 리소스는 고유한 URI(Uniform Resource Identifier)를 사용하여 주소를 지정할 수 있습니다.
  • 리소스(해당 고유 URL를 통해 위치 지정)와의 상호 작용은 HTTP 표준 동사(GET, POST, PUT 및 DELETE)라는 균일 인터페이스를 사용하여 수행됩니다. 상호 작용에는 HTTP Content-Type 헤더를 사용하여 지정하는 리소스의 미디어 유형 선언도 중요합니다. 많이 사용되는 미디어 유형에는 XHTML, XML,.png, PNG 및 JSON이 있습니다.
  • 리소스는 자체 설명적입니다. 리소스에 대한 요청을 처리하는 데 필요한 모든 정보는 요청 자체에 포함되어 있습니다. 이에 따라 상태를 저장하지 않는 서비스가 허용됩니다.
  • 리소스는 다른 리소스에 대한 링크(하이퍼 미디어)를 포함합니다.

간단한 예

REST 아키텍처 스타일을 사용하는 서비스를 일반적으로 RESTful 서비스 또는 끝점이라고 합니다. 이 아키텍처 스타일의 내부 개념을 이해할 수 있도록 작은 예를 살펴보겠습니다. MSDN Magazine에 대한 데이터를 사용하는 서비스를 작성해야 한다고 가정해 보겠습니다. 이 서비스는 지금까지 출간된 모든 년도의 MSDN Magazine에 대한 정보, 그리고 각 발행본에 있는 모든 기사에 대한 정보를 제공할 수 있습니다. 그리고 잡지의 편집자가 이 서비스를 사용하여 새 기사를 추가하고 향후 발행본에 대한 데이터를 관리할 수 있어야 합니다.

RESTful 서비스를 작성할 때는 아주 간단한 기본적인 단계를 통해 서비스를 디자인할 수 있습니다.

  1. 사용될 리소스는 무엇입니까?
  2. 이러한 리소스를 제공하는 데 사용될 URI는 무엇입니까?
  3. 각 URI는 균일 인터페이스(HTTP 동사) 중 어떤 부분을 지원합니까?

이러한 항목은 리소스와 해당 표현, 이러한 리소스의 URI, 그리고 각 URI가 응답하는 균일 인터페이스의 일부인 RESTful 끝점의 기본적인 구성 요소입니다. 이 밖에도 더욱 명시적인 상태 코드 사용, 하이퍼링크를 사용한 리소스 상태 관리와 같이 고급 기능을 활용할 수 있지만 이 예에서는 기본적인 내용만 다루겠습니다.

이제 이러한 단계를 사용하여 가상의 서비스를 디자인할 수 있습니다. 이 서비스에서 리소스는 MSDN Magazine이 출간된 모든 년도, 각 년도에 발행된 모든 발행본, 그리고 각 발행본에 수록된 모든 기사입니다. 여기에서는 이러한 리소스를 나타내는 데 application/xml (XML) 미디어 유형을 사용할 것이지만 RESTful 서비스의 미디어 유형이 XML로 제한되는 것은 아니라는 것을 기억해야 합니다.

다음은 각 리소스의 URI를 결정해야 합니다. 절대 URI는 끝점을 호스트하는 위치에 따라 결정되므로 현재는 상대 URI만 결정하면 됩니다. 년도 목록은 서비스의 루트 URI(/)가 됩니다. 이 구문을 사용하면 /{year}는 각 년도의 모든 발행본을 반환하며, /{year}/{issue}는 각 발행본의 URI이고(발행 월로 각 발행본을 식별), /{year}/{issue}/{article}은 각 기사를 나타냅니다. 여기에서 각 기사는 1부터 n까지 번호가 지정된다고 가정합니다.

다음은 균일 인터페이스에 대한 URI 매핑에 대한 내용입니다. 잡지의 기록은 읽기 전용이어야 하므로 루트 리소스는 GET만 공개합니다. URI /{year}에 대해 PUT을 수행하면 새 년도를 추가할 수 있습니다. PUT은 이 경우와 마찬가지로 클라이언트가 새 리소스의 URI에 대한 정보가 있는 경우 새 리소스를 만드는 데 사용됩니다. PUT은 URI가 알려져 있을 때 기존 리소스를 업데이트하는 데 사용할 수 있습니다. POST는 클라이언트가 새 리소스의 URI에 대한 정보가 없는 경우 리소스를 만드는 데 사용됩니다. 즉, POST는 새로운 기사 리소스를 추가할 때 사용할 동사이며 /{year}/{issue} URI로 전송됩니다.

각 리소스와 각 단어에 대해 계속 설명할 수 있지만 앞의 설명을 통해서 RESTful 끝점의 디자인을 결정하기 위해 수행할 단계를 이해할 수 있기를 바랍니다. 그림 1에서 리소스, URI 및 동사의 전체 목록을 볼 수 있습니다.

그림 1 운영 체제 지원
리소스 URI 동사
전체 년도 "/ " GET
특정 년도의 발행본 "/{year}" GET, PUT
특정 발행본 "/{year}/{issue}" GET, PUT
기사 "/{year}/{issue}/{article}" GET, POST (기사 번호는 시스템에서 할당됨), PUT, DELETE (발행본이 출간되면 delete는 해제됨)

클라이언트가 2006년 1월 기사를 사용하려면 /2006/January에 대해 HTTP GET을 수행하면 됩니다. 필자가 편집자이고 2008년 12월에 기사를 추가하려는 경우 클라이언트가 /2008/December에 대해 기사 리소스를 POST하면 새 기사가 해당 발행본에 추가됩니다. 이것이 이 서비스를 클라이언트로서 사용하기 위해 반복적으로 사용할 패턴입니다.

REST를 사용하는 이유

REST에 대해 잠시 설명했는데 이를 사용해야 하는 이유가 무엇인지 궁금할 것입니다. 개발자가 새로운 스타일, 기술 또는 패턴을 배우고 익히는 데는 동기가 필요합니다. 이 잡지를 읽는 독자라면 아마도 Microsoft 기술 스택의 개발자일 것이며 기존에 클라이언트-서버 응용 프로그램을 구현하는 데 RPC(원격 프로시저 호출)라는 다른 아키텍처 스타일을 사용해왔을 것입니다. DCOM이나 .NET Remoting과 같은 소유 RPC 시스템을 사용하거나 ASMX나 WCF를 통한 SOAP와 같은 상호 운용이 가능한 RPC 기술을 사용하는지에 관계없이 이러한 기술은 Microsoft 플랫폼에서 분명 사용할 수 있는 클라이언트-서버 스타일 구현이었습니다. 그렇다면 REST에 대해 배우고 사용하는 이유는 무엇일까요?

여기에는 두 가지 주요 이유가 있습니다. 첫째, REST는 다양한 경우에 RPC 기술에 비해 많은 기능과 장점을 제공합니다. 둘째, Microsoft는 여러 자체 구현을 RPC 기술(SOAP와 같은)에서 REST로 전환하고 있습니다. 이것은 REST를 사용하여 여러분의 시스템을 작성하고 싶은 생각이 없더라도 Microsoft(그리고 다른 개발사)의 프레임워크와 기술이 REST로 전환되고 있으므로 REST와 상호 작용하는 방법을 배워야 한다는 것을 의미합니다.

다음은 REST가 제공하는 다른 장점의 목록입니다. 이 목록이 장점의 전부는 아닙니다.

캐싱 RESTful 끝점이 HTTP를 사용하여 데이터를 요청할 때 사용되는 HTTP 동사는 GET입니다. GET 요청에 대한 응답으로 반환되는 리소스는 다양한 방법으로 캐시할 수 있습니다. 조건부 GET은 클라이언트가 서비스에 자체 데이터가 여전히 최신 버전인지 확인할 수 있는 방법이며 RESTful 끝점에서 이 선택적인 구현을 제공하면 속도와 확장성을 더욱 개선할 수 있습니다.

병렬 확장 REST는 각 리소스가 특정 요청을 처리하는 데 필요한 모든 상태를 포함하도록 권장합니다. RESTful 서비스는 리소스가 이러한 제약 조건을 충족하고 상태를 저장하지 않을 수 있을 때 더 수월하게 병렬 확장할 수 있습니다.

부작용 RESTful 서비스는 GET을 사용하여 리소스를 요청할 때 부작용이 없어야 합니다. 아쉽지만 이 제약 조건은 다른 몇 가지 REST 제약 조건에 비해 위반되는 경우가 많습니다.

Idempotent 균일 인터페이스의 일부로 일반적으로 사용되는 다른 주요 HTTP 동사에는 PUT과 DELETE가 있습니다. PUT은 사용자 에이전트가 리소스를 수정하려는 경우에 가장 많이 사용되며 DELETE는 이름이 의미하는 것처럼 리소스를 삭제합니다. 중요 비트(idempotent 용어의 의미)는 특정 리소스에 이러한 두 동사를 두 번 이상 사용할 수 있으며 처음 사용했을 때와 효과가 동일하거나 적어도 추가적인 효과가 없다는 것을 의미합니다. 이것은 오류, 네트워크 오류 또는 지연이 발생했을 때 코드가 여러 번 실행되는 안정적인 분산 시스템을 작성할 때 도움이 됩니다.

상호 운용성 클라이언트-서버 프로그램을 작성하는 가장 상호 운용성이 높은 방법으로 SOAP를 꼽는 사람들이 많습니다. 그러나 SOAP 도구 키트가 없는 언어와 환경이 있습니다. 또한 일부 도구 키트는 이전 표준에 기반을 두고 있으며 새 표준을 구현하는 도구 키트와 통신할 수 없는 경우가 있습니다. REST를 사용하기 위한 조건은 대부분의 작업에 HTTP 라이브러리를 사용할 수 있어야 한다는 것뿐이며(XML 라이브러리 역시 유용한 경우가 많음) 이것은 SOAP를 포함하여 어떤 RCP 기술보다 상호 운용성이 우수한 것입니다.

단순성 이 장점은 다른 장점에 비해 조금 더 주관적이며 개발자에 따라서 다른 의미가 될 수 있습니다. 필자가 REST 사용이 단순하다고 하는 것은 리소스를 나타내는 URI, 그리고 균일 인터페이스에 대한 것입니다. 필자는 웹을 오랫동안 사용해왔기 때문에 브라우저에 다른 URI를 입력하면 다른 리소스를 얻을 수 있다는 것을 잘 알고 있습니다. 이를 URI 또는 URL 해킹이라고 하는 경우도 있지만 실은 전혀 악의적인 작업이 아닙니다. 이렇게 여러 해 동안 URI를 사용해왔기 때문에 리소스에 사용할 URI를 디자인하는 것이 매우 자연스럽게 느껴집니다. 균일 인터페이스를 사용하면 작성할 각 서비스마다 인터페이스, 계약 또는 API를 직접 작성할 필요가 없어지므로 개발이 간소화됩니다. 인터페이스(클라이언트가 서비스와 상호 작용하는 방법)는 아키텍처의 제약 조건에 의해 설정됩니다.

앞에서 이야기한 것처럼 이 목록은 완전한 것이 아니며 언제나 REST만 사용해야 한다는 확정적인 증명도 아닙니다. 적절한 상황에 활용할 수 있도록 장점이 무엇인지 알고 있어야 합니다.

WCF와 REST

WCF는 스타일이나 프로토콜에 관계없이 네트워크를 통해 통신하는 응용 프로그램 개발을 위한 Microsoft 프레임워크입니다. WCF의 기본 개념은 확장 가능한 플러그형 프레임워크를 개발자에게 제공함으로써 한 가지 프로그래밍 및 구성 모델을 배우고 이러한 기술을 여러 가지 유형의 분산 시스템에 사용할 수 있도록 하는 것입니다.

WCF의 많은 부분이 RPC(SOAP 사용)에 맞게 디자인된 것은 사실이지만 .NET Framework 3.0의 일부로 처음 릴리스되었기 때문에 REST 서비스를 공개하고 사용하는 기능도 가지고 있습니다. 그러나 WCF로 REST 사용을 수월하게 하기 위한 프로그래밍 모델이 없습니다. 또한 .NET Framework 3.0과 함께 REST를 사용하기 위해서는 약간의 인프라를 작성해야 합니다. .NET Framework 3.5에서는 System.ServiceModel.Web 어셈블리에 이러한 프로그래밍 모델과 인프라가 추가되어 WCF에서 사용할 수 있게 되었습니다. .NET Framework 3.5 SP1에도 몇 가지 사소한 향상된 기능이 추가되었습니다.

프로그래밍 모델은 WebGetAttribute 및 WebInvokeAttribute라는 두 가지 새로운 특성을 중점적으로 사용하며, URI 템플릿 메커니즘을 사용하면 각 메서드가 응답할 URI와 동사를 선언할 수 있습니다. 인프라는 REST 사용을 위한 올바른 네트워킹 스택을 제공하는 바인딩(WebHttpBinding)과 동작(WebHttpBehavior)의 형식을 가지고 있습니다. 사용자 지정 ServiceHost(WebServiceHost)와 ServiceHostFactory(WebServiceHostFactory)에서 제공되는 약간의 호스팅 인프라 도움도 있습니다.

WebGetAttribute와 WebInvokeAttribute

WCF가 연결된 시스템 구축을 간소화하기 위해 서비스의 구현으로 정의한 클래스의 인스턴스에 있는 메서드에 네트워크 메시지를 라우팅하는 기능을 제공합니다. 이를 통해 네트워크 트래픽을 처리하는 데 필요한 인프라가 아니라 서비스 코드 논리에 집중할 수 있게 됩니다.

기본적으로 WCF는 작업의 개념을 바탕으로 발송이라고도 하는 이 라우팅을 수행합니다. 이 발송이 작동하려면 WCF가 대신 받는 모든 메시지에 작업이 있어야 합니다. 그리고 각 Action 메서드에 고유한 작업이 매핑됩니다.

Action의 값은 메서드의 이름(여기에 서비스의 네임스페이스를 더함) 또는 사용자 지정 값(OperationContractAttribute.Action 속성을 통해 설정)에 따라 정해집니다. 여기에 SOAP 사양의 Action 헤더가 기본적으로 사용되므로 이 라우팅 시스템은 SOAP와 밀접하게 연결됩니다. 다행스럽게도 WCF의 다른 거의 모든 것과 마찬가지로 이 기본 발송 인프라는 대체할 수 있습니다.

WCF로 REST 인프라를 사용하면 들어오는 요청의 URI와 사용된 HTTP 동사를 바탕으로 라우팅하는 발송자가 아니라 Action을 바탕으로 라우팅하는 발송자로 기본 발송자가 대체됩니다. 이 라우팅(WebHttpDispatchOperationSelector라는 클래스를 통해 수행)을 통해 수월하게 RESTful 끝점을 구현할 수 있습니다. 이 발송자는 WebHttpBehavior라는 동작에 의해 각 끝점에서 구성되며 이 프로그래밍 모델을 사용하려는 각 끝점에 이 발송자를 추가해야 합니다. 그러나 뒤에서 설명하겠지만 이 작업을 수동으로 해야 하는 경우는 많지 않습니다.

이러한 체계가 작동하기 위한 핵심은 WebHttpDispatchOperationSelector가 다른 URI와 동사를 메서드에 매핑하는 방법을 알아야 한다는 것입니다. 이를 위해 WCF ServiceContract 형식의 메서드에 WebGetAttribute와 WebInvokeAttribute를 추가해야 합니다.

WebGetAttribute는 발송자에게 메서드가 HTTP GET 요청에 응답해야 한다는 것을 알려 줍니다. WebInvokeAttribute는 기본적으로 HTTP POST로 매핑되지만 다른 HTTP 동사(PUT 및 DELETE가 가장 일반적)를 지원하도록 WebInvokeAttribute.Method 속성을 설정할 수 있습니다. 기본적으로 URI는 메서드의 이름(여기에 끝점의 기본 URI가 추가됨)에 따라 결정됩니다.

동사인 메서드 이름은 REST에서 처리하고자 하는 것과는 거리가 멀기 때문에 이 URI는 RESTful에 적합하다고 할 수 없습니다. URI로 공개하려는 것은 명사입니다. 이 때문에 WCF REST 프로그래밍 모델에서는 WebGetAttribute 또는 WebInvokeAttribute의 UriTemplate 속성을 통해 설정할 수 있는 템플릿을 사용하여 각 메서드의 URI를 사용자 지정할 수 있도록 허용하고 있습니다.

UriTemplate과 UriTemplateTable

WCF에는 각 메서드 및 동사 조합의 URI를 사용자 지정할 수 있도록 하기 위해 필자가 이 칼럼에서 MSDN Magazine 서비스 끝점에 대한 설명에 사용한 것과 같은 특수 템플릿 구문으로 각 리소스의 URI를 정의하는 기능이 추가되었습니다. 이 구문을 사용하면 대체할 수 있는 토큰으로 각 메서드가 HTTP 동사(WebGetAttribute 또는 WebInvokeAttribute)와 함께 조합하여 나타내려는 URI 구조를 정의할 수 있습니다. 구문에 대한 자세한 내용은 향후 칼럼에서 설명하겠습니다.

그림 2에는 MSDN Magazine 서비스에 대한 WCF ServiceContract 정의(해당 특성 및 UriTemplate 사용자 지정 포함)가 나와 있으며 이는 앞에서 언급한 기능에 적용됩니다. 이 정의는 기존 WCF 계약 정의 시스템을 GET에 응답해야 할 작업을 위한 WebGetAttribute로 확장합니다. 또한 다른 동사에 응답하도록 작업에 WebInvokeAttribute를 추가합니다.

그림 2 WCF ServiceContract 정의

[ServiceContract]
public interface IMSDNMagazineService
{
    [OperationContract]
    [WebGet(UriTemplate="/")]
    IssuesCollection GetAllIssues();
    [OperationContract]
    [WebGet(UriTemplate = "/{year}")]
    IssuesData GetIssuesByYear(string year);
    [OperationContract]
    [WebGet(UriTemplate = "/{year}/{issue}")]
    Articles GetIssue(string year, string issue);
    [OperationContract]
    [WebGet(UriTemplate = "/{year}/{issue}/{article}")]
    Article GetArticle(string year, string issue, string article);
    [OperationContract]
    [WebInvoke(UriTemplate = "/{year}/{issue}",Method="POST")]
    Article AddArticle(string year, string issue, Article article);

}

이 경우에 WebInvokeAttribute의 기본 동사가 POST이므로 가독성을 위해 AddArticle 메서드에 Method="POST"를 추가했습니다. GET와 POST 메서드에는 모두 UriTemplate 특성을 사용한 URI 사용자 지정이 포함됩니다. UriTemplate 구문은 여러 변수 경로 세그먼트를 허용하며 이러한 각 경로 세그먼트가 인수로서 메서드에 전달됩니다.

WebHttpBinding과 WebHttpBehavior

WCF에서 바인딩은 WCF가 통신하는 방법을 결정합니다. 바인딩은 특정한 끝점에서 원하는 유형의 통신을 제공하기 위해 함께 작업하는 개체 집합인 채널 스택이라고 하는 항목을 만드는 방법을 WCF에 알려 주는 구성이라고 할 수 있습니다.

RESTful 끝점의 경우 사용할 바인딩은 WebHttpBinding입니다. 다른 여러 바인딩과는 달리 WebHttpBinding은 매우 간단하며 HTTP 전송 및 텍스트 메시지 인코더(SOAP를 예상하거나 사용하지 않고 일반 XML만 사용하도록 설정)의 두 가지 구성 요소만 포함합니다.

앞에서 언급했듯이 WebHttpBehavior는 URI와 동사를 합친 발송자가 사용되도록 하는 개체이므로 WebHttpBinding과 WebHttpBehavior는 거의 항상 함께 사용됩니다. 다음은 코드에서는 WCF RESTful 끝점을 직접 호스팅하는 경우 끝점을 생성하는 방법을 보여 줍니다.

ServiceHost sh = 
  new ServiceHost(typeof(MSDNMagazineServiceType));
string baseUri = "http://localhost/MagazineService";
ServiceEndpoint se = 
  sh.AddServiceEndpoint(typeof(IMSDNMagazineService),
  new WebHttpBinding(), baseUri);
se.Behaviors.Add(new WebHttpBehavior());
sh.Open();

URI와 동사를 합친 발송 시스템이 작동하려면 ServiceHost에 끝점을 추가할 때 WebHttpBinding을 지정하는 것은 물론이고 끝점에 WebHttpBehavior를 명시적으로 추가해야 합니다. 물론 구성을 사용하여 이 작업을 할 수도 있습니다(그림 3 참조).

그림 3 구성의 URI와 동사를 합친 발송

<configuration>
  <system.serviceModel>
    <services>
      <service name="MSDNMagazine.MSDNMagazineServiceType">
        <endpoint 
          address="http://localhost/MagazineService" 
          binding="webHttpBinding" 
          contract="MSDNMagazine.IMSDNMagazineService" 
          behaviorConfiguration="webby"/>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="webby">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

WebServiceHost와 WebServiceHostFactory

WCF에 대한 불평 중에는 때로 너무 복잡하다는 것이 있는데 특히 구성과 관련된 부분에 이러한 이야기가 많습니다. RESTful 끝점에서 이러한 문제(단순성은 REST의 장점으로 자주 거론됩니다)를 해결하기 위해 Microsoft는 .NET Framework 3.5에 WebServiceHost와 WebServiceHostFactory라는 두 가지 새로운 형식을 추가했습니다.

WebServiceHost는 ServiceHost-derived 형식이며 RESTful 끝점의 자체 호스팅 시나리오를 간소화해 줍니다. 다음 코드에서는 WebServiceHost로 자체 호스트하는 방법을 보여 줍니다.

string baseUri = "http://localhost/MagazineService";
WebServiceHost sh = 
  new WebServiceHost(typeof(MSDNMagazineServiceType),
  new Uri(baseUri));
sh.Open();

이로써 WebHttpBinding과 WebHttpBehavior를 직접 추가하는 반복적인 코드를 피할 수 있으므로 매우 훌륭한 최적화라고 할 수 있습니다. WebServiceHost 클래스는 자동으로 끝점을 만들고 WebHttpBinding과 WebHttpBehavior로 이를 구성합니다.

WCF를 사용한 관리되는 호스팅 시나리오의 경우 WCF에는 IIS(인터넷 정보 서비스) 내에서 서비스 유형을 가리키는 .svc 파일, 그리고 끝점에 대한 정보를 WCF에 알려 주는 web.config 파일 내의 항목(여러 구성 중에서도 특히 바인딩 및 동작)이 필요합니다.

관리되는 호스팅 시나리오를 간소화하기 위해 Microsoft에서는 관리되는 호스팅 시나리오에서 열린 WCF 확장 지점을 사용하여 여러 RESTful 서비스를 위한 구성이 필요 없는 환경을 만드는 WebServiceHostFactory를 추가했습니다. .svc 파일은 다음과 같습니다.

<%@ ServiceHost Factory=
  "System.ServiceModel.Activation.WebServiceHostFactory"   
  Service="MSDNMagazine.MSDNMagazineServiceType" %>

WebServiceHostFactory는 WebServiceHost 인스턴스를 생성하며 WebServiceHost는 WebHttpBinding과 WebHttpBehavior를 사용하여 자동으로 끝점을 구성하므로 web.config에서 이 끝점을 구성할 필요가 없습니다. 물론 바인딩을 사용자 지정할 필요가 있는 경우에는 구성 시스템을 사용하거나 WebServiceHost/WebServiceFactory에서 파생되는 클래스를 작성해야 합니다. 바인딩을 사용자 지정할 필요가 있었다면 구성 파일에 해당 항목을 추가할 수 있습니다. 그림 4에는 서비스 끝점에서 HTTP 기본 인증을 설정하는 구성 파일이 나와 있습니다.

그림 4 HTTP 기본 인증 설정

<configuration>
<system.serviceModel>
  <services>
    <service name="MSDNMagazine.MSDNMagazineServiceType">
      <endpoint 
        address="http://localhost/MagazineService" 
        binding="webHttpBinding" 
        contract="MSDNMagazine.IMSDNMagazineService" 
        behaviorConfiguration="webby"/>
    </service>
  </services>
  <bindings>
    <webHttpBinding>
      <binding name="secure">
        <security mode="Transport">
          <transport clientCredentialType="Basic"/>
        </security>
      </binding>
    </webHttpBinding>
  </bindings>
  <behaviors>
    <endpointBehaviors>
      <behavior name="webby">
        <webHttp/>
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>
</configuration>

코드 예 사용

REST와 관련된 WCF의 기능을 설명하는 동안 이 칼럼 앞부분에서 제안했던 서비스 구현을 대부분 마무리 지었습니다. 이제 이 서비스와 상호 작용하는 과정을 설명하겠습니다.

일단 서비스가 실행되면 Internet Explorer와 같은 웹 브라우저를 포함하여 모든 클라이언트에서 서비스의 루트 URI에 액세스할 수 있습니다. 브라우저를 사용하여 RESTful 끝점을 신속하게 테스트할 수 있다는 것은 REST 아키텍처 스타일이 웹 작동 방식에 기반을 두고 있기 때문일 것입니다. 결과는 그림 5에 나와 있습니다.

그림 5 루트 리소스 URI

이 경우에는 기본 URI를 적용하는 Visual Studio 2008 Web Development Server에서 호스팅합니다. 관리되는 호스팅 시나리오에서 WCF에는 Issues.svc 파일이 필요합니다. 특정 년도에 대한 결과를 보려면 브라우저에서 주소(URI)에 해당 년도를 추가하면 됩니다(그림 6 참조).

그림 6 2007년을 나타내는 리소스

2008년 10월에 대한 데이터를 얻으려면 URI는 localhost:1355/Issues.svc/2008/October가 되며 현재로서는 빈 집합을 얻게 됩니다. 기사를 추가하려면 기사의 XML 표현을 HTTP 요청 본문으로 사용하여 해당 URI에 HTTP POST를 수행하면 됩니다.

HTTP의 훌륭한 특성 중 하나는 함께 사용할 수 있는 도구가 풍부하다는 것입니다. 필자가 가장 좋아하는 도구 중 하나로 HTTP 요청 및 응답을 볼 수 있는 Fiddler가 있습니다. 이 도구에는 임의의 HTTP 작업을 수행하는 기능도 있습니다. 즉, Fiddler Request Builder 탭을 사용하여 필요한 HTTP POST(그림 7 참조)를 수행할 수 있습니다. 그림 8에서 POST 다음에 2008년 10월 리소스에 대한 요청을 볼 수 있습니다.

그림 7 Fiddler를 사용하여 새 기사를 생성하기 위해 HTTP POST 요청 수행

그림 8 추가된 기사 리소스

Internet Explorer와 Fiddler도 사실상 클라이언트라고 이야기할 수 있겠지만 실제 클라이언트-서버 구현을 작성하는 것은 지금까지 수행한 간단한 단계의 확장이라고 할 수 있습니다. RESTful 클라이언트를 작성하기 위한 보다 복잡한 예는 이어지는 칼럼에서 다루겠습니다. 클라이언트는 각 리소스의 URI, 그리고 각 URI에 대해 균일 인터페이스의 어떤 부분을 사용해야 하는지 알아야 합니다. 클라이언트는 이러한 정보를 사용하여 자체 기능을 구성하여 서비스와 상호 작용할 수 있습니다.

이 첫 번째 칼럼에서는 .NET 응용 프로그램에서 REST 아키텍처 스타일을 손쉽게 구현하기 위해 기본적인 WCF 기능 집합을 사용하는 방법을 살펴보았습니다. 이러한 내용은 웹 피드(RSS 및 Atom), 그리고 AJAX를 사용하여 JSON으로 인코딩된 리소스 지원을 포함하여 흥미로운 기술을 구현하는 데 기반이 됩니다.

이어지는 칼럼에서는 REST와 WCF에 대한 이러한 기본 지식을 더욱 강화하고 이 스타일과 기술에 기반을 두는 Microsoft 플랫폼의 몇 가지 다른 기능에 대해 자세히 알아보겠습니다. 또한 보안에 대한 질문이나 끝점의 처리를 구현하는 데 대한 개념과 같은 REST에 대한 몇 가지 일반적인 질문에 답하겠습니다.

질문이나 의견이 있으면 sstation@microsoft.com으로 보내시기 바랍니다.

Jon Flanders는 독립 컨설턴트이자 강연자이며 Pluralsight에서 강사로 일하고 있습니다. 전문 분야는 BizTalk Server, Windows Workflow Foundation, 그리고 WCF(Windows Communication Foundation)입니다. 문의 사항이 있으면 masteringbiztalk.com/blogs/jon을 방문하십시오.