다음을 통해 공유


개발자의 Windows Communication Foundation 소개 4

Aaron Skonnard, Pluralsight

원본: 2009년 11월

RTM으로 업데이트됨: 2010년 4월

개요

.NET 4에는 몇 가지 매력적인 새로운 기능이 제공되며 WCF(Windows Communication Foundation) 영역에서 향상된 기능이 제공됩니다. 이러한 WCF 개선 사항은 주로 개발자 환경을 단순화하고, 더 많은 통신 시나리오를 가능하게 하고, "워크플로 서비스"를 일류 시민으로 만들어 WF(Windows Workflow Foundation)와 풍부한 통합을 제공하는 데 중점을 줍니다.

좋은 소식은 대부분의 WCF 4 변경 내용이 오늘날의 일반적인 시나리오를 더 쉽게 만들고 새로운 통신 시나리오 및 개발 스타일을 가능하게 하는 데 초점을 맞추고 있다는 것입니다. 따라서 기존 WCF 솔루션을 .NET 4로 이동하는 것은 마이그레이션 측면에서 상당히 원활합니다. 그런 다음 솔루션에서 활용할 WCF 4 기능을 결정하기만 하면 됩니다. 이 문서의 나머지 부분에서는 새로운 WCF 4 기능 영역 각각에 대해 소개하고 작동 방식을 보여 줍니다.

WCF 4의 새로운 기능

WCF 4에는 다양한 특정 기능이 포함되어 있지만 그림 1에서는 아래 문서 전체에서 집중하게 될 기본 기능 영역을 설명합니다. 이러한 기능 영역은 WCF 4의 새로운 기능 대부분을 요약하고 이 .NET 프레임워크 릴리스에서 제공하는 최상위 기회를 강조합니다.

그림 1: WCF 4 기능 영역

기능 영역 Description

단순화된 구성

기본 엔드포인트, 바인딩 및 동작 구성에 대한 지원을 통해 WCF 구성 섹션을 간소화합니다. 이러한 변경으로 구성이 없는 서비스를 호스트할 수 있으므로 가장 일반적인 WCF 시나리오에 대한 개발자 환경이 크게 간소화됩니다.

검색

표준 WS-Discovery 프로토콜을 준수하는 임시 및 관리되는 서비스 검색 동작 모두에 대한 새로운 프레임워크 지원.

라우팅 서비스

WCF 솔루션에서 사용할 수 있는 구성 가능한 라우팅 서비스에 대한 새로운 프레임워크 지원. 콘텐츠 기반 라우팅, 프로토콜 브리징 및 오류 처리를 위한 기능을 제공합니다.

REST 개선 사항

REST 서비스 개발을 간소화하는 몇 가지 추가 기능 및 도구를 사용하여 WCF WebHttp Services가 향상되었습니다.

워크플로 서비스

선언적 장기 실행 워크플로 서비스를 구현하기 위해 WCF를 WF와 통합하기 위한 풍부한 프레임워크 지원. 이 새로운 프로그래밍 모델은 두 프레임워크가 모두 제공하는 최상의 기능(WCF & WF)을 제공합니다.

이러한 기본 기능 영역을 다루면 향상된 형식 확인 기능, 경쟁 소비자와의 큐 지원("수신 컨텍스트"), 바이트 스트림 인코더를 통한 래핑되지 않은 이진 데이터 지원, 고성능 ETW 기반 추적 지원 등 .NET 4와 함께 제공되는 고급 하위 수준 WCF 기능 중 일부에 대해 간략하게 설명합니다.

완료되면 WCF 4를 사용하기가 더 쉬워지고 오늘날 가장 일반적인 시나리오 및 개발 스타일 중 일부에 대해 더 많은 기본 제공 지원을 제공한다는 것을 알 수 있습니다.

단순화된 구성

3.x에서 WCF에서 제공하는 통합 프로그래밍 모델은 축복이자 저주입니다. 다양한 통신 시나리오에 대한 서비스 논리를 간단하게 작성할 수 있지만 시작하기 전에 이해해야 하는 다양한 기본 통신 옵션을 제공하기 때문에 구성 측면에서 복잡성도 증가합니다.

현실은 WCF 구성은 일반적으로 오늘날 실제로 WCF를 사용하는 가장 비용이 많이 드는 영역이 되며, 이러한 복잡성의 대부분은 처리할 준비가 되지 않은 IT/운영 직원에게 있습니다.

이러한 현실을 감안할 때 WCF 3.x를 사용하는 순 복잡성을 고려할 때 ASMX(웹 서비스)ASP.NET 이전 버전보다 사용하기가 더 어렵다는 결론을 내릴 수 있습니다. ASMX를 사용하면 [WebMethod] 작업을 정의할 수 있었고 런타임은 기본 통신에 대한 기본 구성을 자동으로 제공했습니다. 반면에 WCF 3.x로 이동할 때 개발자는 하나 이상의 엔드포인트를 정의하기 위해 다양한 WCF 구성 옵션에 대해 충분히 알고 있어야 합니다. 그리고 구성 옵션의 어려운 수는 종종 멀리 일부 개발자를 놀라게.

ASMX와 마찬가지로 전체 WCF 환경을 쉽게 만들기 위한 노력의 일환으로 WCF 4에는 모든 WCF 구성의 필요성을 완전히 제거하는 새로운 "기본 구성" 모델이 제공됩니다. 특정 서비스에 대한 WCF 구성을 제공하지 않으면 WCF 4 런타임은 일부 표준 엔드포인트 및 기본 바인딩/동작 구성으로 서비스를 자동으로 구성합니다. 따라서 특히 다양한 WCF 구성 옵션에 익숙하지 않고 최소한 시작하기 위해 기본값을 기꺼이 수락하는 사람들을 위해 WCF 서비스를 훨씬 쉽게 시작하고 실행할 수 있습니다.

기본 엔드포인트

WCF 3.x를 사용하면 구성된 엔드포인트 없이 서비스를 호스트하려고 하면 ServiceHost instance 하나 이상의 엔드포인트를 구성해야 한다는 예외가 발생합니다. WCF 4에서는 런타임에서 하나 이상의 "기본 엔드포인트"를 자동으로 추가하여 구성 없이 서비스를 사용할 수 있도록 하기 때문에 더 이상 그렇지 않습니다.

작동 방식은 다음과 같습니다. 호스트 애플리케이션이 ServiceHost instance Open을 호출하면 호스트 애플리케이션이 명시적으로 구성했을 수 있는 모든 항목과 함께 애플리케이션 구성 파일에서 내부 서비스 설명을 빌드하고 구성된 엔드포인트 수가 여전히 0인 경우 ServiceHost 클래스에 있는 새 공용 메서드인 AddDefaultEndpoints를 호출합니다. 이 메서드는 서비스의 기본 주소를 기반으로 서비스 설명에 하나 이상의 엔드포인트를 추가합니다(IIS 시나리오에서는 .svc 주소임). 메서드는 공용이므로 사용자 지정 호스팅 시나리오에서 직접 호출할 수도 있습니다.

정확하게 말하자면 AddDefaultEndpoints 구현은 서비스에서 구현하는 각 서비스 계약에 대해 기본 주소당 하나의 기본 엔드포인트를 추가합니다. 예를 들어 서비스에서 두 개의 서비스 계약을 구현하고 단일 기본 주소로 호스트를 구성하는 경우 AddDefaultEndpoints는 두 개의 기본 엔드포인트(각 서비스 계약에 대해 하나씩)로 서비스를 구성합니다. 그러나 서비스가 두 개의 서비스 계약을 구현하고 호스트가 두 개의 기본 주소(HTTP용 및 TCP용 주소 하나)로 구성된 경우 AddDefaultEndpoints는 4개의 기본 엔드포인트로 서비스를 구성합니다.

이 작업을 설명하는 전체 예제를 살펴보겠습니다. 다음과 같은 WCF 서비스 계약 및 다음 서비스 구현이 있다고 가정해 보겠습니다.

[ServiceContract]

공용 인터페이스 IHello

{

    [OperationContract]

    void SayHello(string name);

}

[ServiceContract]

공용 인터페이스 IGoodbye

{

    [OperationContract]

    void SayGoodbye(string name);

}

public class GreetingService : IHello, IGoodbye // 서비스는 두 계약을 모두 구현합니다.

{

    public void SayHello(string name)

    {

        Console.WriteLine("Hello {0}", name);

    }

    public void SayGoodbye(string name)

    {

        Console.WriteLine("Goodbye {0}", name);

    }

}

WCF 4를 사용하면 ServiceHost를 사용하여 애플리케이션 구성 없이 GreetingService 서비스를 호스트할 수 있습니다. 사용자 지정 호스팅 시나리오에서 ServiceHost를 사용하는 경우 사용할 기본 주소를 하나 이상 지정해야 합니다. 다음은 콘솔 애플리케이션에서 GreetingService를 호스트하는 방법을 보여 줍니다. 다시 이 프로그램과 연결된 app.config 파일이 없다고 가정할 수 있습니다.

class Program

{

    static void Main(string[] args)

    {

        호스트는 HTTP용과 TCP용으로 하나씩 두 개의 기본 주소로 구성됩니다.

        ServiceHost 호스트 = new ServiceHost(typeof(GreetingService),

            new Uri("https://localhost:8080/greeting"),

            new Uri("net.tcp://localhost:8081/greeting"));

        호스트. Open();

        foreach(호스트의 ServiceEndpoint se. Description.Endpoints)

            Console.WriteLine("A: {0}, B: {1}, C: {2}",

                Se. 주소, se.Binding.Name, se.Contract.Name);

        Console.WriteLine("Enter> 키를 눌러 <서비스를 중지합니다.");

        Console.ReadLine();

        호스트. Close();

    }

}

이 예제에서는 두 개의 기본 주소로 ServiceHost를 구성합니다. 하나는 HTTP용이고 다른 하나는 TCP용입니다. 이 프로그램을 실행하면 그림 2와 같이 콘솔 창에 4개의 엔드포인트가 인쇄됩니다. HTTP 기본 주소에 대해 2개, 계약당 1개, TCP 기본 주소에 대해 2개, 계약당 1개를 가져옵니다. 이 모든 것은 ServiceHost instance 백그라운드에서 제공됩니다.

그림 2: 콘솔 창에 표시되는 기본 엔드포인트

WCF가 기본 HTTP 엔드포인트에 BasicHttpBinding을 사용하고 기본 TCP 엔드포인트에 NetTcpBinding을 사용하도록 선택하는 방법을 확인합니다. 곧 이러한 기본값을 변경하는 방법을 보여 드리겠습니다.

이 기본 엔드포인트 동작은 서비스가 엔드포인트로 구성되지 않은 경우에만 시작됩니다. 하나 이상의 엔드포인트를 사용하여 서비스를 구성하도록 콘솔 애플리케이션을 변경하는 경우 이러한 기본 엔드포인트가 출력에 더 이상 표시되지 않습니다. 이를 설명하기 위해 ServiceHost instance 생성한 후 AddServiceEndpoint를 호출하는 다음 코드 줄을 추가합니다.

...

ServiceHost 호스트 = new ServiceHost(typeof(GreetingService),

    new Uri("https://localhost:8080/greeting"),

    new Uri("net.tcp://localhost:8081/greeting"));

호스트. AddServiceEndpoint(typeof(IHello), 새 WSHttpBinding(), "myendpoint");

...

이 코드 줄을 삽입하여 콘솔 애플리케이션을 실행하는 경우 단일 엔드포인트만 출력에 나타납니다. 즉, 위의 코드에서 수동으로 구성한 엔드포인트입니다(그림 3 참조).

그림 3: 단일 엔드포인트를 사용하여 호스트를 구성한 후 콘솔 출력

그러나 기본 엔드포인트 집합을 사용자 고유의 엔드포인트와 함께 추가하려는 경우 항상 AddDefaultEndpoints를 직접 호출할 수 있습니다. 다음 코드 예제에서는 이 작업을 수행하는 방법을 보여 줍니다.

...

ServiceHost 호스트 = new ServiceHost(typeof(GreetingService),

    new Uri("https://localhost:8080/greeting"),

    new Uri("net.tcp://localhost:8081/greeting"));

호스트. AddServiceEndpoint(typeof(IHello), 새 WSHttpBinding(), "myendpoint");

호스트. AddDefaultEndpoints();

...

이 변경 내용으로 콘솔 애플리케이션을 다시 실행하면 콘솔 창에 5개의 엔드포인트가 표시됩니다. 즉, 네 개의 기본 엔드포인트와 함께 수동으로 구성한 엔드포인트가 표시됩니다(그림 4 참조).

그림 4: AddDefaultEndpoints를 수동으로 호출한 후 콘솔 출력

런타임 시 서비스에 기본 엔드포인트를 추가하는 알고리즘 및 메커니즘을 이해했으므로 다음 질문은 WCF가 특정 기반 주소에 사용할 바인딩을 어떻게 결정하나요?

기본 프로토콜 매핑

이 질문에 대한 대답은 간단합니다. WCF는 전송 프로토콜 구성표(예: http, net.tcp, net.pipe 등)와 기본 제공 WCF 바인딩 간의 기본 프로토콜 매핑을 정의합니다. 기본 프로토콜 매핑은 .NET 4 machine.config.comments 파일에 있으며 다음과 같습니다.

<system.serviceModel>

   <protocolMapping>

      <add scheme="http" binding="basicHttpBinding" bindingConfiguration="" />

      <add scheme="net.tcp" binding="netTcpBinding" bindingConfiguration=""/>

      <add scheme="net.pipe" binding="netNamedPipeBinding" bindingConfiguration=""/>

      <add scheme="net.msmq" binding="netMsmqBinding" bindingConfiguration=""/>

   </protocolMapping>

   ...

이 섹션을 machine.config 추가하고 각 프로토콜 체계에 대한 매핑을 수정하여 컴퓨터 수준에서 이러한 매핑을 재정의할 수 있습니다. 또는 애플리케이션의 scope 내에서만 재정의하려는 경우 애플리케이션/웹 구성 파일 내에서 이 섹션을 재정의할 수 있습니다.

예를 들어 organization 주로 WCF를 사용하여 RESTful 서비스를 빌드하는 데 중점을 두는 경우 "http" 프로토콜 체계에 대한 기본 바인딩을 WebHttpBinding으로 변경하는 것이 합리적일 수 있습니다. 다음 예제에서는 애플리케이션 구성 파일 내에서 이 작업을 수행하는 방법을 보여 줍니다.

<구성>

  <system.serviceModel>

    <protocolMapping>

      <add scheme="http" binding="webHttpBinding"/>

    </protocolMapping>

  </system.serviceModel>

</구성>

이 app.config 함께 이전에 표시된 콘솔 애플리케이션을 다시 실행하면 이제 두 개의 기본 HTTP 기반 엔드포인트가 WebHttpBinding을 사용하고 있음을 표시합니다(그림 5 참조).

그림 5: 기본 HTTP 프로토콜 매핑을 재정의한 후 콘솔 출력

WCF가 프로토콜 매핑 테이블을 통해 사용할 바인딩을 결정하면 기본 엔드포인트를 구성할 때 기본 바인딩 구성을 사용합니다. 기본 제공 바인딩 기본값에 만족하지 않는 경우 특정 바인딩에 대한 기본 구성을 재정의할 수도 있습니다.

기본 바인딩 구성

모든 WCF 바인딩은 특정 엔드포인트에 대해 호스트 애플리케이션에서 명시적으로 재정의하지 않는 한 사용되는 기본 구성과 함께 제공됩니다. 사용하는 각 바인딩 instance 명시적 바인딩 구성을 적용하여 재정의하도록 선택하지 않는 한 항상 기본 제공 기본값과 함께 제공됩니다.

WCF 3.x에서는 bindingConfiguration 특성을 통해 엔드포인트 정의에 적용할 수 있는 명명된 바인딩 구성을 정의하여 이 작업을 수행합니다. 이 작업을 제대로 수행하는 메커니즘은 번거롭고 오류가 발생하기 쉽습니다.  다음 구성 파일은 일반적인 예제를 보여줍니다.

<구성>

  <system.serviceModel>

    <bindings>

      <basicHttpBinding>

        <binding name="BasicWithMtom" messageEncoding="Mtom"/>

      </basicHttpBinding>

    </바인딩>

    <services>

      <service name="GreetingService">

        <endpoint address="mtom" binding="basicHttpBinding"

                  bindingConfiguration="BasicWithMtom"

                  contract="IHello"/>

      </service>

    </서비스>

  </system.serviceModel>

</구성>

위의 예제에서 "BasicWithMtom" 바인딩 구성은 메시지 인코딩을 MTOM으로 변경하여 BasicHttpBinding의 기본값을 재정의합니다. 그러나 이 바인딩 구성은 "bindingConfiguration" 특성을 통해 특정 엔드포인트에 적용할 때만 적용됩니다. 이는 종종 개발자 및 운영 담당자를 회피하여 구성 문제를 일으키는 단계입니다.

이제 WCF 4를 사용하여 새 구성을 정의할 때 바인딩 구성 이름을 생략하여 기본 바인딩 구성을 정의할 수 있습니다. 그런 다음, WCF는 명시적 바인딩 구성이 설정되지 않은 바인딩을 사용하는 모든 엔드포인트에 대해 해당 기본 구성을 사용합니다.

예를 들어 앞서 표시된 콘솔 애플리케이션에 다음 app.config 파일을 추가하면 두 개의 기본 HTTP 엔드포인트가 이 기본 BasicHttpBinding 구성을 선택하여 MTOM을 사용하도록 설정합니다.

<구성>

  <system.serviceModel>

    <bindings>

      <basicHttpBinding>

        <binding messageEncoding="Mtom"/><-- name 특성이 없음을 알 수 있습니다.>

      </basicHttpBinding>

    </바인딩>

  </system.serviceModel>

</구성>

물론 이러한 기본 바인딩 구성을 추가하여 컴퓨터에서 실행되는 모든 서비스에 적용하거나 애플리케이션 구성 파일 내에 기본 바인딩 구성을 추가하여 애플리케이션별로 정의할 수 있는 경우 이러한 기본 바인딩 구성을 machine.config 추가할 수도 있습니다.

이 기능은 다른 개발자 또는 IT/운영 직원에게 바인딩 구성의 복잡성을 부과하지 않고 모든 서비스에서 사용할 수 있는 표준 바인딩 기본값 집합을 정의하는 간단한 메커니즘을 제공합니다. 적절한 바인딩을 선택하기만 하면 적절한 기본 구성이 호스팅 환경에서 제공됩니다.

기본 바인딩 구성 외에도 서비스 및 엔드포인트에 대해 고려해야 할 또 다른 사항은 기본 동작 구성입니다.

기본 동작 구성

또한 WCF 4를 사용하면 서비스 및 엔드포인트에 대한 기본 동작 구성을 정의할 수 있으므로 컴퓨터 또는 솔루션 내에서 실행되는 모든 서비스 또는 엔드포인트에서 표준 기본 동작 구성을 공유하려는 경우 작업을 간소화할 수 있습니다.

WCF 3.x에서는 "behaviorConfiguration" 특성을 통해 서비스 및 엔드포인트에 명시적으로 적용하는 명명된 동작 구성을 정의해야 합니다. WCF 4를 사용하면 구성 정의에서 이름을 생략하여 기본 동작 구성을 정의할 수 있습니다. 이러한 기본 동작을 machine.config 추가하면 컴퓨터에서 호스트되는 모든 서비스 또는 엔드포인트에 적용됩니다. app.config 추가하면 호스트 애플리케이션의 scope 내에서만 적용됩니다. 예를 들면 다음과 같습니다.

<구성>

  <system.serviceModel>

    <behaviors>

      <serviceBehaviors>

        <behavior><-- name 특성이 없음을 알 수 있습니다.>

          <serviceMetadata httpGetEnabled="true"/>

        </동작>

       </serviceBehaviors>

    </동작>

  </system.serviceModel>

</구성>

이 예제에서는 명시적 동작 구성과 함께 제공되지 않는 모든 서비스에 대한 서비스 메타데이터를 설정합니다. 이 기본 동작 구성을 콘솔 애플리케이션의 app.config 파일에 추가하고 애플리케이션을 다시 실행하면 기본 HTTP 주소로 이동하여 서비스 도움말 페이지와 서비스의 WSDL 정의를 검색할 수 있습니다(그림 6 참조).

그림 6: 기본 동작 구성에서 사용하도록 설정된 서비스 메타데이터로 검색

WCF 4의 또 다른 새로운 기능은 동작 구성이 이제 상속 모델을 지원한다는 것입니다. 애플리케이션이 machine.config 이미 정의된 것과 동일한 이름을 사용하여 동작 구성을 정의하는 경우 애플리케이션별 동작 구성이 컴퓨터 전체 구성과 병합되어 파생된 복합 동작 구성에 추가 동작을 추가합니다.

표준 엔드포인트

기본 엔드포인트와 관련된 또 다른 새로운 WCF 4 기능은 "표준 엔드포인트"라고 합니다. 표준 엔드포인트는 간단히 사용할 수 있는 WCF 4 프레임워크에 기본 제공되는 일반적인 미리 구성된 엔드포인트 정의라고 생각할 수 있습니다. 표준 엔드포인트는 일반적으로 변경되지 않는 "표준" 엔드포인트 구성을 정의하지만, 필요한 경우 곧 확인할 수 있습니다.

그림 7에서는 WCF 4와 함께 제공되는 표준 엔드포인트에 대해 설명합니다. 가장 일반적인 WCF 4 기능 및 통신 시나리오 중 일부에 대한 표준 엔드포인트 정의를 제공합니다. 예를 들어 MEX 엔드포인트의 경우 항상 서비스 계약에 대해 IMetadataExchange를 지정해야 하며 HTTP를 선택할 가능성이 가장 높습니다. 따라서 WCF는 항상 수동으로 수행하도록 강요하는 대신 사용하기 쉬운 "mexEndpoint"라는 metdata 교환에 대한 표준 엔드포인트 정의를 제공합니다.

그림 7: WCF 4의 표준 엔드포인트

표준 엔드포인트 이름 Description

mexEndpoint

서비스 계약에 대해 IMetadataExchange로 구성된 MEX의 표준 엔드포인트, mexHttpBinding을 기본 바인딩으로 정의하고(변경할 수 있음) 빈 주소를 정의합니다.

dynamicEndpoint

WCF 클라이언트 애플리케이션 내에서 WCF 검색을 사용하도록 구성된 표준 엔드포인트를 정의합니다. 이 표준 엔드포인트를 사용하는 경우 첫 번째 호출 중에 클라이언트가 지정된 계약과 일치하는 서비스 엔드포인트를 쿼리하고 자동으로 연결하기 때문에 주소가 필요하지 않습니다. 기본적으로 검색 쿼리는 멀티캐스트 UDP를 통해 전송되지만 필요할 때 사용할 검색 바인딩 및 검색 조건을 지정할 수 있습니다.

discoveryEndpoint

클라이언트 애플리케이션 내에서 검색 작업을 위해 미리 구성된 표준 엔드포인트를 정의합니다. 사용자는 이 표준 엔드포인트를 사용할 때 주소와 바인딩을 지정해야 합니다.

udpDiscoveryEndpoint

멀티캐스트 주소에서 UDP 바인딩을 사용하여 클라이언트 애플리케이션 내에서 검색 작업을 위해 미리 구성된 표준 엔드포인트를 정의합니다. DiscoveryEndpoint에서 파생됩니다.

announcementEndpoint

검색의 알림 기능에 대해 미리 구성된 표준 엔드포인트를 정의합니다. 사용자는 이 표준 엔드포인트를 사용할 때 주소와 바인딩을 지정해야 합니다.

udpAnnouncementEndpoint

멀티캐스트 주소의 UDP 바인딩을 통해 공지 기능에 대해 미리 구성된 표준 엔드포인트를 정의합니다. 이 엔드포인트는 announcementEndpoint에서 파생됩니다.

workflowControlEndpoint

워크플로 인스턴스의 실행(만들기, 실행, 일시 중단, 종료 등)을 제어하기 위한 표준 엔드포인트를 정의합니다.

webHttpEndpoint

WebHttpBinding 및 WebHttpBehavior로 구성된 표준 엔드포인트를 정의합니다. REST 서비스를 노출하는 데 사용합니다.

webScriptEndpoint

WebHttpBinding 및 WebScriptEnablingBehavior로 구성된 표준 엔드포인트를 정의합니다. 을 사용하여 Ajax 서비스를 노출합니다.

이러한 표준 엔드포인트는 이름으로 참조하기만 하면 고유한 서비스 구성에서 활용할 수 있습니다. 이제 엔드포인트 요소에는 <표준 엔드포인트> 의 이름을 지정하는 데 사용할 수 있는 "kind" 특성이 함께 제공됩니다. instance 경우 다음 예제에서는 표준 "mexEndpoint" 정의를 활용하여 MEX 엔드포인트로 GreetingService를 구성합니다.

<구성>

  <system.serviceModel>

    <services>

      <서비스 이름="GreetingService">

        <endpoint kind="basicHttpBinding" contract="IHello"/>

        <endpoint kind="mexEndpoint" address="mex" />

      </service>

    </서비스>

  </system.serviceModel>

</구성>

표준 엔드포인트는 대부분의 구성 세부 정보(예: mexEndpoint를 사용하여 바인딩 또는 계약을 지정할 필요가 없음)로부터 보호하지만, 사용하려고 하지만 표준 엔드포인트 정의를 약간 다르게 구성해야 하는 경우도 있습니다. 

이 작업을 수행해야 하는 경우 standardEndpoints 섹션을 <> 사용하고 표준 엔드포인트에 대한 엔드포인트 구성을 재정의할 수 있습니다. 그런 다음, 다음과 같이 endpointConfiguration 특성을 통해 새 <엔드포인트> 를 정의할 때 해당 구성을 참조할 수 있습니다.

<구성>

  <system.serviceModel>

    <services>

      <서비스 이름="GreetingService">

        <endpoint binding="basicHttpBinding" contract="IHello"/>

        <endpoint kind="udpDiscoveryEndpoint" endpointConfiguration="D11"/>

      </service>

    </서비스>

    <standardEndpoints>

      <udpDiscoveryEndpoint>

        <standardEndpoint name="D11" discoveryVersion="WSDiscovery11"/>

      </udpDiscoveryEndpoint>

    </standardEndpoints>

    <behaviors>

      <serviceBehaviors>

        <동작>

          <serviceDiscovery/>

          <serviceMetadata httpGetEnabled="true"/>

        </동작>

      </serviceBehaviors>

    </동작>

  </system.serviceModel>

</구성>

이 예제에서는 "udpDiscoveryEndpoint"라는 표준 엔드포인트의 기본 WS-Discovery 버전을 변경합니다(곧 서비스 검색에 대해 자세히 설명하겠습니다).

IIS/ASP.NET 호스팅 간소화

기본 엔드포인트, 기본 바인딩 구성 및 기본 동작 구성에 대한 이러한 새로운 기능을 고려할 때 IIS/ASP.NET에서 호스팅하는 것이 WCF 4에서 훨씬 쉬워집니다. ASMX 서비스를 사용하는 데 익숙한 ASP.NET 개발자는 이제 본질적으로 단순한 WCF 서비스를 정의할 수 있습니다.

실제로 다음 WCF 서비스 정의가 얼마나 간단한지 검사.

<-- HelloWorld.svc -->

<%@ ServiceHost Language="C#" Debug="true" Service="HelloWorldService

    CodeBehind="~/App_Code/HelloWorldService.cs" %>

[ServiceContract]

public 클래스 HelloWorldService

{

    [OperationContract]

    public string HelloWorld()

    {

        "hello, world"를 반환합니다.

    }

}

이는 서비스 계약을 정의하기 위해 별도의 인터페이스 정의를 사용하지 않고 모든 것이 하나의 파일 HelloWorld.svc에 정의되어 있기 때문에 WCF 서비스 정의의 가장 간단한 형태입니다(참고: ASMX와의 비교를 그릴 수 있다는 점에 유의하여 이 방법을 권장하지 않음). 이는 일반적인 ASMX 서비스와 매우 비슷하게 느껴지며, 주요 차이점은 서비스 클래스(예: [WebService] 및 [WebMethod])에서 사용하는 특성 이름입니다. 움직이는 부품은 확실히 적습니다.

이전 섹션에서 설명한 새로운 WCF 4 기능을 사용하면 이제 추가 WCF 구성 없이 HelloWorld.svc로 이동하고 WCF 활성화 논리는 백그라운드에서 ServiceHost instance 만들고 단일 기본 HTTP 엔드포인트로 구성합니다. 서비스 메타데이터를 사용하도록 설정하는 machine.config 파일에 기본 서비스 동작을 추가한 경우 HelloWorld.svc로 이동하면 WCF 도움말 페이지와 WSDL 정의에 대한 링크가 표시됩니다(그림 8 참조).

그림 8: HelloWorldService 도움말 페이지

시스템 전체에서 서비스 메타데이터를 사용하도록 설정하지 않은 경우 web.config 파일에 다음 기본 동작 구성을 추가하여 웹 애플리케이션 내에서 사용하도록 설정할 수 있습니다.

...

<system.serviceModel>

  <behaviors>

    <serviceBehaviors>

      <behavior><-- name 특성이 없음을 알 수 있습니다.>

         <serviceMetadata httpGetEnabled="true"/>

      </동작>

    </serviceBehaviors>

  </동작>

</system.serviceModel>

...

이전 섹션에서 설명한 절차에 따라 다른 기본 설정을 변경할 수도 있습니다. 예를 들어 기본 프로토콜 매핑을 변경하거나, 기본 바인딩 구성을 추가하거나, 추가 기본 동작 구성을 추가할 수 있습니다. 서비스가 둘 이상의 서비스 계약을 구현하는 경우 결과 ServiceHost instance 계약당 하나의 HTTP 엔드포인트로 구성됩니다.

예를 들어 여기에 표시된 .svc 파일을 통해 GreetingService(이전 버전)를 호스트한다고 가정합니다.

<-- GreetingService.svc -->

<%@ServiceHost Service="GreetingService"%>

GreetingService에 대한 정의를 고려할 때 GreetingService.svc로 처음 검색할 때 WCF 활성화 논리는 ServiceHost instance 만들고 GreetingService 유형(각 서비스 계약에 대해 하나씩)에 대한 두 개의 기본 HTTP 엔드포인트를 추가합니다. WSDL 정의로 이동하여 이를 확인할 수 있으며 서비스> 요소 내에서 <두 개의 <포트> 요소를 찾을 수 있습니다.

전반적으로 이러한 WCF 구성 간소화를 통해 ASP.NET 개발자가 웹 애플리케이션 내에서 WCF 서비스를 훨씬 쉽게 시작하고 실행할 수 있으며, 개발자가 ASP.NET 웹 서비스에 사용된 환경에 훨씬 더 가까운 가장 간단한 사례를 제공합니다.

파일 없는 활성화

.svc 파일을 사용하면 WCF 서비스를 쉽게 노출할 수 있지만 Web.config 내에서 가상 활성화 엔드포인트를 정의하여 .svc 파일에 대한 필요성을 완전히 제거하는 것이 더 쉬운 방법입니다.

WCF 4에서는 Web.config 서비스 유형에 매핑되는 가상 서비스 활성화 엔드포인트를 정의할 수 있습니다. 이렇게 하면 물리적 .svc 파일(즉, "파일 없는 활성화")을 유지 관리하지 않고도 WCF 서비스를 활성화할 수 있습니다. 다음 예제에서는 활성화 엔드포인트를 구성하는 방법을 보여줍니다.

<구성>

  <system.serviceModel>

    <serviceHostingEnvironment>

      <serviceActivations>

        <add relativeAddress="Greeting.svc" service="GreetingService"/>

      </serviceActivations>

    </serviceHostingEnvironment>

  </system.serviceModel>

</구성>

이제 "Greeting.svc"의 상대 경로(웹 애플리케이션의 기본 주소를 기준으로)를 사용하여 GreetingService를 활성화할 수 있습니다. 이를 설명하기 위해 머신에 "GreetingSite"라는 IIS 애플리케이션을 만들었는데, "ASP.NET v4.0" 애플리케이션 풀에 할당하고 위에 표시된 web.config 포함하는 GreetingService 프로젝트 디렉터리에 매핑했습니다. 이제 실제로 디스크에 https://localhost/GreetingSite/Greeting.svc 실제 .svc 파일이 없으면 으로 간단히 찾아볼 수 있습니다. 그림 9는 브라우저의 모양을 보여줍니다.

그림 9: 파일 없는 활성화 예제

검색

논의하려는 다음 주요 WCF 4 기능은 서비스 검색입니다. 일부 특수 서비스 지향 환경에서는 런타임 위치가 동적이며 지속적으로 변화하는 서비스가 있습니다. 예를 들어 다양한 유형의 서비스 지원 디바이스가 전체 비즈니스 솔루션의 일부로 네트워크를 지속적으로 조인하고 나가는 환경을 고려합니다. 이 현실을 처리하려면 클라이언트가 서비스 엔드포인트의 런타임 위치를 동적으로 검색해야 합니다.

WS-Discovery 런타임에 서비스 엔드포인트의 위치를 동적으로 검색하기 위한 SOAP 기반 프로토콜을 정의하는 OASIS 사양입니다. 프로토콜을 사용하면 클라이언트가 특정 조건과 일치하는 서비스 엔드포인트를 검색하여 적합한 후보 목록을 검색할 수 있습니다. 그런 다음 클라이언트는 검색된 목록에서 특정 엔드포인트를 선택하고 현재 런타임 엔드포인트 주소를 사용할 수 있습니다.

WS-Discovery 임시 모드 및 관리 모드의 두 가지 기본 작업 모드를 정의합니다. 임시 모드에서 클라이언트는 멀티캐스트 메시지를 전송하여 서비스를 검색합니다. 프레임워크는 이 임시 모드에 대한 UDP 멀티캐스트 메커니즘을 제공합니다. 프로브와 일치하는 서비스는 클라이언트에 직접 응답합니다. 클라이언트 폴링의 필요성을 최소화하기 위해 서비스는 "수신 대기 중"일 수 있는 클라이언트에 멀티캐스트 메시지를 전송하여 네트워크에 가입하거나 떠날 때 스스로 "알릴" 수도 있습니다. 임시 검색은 멀티캐스팅 메시지에 사용되는 프로토콜에 의해 제한됩니다. UDP의 경우 로컬 서브넷에서 수신 대기하는 서비스만 메시지를 받을 수 있습니다.

관리 서비스 검색을 사용하면 네트워크에서 검색 가능한 서비스 엔드포인트를 "관리"하는 검색 프록시를 제공합니다. 클라이언트는 검색 프록시와 직접 통신하여 검색 기준에 따라 서비스를 찾습니다. 검색 프록시에는 쿼리와 일치할 수 있는 서비스의 리포지토리가 필요합니다. 프록시가 이 정보로 채워지는 방법은 구현 세부 정보입니다. 검색 프록시는 기존 서비스 리포지토리에 쉽게 연결하거나, 엔드포인트 목록으로 미리 구성하거나, 검색 프록시가 캐시를 업데이트하기 위한 공지 사항을 수신 대기할 수도 있습니다. 관리 모드에서 알림은 수신자에게 직접 유니캐스트가 될 수 있으며, 잠재적으로 검색 프록시에 의해 발생할 수 있습니다.

.NET 4.0 프레임워크는 자체 검색 프록시를 구현하는 데 필요한 기본 클래스를 제공합니다. 기본 클래스는 검색 프로토콜 세부 정보를 추상화하므로 검색 프록시에 포함하려는 논리에만 집중할 수 있습니다. 예를 들어 검색 메시지, 알림 메시지 및 해결 메시지에 대한 응답으로 검색 프록시가 수행할 작업을 정의하기만 하면 됩니다.

WCF 4는 WS-Discovery 프로토콜의 완전한 구현을 제공하며 임시 및 관리되는 검색 모드를 모두 지원합니다. 아래 각 항목에 대해 간략하게 살펴보겠습니다.

간단한 서비스 검색

서비스 검색을 사용하도록 설정하는 가장 쉬운 방법은 임시 모드를 사용하는 것입니다. WCF를 사용하면 몇 가지 표준 검색 엔드포인트 및 서비스 검색 동작을 제공하여 서비스 호스트 애플리케이션 내에서 서비스 검색을 쉽게 사용하도록 설정할 수 있습니다. 검색을 위해 서비스를 구성하려면 표준 "udpDiscoveryEndpoint" 엔드포인트를 추가한 다음 서비스에서 serviceDiscovery> 동작을 사용하도록 설정합니다<.

이 작업을 수행하는 방법을 보여 주는 전체 예제는 다음과 같습니다.

<구성>

    <system.serviceModel>

      <services>

        <service name="CalculatorService">

          <endpoint binding="wsHttpBinding" contract="ICalculatorService" />

          <표준 UDP 검색 엔드포인트를 추가할 -- 있습니다.>

          <endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>

        </service>

      </서비스>

      <behaviors>

        <serviceBehaviors>

          <동작>

            <serviceDiscovery/><-- 서비스 검색 동작을 사용하도록 설정합니다.>

          </동작>

        </serviceBehaviors>

      </동작>

    </system.serviceModel>

</구성>

이렇게 하면 로컬 서브넷에서 UDP를 통해 서비스를 검색할 수 있게 됩니다. 그러면 클라이언트는 런타임에 WS-Discovery 활용하여 실행 중인 서비스의 실제 주소를 "검색"할 수 있습니다. WCF 4를 사용하면 클라이언트가 dynamicEndpoint 표준 엔드포인트를 통해 이 작업을 쉽게 수행할 수 있습니다.

서비스에 연결하는 데 사용하던 기존 클라이언트 엔드포인트를 사용하고 주소를 제거하고 kind="dynamicEndpoint" 태그를 추가하기만 하면 됩니다.

<구성>

    <system.serviceModel>

        <client>

          <엔드포인트(endpoint)

              name="calculatorEndpoint"

              kind="dynamicEndpoint"

              binding="wsHttpBinding"

              contract="ICalculatorService">

          </끝점>

        </클라이언트>

    </system.serviceModel>

</구성>

첫 번째 서비스 호출이 수행되면 클라이언트는 ICalculatorService 계약과 일치하는 서비스를 찾는 멀티캐스트 쿼리를 보내고 연결을 시도합니다. 다양한 설정을 사용하면 세러치를 미세 조정하고, 검색 바인딩을 조정하고, 검색 프로세스를 제어할 수 있습니다. DiscoveryClient 클래스를 사용하여 프로그래밍 방식으로 이 모든 작업을 수행할 수도 있습니다.

다음 예제에서는 UdpDiscoveryEndpoint를 프로그래밍 방식으로 사용하여 ICalculatorService 엔드포인트를 검색한 다음 호출하는 방법을 보여 줌으로써 한 단계 더 나아갑니다.

DiscoveryClient 만들기

DiscoveryClient discoveryClient =

    new DiscoveryClient(new UdpDiscoveryEndpoint());

지정된 scope ICalculatorService 엔드포인트를 찾습니다.

FindCriteria findCriteria = new FindCriteria(typeof(ICalculatorService));

FindResponse findResponse = discoveryClient.Find(findCriteria);

처음 검색된 엔드포인트 선택

EndpointAddress address = findResponse.Endpoints[0]. 주소;

대상 서비스 클라이언트 만들기

CalculatorServiceClient 클라이언트 =

    new CalculatorServiceClient("calculatorEndpoint");

검색된 서비스 엔드포인트에 연결

클라이언트. Endpoint.Address = address;

Console.WriteLine("Invoking CalculatorService at {0}", address);

서비스 추가 작업을 호출합니다.

double result = client. Add(100, 15.99);

Console.WriteLine("Add({0},{1}) = {2}", 100, 15.99, result);

클라이언트 프로그램이 검색된 엔드포인트의 컬렉션을 검색한 후에는 그 중 하나를 사용하여 실제로 대상 서비스를 호출할 수 있습니다. 그림 10에서는 서비스가 동시에 실행되고 있다고 가정하여 위에 표시된 클라이언트 코드를 실행하는 출력을 보여 둡니다. 참고: 이 예제에서는 검색 클라이언트의 찾기 작업이 동기적입니다. 검색은 비동기 찾기 작업도 지원합니다.

그림 10: 검색 클라이언트 코드 실행 출력

엔드포인트를 검색할 때 범위 사용

이전 예제에서 클라이언트는 단순히 서비스 계약 유형에 따라 서비스를 검색했습니다. 클라이언트는 검색 프로브를 보낼 때 추가 범위 지정 정보를 제공하여 검색 결과의 범위를 좁힐 수 있습니다. 검색하는 동안 "범위"를 사용하는 방법을 알아보는 간단한 예제를 살펴보겠습니다.

먼저 서비스는 검색을 위해 게시할 각 엔드포인트와 하나 이상의 범위를 연결해야 합니다. WCF 4에는 엔드포인트 정의와 <연결할 수 있는 범위 집합을 정의하는 데 사용할 수 있는 endpointDiscovery> 동작이 함께 제공됩니다. 다음 예제에서는 두 범위를 서비스에 정의된 단일 엔드포인트와 연결하는 방법을 보여 줍니다.

<구성>

    <system.serviceModel>

      <services>

        <service name="CalculatorService"

                 behaviorConfiguration="calculatorServiceBehavior">

          <endpoint binding="wsHttpBinding"

                    contract="ICalculatorService"

                    behaviorConfiguration="ep1Behavior" />

          <endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>

        </service>

      </서비스>

      <behaviors>

        <serviceBehaviors>

          <behavior name="calculatorServiceBehavior">

            <serviceDiscovery/>

          </동작>

        </serviceBehaviors>

        <endpointBehaviors>

          <behavior name="ep1Behavior">

            <endpointDiscovery>

               <이 엔드포인트 동작과 연결된 범위를 --.>

              <scopes>

                <add scope="http://www.example.org/calculator"/>

                <add scope="ldap:///ou=engineering,o=exampleorg,c=us"/>

              </범위>

            </endpointDiscovery>

          </동작>

         </endpointBehaviors>

      </동작>

    </system.serviceModel>

</구성>

클라이언트는 런타임에 특정 범위를 기반으로 서비스 엔드포인트를 검색할 수 있습니다. Find 작업에 제공하는 FindCriteria instance 대상 범위 목록을 추가하여 수행할 수 있습니다. 다음 코드는 특정 LDAP scope 일치하는 ICalculatorService 엔드포인트를 검색하는 방법을 보여 줍니다.

...

DiscoveryClient 만들기

DiscoveryClient discoveryClient = new DiscoveryClient("udpDiscoveryEndpoint");

지정된 scope ICalculatorService 엔드포인트를 찾습니다.

Uri scope = new Uri("ldap:///ou=engineering,o=exampleorg,c=us");

FindCriteria findCriteria = new FindCriteria(typeof(ICalculatorService));

findCriteria.Scopes.Add(scope);

FindResponse findResponse = discoveryClient.Find(findCriteria);

...

범위를 활용하면 클라이언트가 관심 있는 특정 서비스 엔드포인트를 보다 쉽게 검색할 수 있도록 검색 구현을 미세 조정할 수 있습니다. 검색을 통해 추가 사용자 지정도 가능합니다. 예를 들어 서비스는 엔드포인트에 사용자 지정 XML 메타데이터를 추가할 수 있습니다. 이 정보는 클라이언트의 쿼리에 대한 응답으로 클라이언트에 함께 전송됩니다.

서비스 공지 사항

또한 WCF 4를 사용하면 시작 시 엔드포인트를 "발표"하도록 서비스를 쉽게 구성할 수 있습니다. 이를 통해 "수신 대기"하는 클라이언트는 네트워크에 조인할 때 새 서비스 엔드포인트에 대해 바로 알아볼 수 있으므로 클라이언트에서 수행하는 검색(및 멀티캐스트 메시징)의 양을 줄일 수 있습니다.

serviceDiscovery> 동작을 사용하여 알림 엔드포인트로 <서비스를 구성할 수 있습니다. <serviceDiscovery> 동작을 사용하면 서비스에서 노출할 알림 엔드포인트의 컬렉션을 정의할 수 있습니다. 대부분의 경우 표준 "udpAnnouncementEndpoint"를 사용할 수 있습니다.

또한 클라이언트에서 시작한 검색 프로브에 응답하려면 표준 "udpDiscoveryEndpoint"로 서비스를 구성해야 합니다. 다음 예제에서는 일반적인 구성을 보여줍니다.

<구성>

  <system.serviceModel>

    <services>

      <service name="CalculatorService">

        <endpoint binding="wsHttpBinding" contract="ICalculatorService"/>

        <endpoint kind="udpDiscoveryEndpoint"/>

      </service>

    </서비스>

    <behaviors>

      <serviceBehaviors>

        <동작>

          <serviceDiscovery>

            <announcementEndpoints>

              <endpoint kind="udpAnnouncementEndpoint"/>

            </announcementEndpoints>

          </serviceDiscovery>

        </동작>

      </serviceBehaviors>

    </동작>

  </system.serviceModel>

</구성>

이 구성이 적용되면 서비스는 온라인 상태가 되면 자신을 알리고 오프라인 상태가 될 때도 알려줄 것입니다. 이러한 공지를 활용하려면 런타임에 수신 대기하도록 클라이언트를 구체적으로 디자인해야 합니다. WS-Discovery 알림 프로토콜을 구현하는 클라이언트 애플리케이션 내에서 알림 서비스를 호스팅하여 이 작업을 수행합니다.

WCF 4에는 이 목적을 위해 특별히 설계된 AnnouncementService라는 클래스가 함께 제공됩니다. AnnouncementService는 OnlineAnnouncementReceived 및 OfflineAnnouncementReceived라는 두 가지 이벤트 처리기를 제공합니다. 클라이언트 애플리케이션은 ServiceHost를 사용하여 AnnouncementService의 instance 호스트하고 이러한 두 이벤트에 대한 이벤트 처리기를 등록할 수 있습니다.

서비스가 온라인 상태가 되며 자체 발표될 때마다 클라이언트 호스팅 AnnouncementService는 "온라인" 공지 사항을 받게 되며 OnlineAnnouncementReceived는 클라이언트에서 발생합니다. 서비스가 오프라인 상태가 되면 "오프라인" 알림이 전송되고 OfflineAnnouncementReceived가 클라이언트에서 발생합니다. 다음은 AnnouncementService를 호스트하고 두 알림 이벤트에 대한 처리기를 구현하는 샘플 클라이언트 애플리케이션을 보여 줍니다.

class Client

{

    public static void Main()

    {

        AnnouncementService instance 만들기

        AnnouncementService announcementService = new AnnouncementService();

        알림 이벤트 구독

        announcementService.OnlineAnnouncementReceived += OnOnlineEvent;

        announcementService.OfflineAnnouncementReceived += OnOfflineEvent;

        AnnouncementService에 대한 ServiceHost 만들기

        using(ServiceHost announcementServiceHost =

            new ServiceHost(announcementService))

        {

            UDP 멀티캐스트를 통해 전송된 공지 사항 수신 대기

            announcementServiceHost.AddServiceEndpoint(

                new UdpAnnouncementEndpoint());

            announcementServiceHost.Open();

            Console.WriteLine("서비스 공지 수신 대기");

                    Console.WriteLine();

            Console.WriteLine("Enter> 키를 눌러 <종료합니다.");

            Console.ReadLine();

        }

    }

    static void OnOnlineEvent(object sender, AnnouncementEventArgs e)

    {

                Console.WriteLine();

        Console.WriteLine("에서 온라인 공지 {0}수신:",

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(예: EndpointDiscoveryMetadata);

    }

    static void OnOfflineEvent(object sender, AnnouncementEventArgs e)

    {

                Console.WriteLine();

        Console.WriteLine("에서 {0}오프라인 공지 수신:",

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(예: EndpointDiscoveryMetadata);

    }

    ...

}

그림 11: 검색 알림 메시지 수신 대기

이제 이 클라이언트 프로그램을 실행하고 잠시 동안 실행 중인 상태로 유지한다고 가정해 보겠습니다. 그런 다음 나중에 서비스 호스트 애플리케이션의 몇 가지 인스턴스를 실행합니다. 각 알림이 시작되면 클라이언트 콘솔 창에 "온라인" 알림 메시지가 표시됩니다. 각 서비스 호스트 애플리케이션을 닫으면 클라이언트 콘솔 창에 "오프라인" 알림 메시지가 표시됩니다. 그림 11은 방금 설명한 작업을 수행한 후의 결과 클라이언트 콘솔 창을 보여줍니다.

임시 검색 모드는 로컬 서브넷에서만 작동합니다. 로컬 네트워크의 경계를 벗어나는 WS-Discovery 사용하려면 관리되는 검색 모드로 전환해야 합니다. WCF 4는 필요한 관리되는 검색 구성 요소 빌드도 지원합니다.

관리되는 서비스 검색

관리되는 검색 모드를 구현하려면 검색 프록시 서비스를 구현해야 하므로 임시 모드보다 약간 더 복잡합니다. 검색 프록시 서비스는 사용 가능한 모든 서비스 엔드포인트를 추적하는 구성 요소입니다. 이 예제에서는 알림 기능을 사용하여 검색 프록시를 업데이트합니다. 검색 프록시에 관련 검색 정보를 제공하는 다른 여러 가지 방법이 있습니다. 예를 들어 기존 엔드포인트 데이터베이스를 연결하고 여기에서 데이터를 캡처할 수 있습니다. 그렇다면 검색 프록시 서비스를 구현하려면 어떻게 해야 할까요?

WCF 4에는 검색 프록시 서비스를 구현하기 위해 에서 파생할 수 있는 DiscoveryProxy라는 기본 클래스가 함께 제공됩니다. 그림 12는 사용자 지정 검색 프록시 서비스 구현의 시작을 보여줍니다. .NET 4 SDK 샘플에는 참조에 대한 전체 샘플 구현이 포함되어 있습니다. 검색 프록시 서비스 구현이 완료되면 어딘가에 호스트해야 합니다.

그림 12: 사용자 지정 검색 프록시 서비스 구현

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,

    ConcurrencyMode = ConcurrencyMode.Multiple)]

public 클래스 MyDiscoveryProxy: DiscoveryProxyBase

{

    EndpointDiscoveryMetadata를 저장할 리포지토리입니다.

    대신 데이터베이스 또는 플랫 파일을 사용할 수도 있습니다.

    <사전 EndpointAddress, EndpointDiscoveryMetadata> onlineServices;

    public MyDiscoveryProxy()

    {

        this.onlineServices =

            new Dictionary<EndpointAddress, EndpointDiscoveryMetadata>();

    }

    프록시에서 Hello 메시지를 받으면 OnBeginOnlineAnnouncement가 호출됩니다.

    protected override IAsyncResult OnBeginOnlineAnnouncement(

        DiscoveryMessageSequence 메시지Sequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, AsyncCallback 콜백, 개체 상태)

    {

        이. AddOnlineService(endpointDiscoveryMetadata);

        return new OnOnlineAnnouncementAsyncResult(callback, state);

    }

    protected override void OnEndOnlineAnnouncement(IAsyncResult result)

    {

        OnOnlineAnnouncementAsyncResult.End(result);

    }

    프록시에서 Bye 메시지를 받으면 OnBeginOfflineAnnouncement가 호출됩니다.

    protected override IAsyncResult OnBeginOfflineAnnouncement(

        DiscoveryMessageSequence 메시지Sequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, AsyncCallback 콜백, 개체 상태)

    {

        이. RemoveOnlineService(endpointDiscoveryMetadata);

        반환 새 OnOfflineAnnouncementAsyncResult(콜백, 상태);

    }

    protected override void OnEndOfflineAnnouncement(IAsyncResult result)

    {

        OnOfflineAnnouncementAsyncResult.End(result);

    }

    프록시에서 프로브 요청 메시지를 받을 때 OnBeginFind가 호출됩니다.

    protected override IAsyncResult OnBeginFind(

        FindRequestContext findRequestContext, AsyncCallback 콜백, 개체 상태)

    {

        이. MatchFromOnlineService(findRequestContext);

        새 OnFindAsyncResult(콜백, 상태);를 반환합니다.

    }

    protected override void OnEndFind(IAsyncResult result)

    {

        OnFindAsyncResult.End(result);

    }

    ...

이 예제에서는 콘솔 애플리케이션에서 MyDiscoveryProxy 서비스를 호스트하기만 하면 됩니다.  검색 엔드포인트와 알림 엔드포인트라는 두 개의 엔드포인트를 사용하여 호스트를 구성합니다. 다음 예제에서는 이러한 두 엔드포인트를 모두 사용하여 MyDiscoveryProxy 서비스를 올바르게 호스트하는 방법을 보여 줍니다.

class Program

{

    public static void Main()

    {

        Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");

        Uri announcementEndpointAddress =

            new Uri("net.tcp://localhost:9021/Announcement");

        ServiceHost proxyServiceHost = new ServiceHost(new MyDiscoveryProxy());

        DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(

            new NetTcpBinding(), 새 EndpointAddress(probeEndpointAddress));

        discoveryEndpoint.IsSystemEndpoint = false;

        AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(

            new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));

        proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);

        proxyServiceHost.AddServiceEndpoint(announcementEndpoint);

        proxyServiceHost.Open();

        Console.WriteLine("프록시 서비스가 시작되었습니다.");

                Console.WriteLine();

        Console.WriteLine("Enter> 키를 눌러 <서비스를 종료합니다.");

                Console.WriteLine();

        Console.ReadLine();

        proxyServiceHost.Close();

    }

}

검색 프록시 서비스가 실행되고 나면 검색 프록시 서비스에 직접 알리도록 서비스를 구성할 수 있습니다. 마찬가지로 검색 프록시 서비스를 직접 검색하도록 클라이언트 애플리케이션을 구성할 수 있습니다(더 이상 멀티캐스트 메시징 없음).

서비스 호스트 애플리케이션 내에서 AnnouncementEndpoint를 만들 때 검색 프록시의 알림 주소를 지정하여 검색 프록시 서비스에 직접 알리도록 서비스를 구성합니다. 다음 예제에서는 이 작업을 수행하는 방법을 보여줍니다.

...

Uri baseAddress = new Uri("net.tcp://localhost:9002/CalculatorService/" +

    Guid.NewGuid(). ToString());

Uri announcementEndpointAddress = new Uri("net.tcp://localhost:9021/Announcement");

ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService), baseAddress);

ServiceEndpoint netTcpEndpoint = serviceHost.AddServiceEndpoint(

    typeof(ICalculatorService), 새 NetTcpBinding(), 문자열입니다. 비어 있음);

호스트된 프록시 서비스를 가리키는 알림 엔드포인트 만들기

AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(

    new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));

ServiceDiscoveryBehavior serviceDiscoveryBehavior = new ServiceDiscoveryBehavior();

serviceDiscoveryBehavior.AnnouncementEndpoints.Add(announcementEndpoint);

serviceHost.Description.Behaviors.Add(serviceDiscoveryBehavior);

serviceHost.Open();

...

그런 다음 클라이언트 애플리케이션 내에서 DiscoveryEndpoint를 만들 때 검색 프록시의 프로브 주소를 지정하여 검색 프록시 서비스와 직접 통신하도록 클라이언트 애플리케이션을 구성할 수 있습니다. 다음 예제에서는 이 작업을 수행하는 한 가지 방법을 보여 줍니다.

...

프록시 서비스를 가리키는 검색 엔드포인트를 만듭니다.

Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");

DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(

    new NetTcpBinding(), 새 EndpointAddress(probeEndpointAddress));

이전에 만든 discoveryEndpoint를 사용하여 DiscoveryClient 만들기

DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint);

ICalculatorService 엔드포인트 찾기

FindResponse findResponse = discoveryClient.Find(

    new FindCriteria(typeof(ICalculatorService)));

...

이제 전체 예제를 살펴보겠습니다. 먼저 검색 프록시 서비스를 사용할 수 있도록 검색 프록시 애플리케이션을 실행합니다. 그런 다음, 검색 프록시를 사용하여 자신을 알리는 서비스 호스트 애플리케이션의 instance 실행합니다. 이 경우 검색 프록시 애플리케이션의 콘솔 창에 인쇄된 메시지가 표시됩니다(그림 13 참조). 이는 서비스가 검색 프록시에 성공적으로 발표되었고 검색 프록시가 새로운 "온라인" 서비스 엔드포인트에 대한 정보를 저장했음을 보여 줍니다. 이제 위에 표시된 클라이언트 코드를 실행하면 검색 프록시를 직접 검색하고 현재 실행 중인 대상 서비스의 엔드포인트 주소를 검색합니다.

그림 13: 런타임 시 검색 프록시 서비스의 출력

관리 서비스 검색의 아름다움은 네트워크 경계(기존 서비스 호출 기반)에서 작동하며 검색 솔루션 내에서 멀티캐스트 메시징의 필요성을 줄인다는 것입니다. 또한 클라이언트는 검색 프록시를 통해 서비스를 찾기 때문에 서비스 자체를 검색하기 위해 항상 가동 및 실행할 필요가 없습니다.

고급 검색 프록시 사용

WCF 프로그래밍 모델은 검색 프록시를 구현하는 데 많은 유연성을 제공합니다. 알림 수신은 서비스 목록을 채우는 한 가지 방법입니다. 그러나 유일한 메서드는 아닙니다. 예를 들어 환경에 서비스 리포지토리가 이미 포함되어 있는 경우 런타임에 리포지토리를 검색할 수 있도록 해당 저장소 위에 검색 프록시 외관을 쉽게 빌드할 수 있습니다.

검색 프록시는 임시 또는 관리 모드에서 설정할 수 있습니다. 관리 모드에서 작동하는 경우 클라이언트는 공지, 프로브 및 해결을 사용하여 유니캐스트 방식으로 프록시와 직접 통신합니다. 또한 프록시는 유니캐스트 방식으로 응답을 보낸 사람에게 다시 전송합니다.

임시 모드에서 작동하는 경우 프록시는 멀티캐스트 검색 메시지를 수신 대기하고 보낸 사람에게 직접 응답할 수 있습니다. 이 임시 모드에서는 멀티캐스트 메시지를 표시하지 않게 프록시를 구체적으로 구성할 수도 있습니다. 즉, 프록시가 멀티캐스트 메시지를 수신하는 경우 발신자에게 현재 상태를 알리고 보낸 사람에게 프록시에서 추가 쿼리를 지시하도록 알려 추가 멀티캐스트 메시지를 방지합니다.

이러한 고급 검색 시나리오에 대한 자세한 내용은 의 WS-Discovery 입문서 를 http://www.oasis-open.org/committees/download.php/32184/WS-D-primer-wd-04.docx참조하세요.

라우팅 서비스

일부 서비스 지향 환경에서는 브로커 또는 게이트웨이 역할을 하는 중앙 집중식 "라우팅" 서비스를 organization 중심으로 분산된 실제 비즈니스 서비스에 활용하는 것이 유용한 경우가 많습니다. 이렇게 하면 소비자가 실제 비즈니스 서비스와 분리되고 라우팅 노드 내에서 다양한 유형의 중간 처리를 수행할 수 있습니다.

예를 들어 일부 환경에서는 라우팅을 사용하여 들어오는 모든 메시지가 통과해야 하는 중앙 집중식 보안 경계를 구현합니다. 일부는 콘텐츠 기반 라우팅 기술을 사용하여 들어오는 특정 메시지의 콘텐츠를 기반으로 사용할 대상 서비스를 결정합니다. 다른 사용자는 라우팅을 사용하여 프로토콜 브리징을 구현하므로 라우터가 다른 프로토콜 집합을 사용하여 대상 서비스와 통신하는 동안 소비자가 하나의 프로토콜 집합을 사용하여 통신할 수 있습니다. 다양한 부하 분산 또는 서비스 버전 관리 기술에 라우팅을 사용하는 것도 드문 일이 아닙니다.

이유가 무엇이든 간에 "중간 라우팅" 패턴은 오늘날 대규모 SOA 솔루션을 빌드할 때 일반적인 요구 사항입니다. WCF 3.x에서는 라우팅에 대한 공식적인 지원이 없었습니다. 프레임워크는 자체 라우팅 서비스를 구현하는 데 필요한 API를 제공했지만 제대로 수행하려면 많은 작업이 필요했습니다. 이 작업을 수행하는 방법을 보여주는 몇 가지 문서가 MSDN Magazine에 게시되었습니다.

라우팅은 요즘 매우 일반적인 요구 사항이기 때문에 WCF 4는 이제 프레임워크에서 자체 솔루션에서 단순히 호스트하고 구성할 수 있는 공식 "라우팅 서비스"를 제공합니다.

RoutingService 이해

WCF 4에는 애플리케이션 내에서 사용할 수 있는 일반 WCF 라우팅 구현을 제공하는 RoutingService라는 새 클래스가 함께 제공됩니다. RoutingService는 단방향, 요청 응답 및 이중 메시징과 같은 다양한 메시징 패턴을 사용하여 WCF 지원 프로토콜을 통해 라우팅 메시지를 처리할 수 있습니다. 다음은 RoutingService 클래스 정의를 보여줍니다.

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any,

    InstanceContextMode = InstanceContextMode.PerSession,

    UseSynchronizationContext = false, ValidateMustUnderstand = false),

 AspNetCompatibilityRequirements(RequirementsMode =

    AspNetCompatibilityRequirementsMode.Allowed)]

public sealed 클래스 RoutingService: // contracts는 서로 다른 통신 패턴을 허용합니다.

    ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter,

    IDuplexSessionRouter, IDisposable

{

    ... // 구현 생략

}

보듯이 RoutingService 클래스는 여러 메시징 패턴을 지원하기 위해 여러 서비스 계약에서 파생됩니다. 각 서비스 계약은 적절한 경우 세션 기반 통신 지원을 포함하여 다양한 메시징 패턴을 지원합니다.

RoutingService의 전체 목적은 소비자로부터 들어오는 메시지를 수신하고 적절한 다운스트림 서비스로 "라우팅"하는 것입니다. RouterService는 메시지 필터 집합에 대해 들어오는 각 메시지를 평가하여 사용할 대상 서비스를 결정합니다. 따라서 개발자는 일반적으로 구성 파일에서 메시지 필터를 정의하여 라우팅 동작을 제어합니다. 대상 서비스는 RouterService와 동일한 컴퓨터에 상주할 수 있지만, 네트워크 간에 배포될 수도 있고 다양한 프로토콜이 필요할 수도 있습니다.

RoutingService 호스팅

다른 WCF 서비스와 마찬가지로 애플리케이션에서 RoutingService를 호스트할 수 있습니다. ServiceHost instance 만들고 서비스 유형에 대해 RoutingService를 지정하기만 하면 됩니다. ServiceHost instance Open을 호출하면 RoutingService는 다음과 같이 메시지를 "라우팅"할 준비가 됩니다.

using System;

System.ServiceModel 사용;

System.ServiceModel.Routing을 사용합니다.

public static void Main()

{

    RoutingService 형식에 대한 ServiceHost를 만듭니다.

    using(ServiceHost serviceHost =

        new ServiceHost(typeof(RoutingService))

    {

        다음을 시도해 보세요.

        {

            serviceHost.Open();

            Console.WriteLine("라우팅 서비스가 현재 실행 중입니다.");

            Console.WriteLine("Enter> 키를 눌러 <라우터를 종료합니다.");

            이제 서비스에 액세스할 수 있습니다.

            Console.ReadLine();

            serviceHost.Close();

        }

        catch(CommunicationException)

        {

            serviceHost.Abort();

        }

    }

}

또한 다른 서비스와 마찬가지로 RoutingService를 구성하고 라우팅 필터를 정의합니다. 먼저 하나 이상의 엔드포인트를 사용하여 구성해야 합니다. 라우팅 엔드포인트를 정의할 때 WCF 바인딩과 위에 표시된 RoutingService에서 구현한 라우팅 서비스 계약 중 하나를 선택합니다(예: ISimplexDatagramRouter, IRequestReplyRouter 등). 여러 메시징 패턴 또는 WCF 바인딩을 지원하려는 경우 RoutingService에 둘 이상의 엔드포인트를 노출할 수 있습니다.

다음 예제에서는 4개의 라우팅 엔드포인트인 BasicHttpBinding(단방향 및 요청-회신)을 사용하는 두 개와 WSHttpBinding(단방향 및 request-reply)을 사용하는 두 개의 라우팅 엔드포인트를 사용하여 RoutingService를 구성하는 방법을 보여 줍니다. 다른 WCF 서비스를 구성하는 것과 같은지 알아봅니다.

<구성>

  <system.serviceModel>

    <services>

      <-- 라우팅 서비스 -->

      <서비스 동작Configuration="routingData"

          name="System.ServiceModel.Routing.RoutingService">

        <host>

          <baseAddresses>

            <add baseAddress="https://localhost:8000/routingservice/router"/>

          </baseAddresses>

        </호스트>

        <!--

          라우터가 수신 대기할 엔드포인트를 정의하고 구성합니다.

          사용하려는 계약입니다. 라우터 제공 계약은 다음과 같습니다.

          ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter 및

          IDuplexSessionRouter.

         -->

        <endpoint address="oneway-basic"

                  binding="basicHttpBinding"

                  name="onewayEndpointBasic"

                  contract="System.ServiceModel.Routing.ISimplexDatagramRouter" />

        <endpoint address="oneway-ws"

                  binding="wsHttpBinding"

                  name="onewayEndpointWS"

                  contract="System.ServiceModel.Routing.ISimplexDatagramRouter" />

        <endpoint address="twoway-basic"

                  binding="basicHttpBinding"

                  name="reqReplyEndpointBasic"

                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />

        <endpoint address="twoway-ws"

                  binding="wsHttpBinding"

                  name="reqReplyEndpointWS"

                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />

      </service>

    </서비스>

    ...

ISimplexDatagramRouter 및 IRequestReplyRouter 인터페이스는 비즈니스별 서비스 계약과 함께 사용할 수 있는 제네릭 단방향 및 요청-회신 서비스 계약 정의를 정의합니다. 다음은 이러한 인터페이스가 WCF에서 정의된 방법을 보여 줍니다.

[ServiceContract(Namespace="https://schemas.microsoft.com/netfx/2009/05/routing",

    SessionMode = SessionMode.Allowed)]

공용 인터페이스 ISimplexDatagramRouter

{

    [OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]

    IAsyncResult BeginProcessMessage(Message message, AsyncCallback 콜백,

        개체 상태);

    void EndProcessMessage(IAsyncResult 결과);

}

[ServiceContract(Namespace="https://schemas.microsoft.com/netfx/2009/05/routing",

    SessionMode = SessionMode.Allowed)]

공용 인터페이스 IRequestReplyRouter

{

    [OperationContract(AsyncPattern = true, IsOneWay= false, Action = "*",

        ReplyAction = "*")]

    [GenericTransactionFlow(TransactionFlowOption.Allowed)]

    IAsyncResult BeginProcessRequest(Message message, AsyncCallback 콜백,

        개체 상태);

    메시지 EndProcessRequest(IAsyncResult 결과);

}

위의 엔드포인트 구성은 소비자가 사용할 라우팅 엔드포인트를 노출합니다.  클라이언트 애플리케이션은 클라이언트 코드 내에서 사용할 이러한 엔드포인트 중 하나를 선택하고 모든 서비스 호출을 RoutingService로 직접 전달합니다. RoutingService는 이러한 엔드포인트 중 하나를 통해 메시지를 받으면 라우팅 메시지 필터를 평가하여 메시지를 전달할 위치를 결정합니다.

메시지 필터를 사용하여 RoutingService 구성

코드 또는 구성(예: WCF의 다른 모든 항목)을 통해 메시지 필터를 사용하여 RoutingService를 구성할 수 있습니다. WCF 4는 라우팅 메시지 필터를 관리하기 위한 RoutingBehavior를 제공합니다. 먼저 RouterService에서 RoutingBehavior를 사용하도록 설정한 다음, RoutingService의 이 특정 instance 사용할 필터 테이블의 이름을 지정해야 합니다.

<구성>

  <system.serviceModel>

    ...

    <behaviors>

      <serviceBehaviors>

        <behavior name="routingData">

          <serviceMetadata httpGetEnabled="True"/>

          <-- 라우팅 동작을 정의하고 필터 테이블 이름을 지정합니다.>

          <라우팅 filterTableName="filterTable1" />

        </동작>

      </serviceBehaviors>

    </동작>

    ...

엔드포인트를 사용하여 RoutingService를 구성한 이전 예제를 살펴보면 behaviorConfiguration 특성을 통해 서비스에 "routingData" 동작을 적용한 것을 볼 수 있습니다. 다음으로 "filterTable1"이라는 필터 테이블을 정의해야 합니다.

그러나 필터 테이블을 정의하려면 라우팅하려는 대상 서비스에 대한 엔드포인트 정의가 필요합니다. RoutingService는 대상 서비스에 메시지를 전달할 때 기본적으로 "클라이언트"이므로 WCF <클라이언트> 구성 섹션 내에서 이러한 대상 엔드포인트를 정의합니다. 다음 예제에서는 라우팅할 수 있는 두 개의 대상 엔드포인트를 정의하는 방법을 보여 줍니다.

<구성>

    ...

    <-- 라우터가 통신할 클라이언트 엔드포인트를 정의합니다.

         라우터가 메시지를 보낼 대상입니다. -->

    <client>

      <endpoint name="CalculatorService1"

       address="https://localhost:8000/servicemodelsamples/calcservice1"

       binding="wsHttpBinding" contract="*" />

      <endpoint name="CalculatorService2"

       address="https://localhost:8001/servicemodelsamples/calcservice2"

       binding="wsHttpBinding" contract="*" />

    </클라이언트>

    ...

이제 런타임에 라우팅 논리를 결정하는 실제 필터 테이블을 정의할 수 있습니다. filterTables 요소 내에서 <필터 테이블 항목을 정의합니다> . filterTable> 내의 <각 항목은 라우팅 "필터"와 대상 엔드포인트 간의 매핑을 정의합니다. filters 요소 내에서 <사용하려는 "필터"를 정의합니다> . 각 <필터> 항목은 필터별 데이터(예: 작업 값, XPath 식 등)와 함께 사용할 필터 유형을 지정합니다.

다음 예제에서는 CalculatorService1 엔드포인트에 매핑되는 단일 필터를 사용하여 필터 테이블을 구성하는 방법을 보여 줍니다. 이 경우 "MatchAll" 필터는 들어오는 모든 메시지와 일치합니다.

<구성>

    ...

    <-- 경로 지정 섹션 -->

    <routing>

      <-- 라우터에서 사용할 필터를 정의합니다. -->

      <filters>

        <filter name="MatchAllFilter1" filterType="MatchAll" />

      </필터>

      <-- matchAll 필터가 포함된 필터 테이블을 정의합니다.>

      <filterTables>

        <filterTable name="filterTable1">

            <-- 이전에 정의된 클라이언트 엔드포인트에 필터를 매핑합니다.

                 이 필터와 일치하는 메시지가 해당 대상으로 전송됩니다. -->

          <add filterName="MatchAllFilter1" endpointName="CalculatorService1" />

        </filterTable>

      </filterTables>

    </라우팅>

  </system.serviceModel>

</구성>

라우팅 서비스 호스트 애플리케이션, CalculatorService1 호스트 애플리케이션 및 라우터 엔드포인트 중 하나에 메시지를 보내도록 설계된 클라이언트를 실행하여 라우팅이 제대로 작동하는지 확인할 수 있습니다. 클라이언트를 실행할 때 메시지가 중간 RoutingService에 의해 "라우팅"된 후 CalculatorService 1에 도착하는 것을 볼 수 있습니다(그림 14, 그림 15 및 그림 16 참조).

그림 14: RoutingService 호스트 애플리케이션

그림 15: 에서 RoutingService를 대상으로 하는 클라이언트 https://localhost:8000/routingservice/router

그림 16: 대상 서비스(CalculatorService1)

메시지 필터 및 콘텐츠 기반 라우팅

WCF에는 라우팅 메시지 필터와 함께 사용하여 들어오는 메시지의 콘텐츠를 검사하는 데 사용할 수 있는 몇 가지 기본 제공 MessageFilter 클래스가 함께 제공됩니다.

예를 들어 WCF는 특정 WS-Addressing "action" 값을 일치시킬 수 있는 ActionMessageFilter를 제공합니다. 또한 WCF는 특정 엔드포인트 세부 정보를 일치시킬 수 있는 EndpointAddressMessageFilter, EndpointNameMessageFilter 및 PrefixEndpointAddressMessageFilter를 제공합니다. 가장 유연한 것 중 하나는 들어오는 메시지에 대해 XPath 식을 평가할 수 있는 XPathMessageFilter입니다. 이러한 모든 필터를 사용하면 솔루션 내에서 콘텐츠 기반 라우팅을 수행할 수 있습니다.

이러한 기본 제공 MessageFilter 형식 외에도 WCF 4를 사용하면 RoutingService의 기본 확장점 중 하나인 사용자 지정 메시지 필터를 정의할 수도 있습니다.

작업 값을 기반으로 콘텐츠 기반 라우팅을 수행하는 예제를 살펴보겠습니다. CalculatorService 작업의 절반을 CalculatorService1로, 나머지 절반은 CalculatorService2로 라우팅하려고 합니다. 다음과 같이 각 다른 CalculatorService 작업 값에 대한 필터를 정의하고 그 중 절반을 각 대상 서비스 엔드포인트에 매핑하여 이 작업을 수행할 수 있습니다.

<구성>

    ...

    <-- 경로 지정 섹션 -->

    <routing>

      <-- 라우터에서 사용할 필터를 정의합니다. -->

     <filters>

        <filter name="addFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Add"/>

         <filter name="subFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Subtract"/>

        <filter name="mulFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Multiply"/>

        <filter name="divFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Divide"/>

      </필터>

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"/>

          <add filterName="subFilter" endpointName="CalculatorService2"/>

          <add filterName="mulFilter" endpointName="CalculatorService1"/>

          <add filterName="divFilter" endpointName="CalculatorService2"/>

        </filterTable>

      </filterTables>

    </라우팅>

  </system.serviceModel>

</구성>

이제 솔루션을 실행하고 네 가지 작업을 모두 호출하는 클라이언트를 실행하면 작업의 절반이 각 서비스 콘솔 창에 표시됩니다(그림 17 및 그림 18 참조).

그림 17: CalculatorService1의 출력

그림 18: CalculatorService2의 출력

XPathMessageFilter는 들어오는 메시지에 대해 평가할 다양한 XPath 식을 제공할 수 있으므로 훨씬 더 유연합니다. XPath 식은 SOAP 헤더 또는 SOAP 본문을 포함하여 들어오는 메시지의 모든 부분을 평가할 수 있습니다. 이렇게 하면 콘텐츠 기반 메시지 필터를 빌드할 때 많은 유연성을 얻을 수 있습니다. XPathMessageFilter의 메커니즘을 이해하기 위해 다음에서는 XPath 식을 사용하여 마지막 예제를 다시 작성하는 방법을 보여 줍니다.

<구성>

    ...

    <-- 경로 지정 섹션 -->

    <routing>

      <-- 라우터에서 사용할 필터를 정의합니다. -->

     <filters>

        <filter name="addFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Add'"/>

        <filter name="subFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Subtract'"/>

        <filter name="mulFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Multiply'"/>

        <filter name="divFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Divide'"/>

      </필터>

      <namespaceTable>

        <add prefix="s" namespace="http://www.w3.org/2003/05/soap-envelope" />

        <add prefix="wsa" namespace="http://www.w3.org/2005/08/addressing" />

      </namespaceTable>

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"/>

          <add filterName="subFilter" endpointName="CalculatorService2"/>

           <add filterName="mulFilter" endpointName="CalculatorService1"/>

          <add filterName="divFilter" endpointName="CalculatorService2"/>

        </filterTable>

      </filterTables>

    </라우팅>

  </system.serviceModel>

</구성>

filterData 특성에는 들어오는 메시지에 대해 평가되는 XPath 식이 포함되어 있습니다(식은 이 예제의 작업 값을 검사). 네임스페이스Table> 요소를 사용하여 <네임스페이스 접두사 바인딩 집합도 어떻게 정의했는지 확인합니다. 위에서 수행한 것처럼 XPath 식 내에서 네임스페이스 접두사를 사용하려는 경우에 필요합니다. 이 구성을 사용하여 솔루션을 다시 실행하면 이전과 동일한 결과가 생성됩니다(그림 17 및 그림 18 참조).

사용자 지정 SOAP 헤더를 기반으로 하거나 SOAP 메시지 본문에 있는 콘텐츠를 기반으로 메시지를 라우팅해야 할 때마다 이 XPath 필터 기술을 사용해야 합니다.

프로토콜 브리징

이전 예제에서는 동일한 WCF 바인딩(WSHttpBinding)을 사용하여 클라이언트와 라우터 간에, 라우터와 대상 서비스 간에 통신했습니다. RoutingService는 대부분의 WCF 바인딩에서 통신을 브리징할 수 있습니다. 예를 들어 클라이언트가 WSHttpBinding을 통해 통신하도록 라우터를 구성할 수 있지만 라우터는 NetTcpBinding 또는 NetNamedPipeBinding을 사용하여 다운스트림 대상 서비스와 통신합니다.

이 시나리오를 처리하도록 RoutingService를 구성하는 방법을 살펴보겠습니다. RoutingService 엔드포인트 구성은 위와 동일하게 둡니다. 그러면 소비자가 BasicHttpBinding 또는 WSHttpBinding을 통해 RoutingService와 통신할 수 있습니다. 하지만 이제 다음과 같이 NetTcpBinding 및 NetNamedPipeBinding을 사용하도록 대상 서비스에 대한 클라이언트 엔드포인트 정의를 변경합니다.

<구성>

    ...

    <-- 라우터가 통신할 클라이언트 엔드포인트를 정의합니다.

         라우터가 메시지를 보낼 대상입니다. -->

    <client>

      <endpoint name="CalculatorService1"

       address="net.tcp://localhost:8001/servicemodelsamples/calcservice1"

       binding="netTcpBinding" contract="*" />

      <endpoint name="CalculatorService2"

       address="net.pipe://localhost/servicemodelsamples/calcservice2"

       binding="netNamedPipeBinding" contract="*" />

    </클라이언트>

    ...

물론 호환되는 NetTcpBinding 및 NetNamedPipeBinding 엔드포인트를 각각 지원하도록 CalculatorService1 및 CalculatorService2 애플리케이션을 업데이트해야 합니다. 이 구성이 적용되면 소비자는 BasicHttpBinding/WSHttpBinding을 사용하여 RoutingService와 통신할 수 있으며 라우터는 메시지가 라우팅되는 서비스에 따라 NetTcpBinding 또는 NetNamedPipeBinding을 사용하여 대상 서비스와 통신합니다.

오류 전달 및 내결함성

또한 RoutingService는 런타임 통신 오류를 처리하고 기본 수준의 내결함성을 지원하는 기본 제공 메커니즘을 제공합니다. 필터 테이블을 정의할 때 초기 대상 엔드포인트와 통신하면 오류가 발생하는 경우 RoutingService에서 사용할 다른 대체 엔드포인트 목록을 정의할 수 있습니다. 따라서 기본적으로 "백업" 엔드포인트 목록을 가질 수 있습니다.

다음 예제에서는 필터 테이블 항목과 연결할 수 있는 backupLists> 요소 내에서 <백업 엔드포인트 목록을 정의하는 방법을 보여 줍니다.

<구성>

    ...

    <--ROUTING 섹션 -->

    <routing>

      ... <! -- 라우터에서 사용할 필터를 정의합니다. -->

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="subFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="mulFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="divFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

        </filterTable>

      </filterTables>

      <backupLists>

        <backupList name="backupEndpoints">

          <add endpointName="CalculatorService2"/>

        </backupList>

      </backupLists>

    </라우팅>

  </system.serviceModel>

</구성>

CalculatorService2는 TimeoutException, CommunicationException 또는 파생된 예외 형식이 생성될 때만 사용되는 "백업" 엔드포인트이므로 이 예제에서 CalculatorService1로 전달하도록 모든 필터 테이블 항목을 구성한 방법을 확인합니다. 예를 들어 솔루션을 다시 실행하고 CalculatorService1을 닫은 다음 클라이언트 프로그램을 실행하면 모든 메시지가 CalculatorService2에 표시됩니다. 이 모든 라우팅 구성을 호스트 애플리케이션 코드에서 동적으로 수행할 수 있다는 점에 다시 한 번 유의해야 합니다.

멀티캐스트 라우팅 동작

또한 RoutingService는 "멀티캐스트" 방식으로 들어오는 특정 메시지를 여러 대상으로 자동으로 라우팅하도록 지원합니다. 들어오는 메시지가 구성된 필터 테이블에 있는 여러 필터와 일치하면 RoutingService는 자동으로 메시지를 "일치하는" 필터와 연결된 각 대상 엔드포인트로 라우팅합니다.

다음 예제에서는 들어오는 모든 메시지와 일치하는 동일한 와일드카드 필터로 구성된 두 개의 라우팅 항목을 보여 줍니다.

<구성>

    ...

    <--ROUTING 섹션 -->

    <routing>

      <-- 라우터에서 사용할 필터를 정의합니다. -->

     <filters>

        <filter name="wildcardFilter" filterType="MatchAll" />

      </필터>

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="wildcardFilter" endpointName="CalculatorService1"/>

          <add filterName="wildcardFilter" endpointName="CalculatorService2"/>

          <add filterName="wildcardFilter" endpointName="CalculatorService3"/>

        </filterTable>

      </filterTables>

    </라우팅>

  </system.serviceModel>

</구성>

이 구성이 적용되면 들어오는 각 SOAP 메시지는 메시지에 있는 내용에 관계없이 모든 대상 엔드포인트로 자동으로 라우팅됩니다.

이 멀티캐스트 동작은 이전 섹션에서 설명한 프로토콜 브리징 및 오류 처리 기능으로 구성됩니다. 유일한 문제는 멀티캐스트가 단방향 또는 이중 통신에만 작동하지만 요청-응답 통신에는 작동하지 않습니다. 기본 시스템은 나가는 요청과 들어오는 응답 간에 일대일 비율을 유지해야 하기 때문에 입니다.

향상된 REST 지원

WCF 4에는 WCF를 사용하여 RESTful 서비스를 빌드할 때 유용한 몇 가지 새로운 기능이 제공됩니다.  이 기능 집합을 이제 WCF WebHttp Services라고 합니다. 여기에는 소비자에 대한 RESTful 서비스, 간소화된 HTTP 캐싱, 메시지 형식 선택, REST 친화적인 예외, ASP.NET 라우팅 통합, 일부 새로운 Visual Studio 프로젝트 템플릿 등을 설명하는 자동 도움말 페이지에 대한 지원이 포함됩니다. 이러한 모든 기능을 자세히 다룰 공간이 없지만, 나머지에 대한 자세한 정보 링크와 함께 아래의 몇 가지 즐겨찾기에 대한 빠른 소개를 제공합니다.

이러한 기능 중 상당수는 작년에 WCF REST 스타터 키트에 의해 처음 도입되었으며 현재 공식 프레임워크로 전환되고 있습니다. 향후 더 많은 WCF REST 스타터 키트 기능 후속 조치가 표시될 수 있습니다.

자동 도움말 페이지

WCF 4에서 WebServiceHost 클래스를 사용하는 경우 RESTful 서비스는 자동으로 자동 도움말 페이지 기능의 이점을 누릴 수 있습니다. 이는 WSDL 메타데이터 및 클라이언트 쪽 코드 생성이 부족하여 REST를 사용할 때 훨씬 더 필요하므로 소비자가 서비스를 시작하는 방법을 훨씬 쉽게 파악할 수 있으므로 일반적으로 이 새로운 기능을 사용하도록 설정하는 것이 좋습니다.

WebServiceHost 클래스를 사용하여 서비스를 호스트하는 경우 WebHttpBehavior를 사용하여 서비스를 자동으로 구성하고 기본 HTTP 주소에서 WebHttpBinding으로 구성된 기본 HTTP 엔드포인트를 추가합니다. WCF 4를 기준으로 WebHttpBehavior 클래스에는 호스트 내에서 새 도움말 페이지를 사용할 수 있는지 여부를 제어하는 HelpEnabled 속성이 함께 제공됩니다. 다음 구성 예제에서는 특정 REST 엔드포인트에 대해 자동 도움말 페이지 기능을 사용하도록 설정하는 방법을 보여 줍니다.

<구성>

  <system.serviceModel>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

    <behaviors>

      <endpointBehaviors>

        <behavior name="HelpBehavior">

          <webHttp helpEnabled="true" />

        </동작>

      </endpointBehaviors>

    </동작>

    <services>

      <service name="CounterResource">

        <endpoint behaviorConfiguration="HelpBehavior"

                  binding="webHttpBinding"

                  contract="CounterResource" />

      </service>

    </서비스>

  </system.serviceModel>

</구성>

URL 끝에 "도움말"이 추가된 서비스의 기본 주소로 이동하여 도움말 페이지를 볼 수 있습니다(그림 19 참조).

그림 19: RESTFul 서비스에 대한 자동 도움말 페이지

도움말 페이지는 [WebGet] 또는 [WebInvoke]로 주석이 추가된 각 작업에 대해 사람이 읽을 수 있는 설명을 제공하며, 각 작업에 대해 URI 템플릿, 지원되는 HTTP 작업 및 지원되는 메시지 형식을 설명합니다(기본적으로 소비자가 알아야 할 모든 것). 각 작업에 [Description] 특성을 적용하여 보다 인간 친화적인 설명을 제공할 수도 있습니다.

각 요청/응답에 대해 도움말 페이지에서는 소비자가 서비스와 통합하는 데 사용할 수 있는 XML 스키마 및 해당 샘플 XML instance 제공합니다. 소비자는 스키마를 사용하여 적절한 클라이언트 쪽 직렬화 가능 형식을 생성하거나 샘플 XML 문서를 검사하여 적절한 XML 처리 코드를 작성하는 방법을 수동으로 결정할 수 있습니다. 두 방법 모두 유용합니다.

그림 20: 특정 작업에 대한 자동 도움말 페이지

이 새로운 도움말 페이지 기능을 사용하면 RESTful 서비스를 자동으로 더 쉽게 검색할 수 있으므로 궁극적으로 다른 사용자가 더 쉽게 사용할 수 있습니다. 소비자는 서비스의 URI 디자인, 지원되는 HTTP 작업 및 요청/응답 형식을 검색할 수 있으며, 설명은 ASP.NET Web Services에서 작동하는 방식과 유사하게 항상 WCF 코드와 동기화 상태를 유지합니다.

HTTP 캐싱 지원

REST의 주요 잠재적 이점 중 하나는 HTTP 캐싱입니다. 그러나 이러한 이점을 실현하려면 요청 및 응답 메시지에서 다양한 HTTP 캐싱 헤더를 활용해야 합니다. WebOperationContext instance 통해 요청/응답 헤더에 수동으로 액세스하여 WCF 서비스 작업 내에서 이 작업을 수행할 수 있지만 제대로 수행하는 것은 간단하지 않습니다.

따라서 WCF 4에는 GET 작업에 선언적으로 적용할 수 있는 [AspNetCacheProfile] 특성을 통해 캐싱을 제어하는 더 간단한 모델이 제공됩니다. 이 특성을 사용하면 각 작업에 대해 ASP.NET 캐싱 프로필 이름을 지정할 수 있으며, 내부적으로는 모든 기본 HTTP 캐싱 세부 정보를 처리하는 캐싱 검사기(CachingParameterInspector)가 있습니다.

[AspNetCacheProfile] 구현은 표준 ASP.NET 출력 캐싱 메커니즘을 기반으로 합니다. 다음 예제에서는 [WebGet] 작업에 [AspNetCacheProfile] 특성을 적용하는 방법을 보여줍니다.

...

[AspNetCacheProfile("CacheFor60Seconds")]

[WebGet(UriTemplate=XmlItemTemplate)]

[OperationContract]

public Counter GetItemInXml()

{

    return HandleGet();

}

...

여기서는 web.config 파일 내에서 "CacheFor60Seconds"라는 ASP.NET 출력 캐싱 프로필을 정의해야 합니다. 다음 web.config 이 작업을 수행하는 방법을 보여줍니다.

<구성>

  <system.web>

    <캐싱>

      <outputCacheSettings>

        <outputCacheProfiles>

          <add name="CacheFor60Seconds" duration="60" varyByParam="format" />

        </outputCacheProfiles>

      </outputCacheSettings>

    </캐싱>

  </System.web>

  <system.serviceModel>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

  </system.serviceModel>

</구성>

ASP.NET 캐싱 프로필이 60초 동안 출력을 캐시하도록 설정되고 "형식" 쿼리 문자열 변수에 따라 캐시를 변경하도록 구성됩니다. 이는 문제의 서비스가 형식 변수(예: "?format=json")를 통해 제어하는 XML과 JSON을 모두 지원하기 때문에 중요합니다. 서비스는 XML 및 JSON 응답을 서로 독립적으로 캐시해야 합니다.

이 구성 파일은 출력 캐싱과 같은 다양한 ASP.NET 기능을 활용하려는 경우 필요한 ASP.NET 호환성 모드를 사용하도록 설정하는 방법도 보여 줍니다.

[AspNetCacheProfile] 특성을 사용하면 HTTP 캐싱 헤더를 직접 사용할 필요 없이 HTTP 캐싱을 훨씬 쉽게 활용할 수 있습니다. 기본 WCF 동작은 응답에 HTTP Cache-Control, Date, Expires 및 Vary HTTP 헤더를 삽입하는 것을 처리하며, 클라이언트는 향후 왕복에 대한 적절한 캐싱 의미 체계를 결정하는 데 활용할 수도 있습니다.

메시지 형식 선택

그림 19를 다시 살펴보면 CounterResource 서비스가 GET, POST 및 PUT 작업에 대한 XML 및 JSON 형식을 모두 지원한다는 것을 알 수 있습니다. 이는 WCF 3.5부터 [WebGet] 및 [WebInvoke] 특성에 있는 RequestFormat 및 ResponseFormat 속성을 통해 가능해졌습니다.

여기에 설명된 대로 각 버전에 대해 XML 버전과 JSON 버전에 대한 별도의 작업 계약을 정의하여 CounterResource 서비스에서 이 작업을 수행했습니다.

...

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItemInXml()

{

    return HandleGet();

}

[WebGet(UriTemplate = "?format=json", ResponseFormat=WebMessageFormat.Json)]

[OperationContract]

public Counter GetItemInJson()

{

    return HandleGet();

}

...

이는 모든 논리 작업에 대해 XML 및 JSON 형식을 모두 지원하려는 경우 두 개의 작업 계약이 필요하다는 것을 의미합니다. CounterResource 서비스의 경우 GET, POST 및 PUT 작업에 대해 XML과 JSON을 모두 지원하기 위해 6개의 작업 계약이 있어야 했습니다.

WCF 4를 사용하면 HTTP "수락" 헤더를 기반으로 자동 형식 선택을 지원하여 이 시나리오를 훨씬 쉽게 처리할 수 있습니다. 어떻게 작동하는지 설명하겠습니다.

먼저 각 논리 작업에 대해 단일 작업 계약만 필요합니다.

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItem()

{

    return HandleGet();

}

그런 다음, 다음과 같이 표준 webHttpEndpoint에서 자동 서식 선택을 선택합니다.

<구성>

  <system.serviceModel>

    <standardEndpoints>

      <webHttpEndpoint>

        <-- "" 표준 엔드포인트는 웹 엔드포인트를 자동으로 만드는 데 사용됩니다. -->

        <standardEndpoint name="" helpEnabled="true"

            automaticFormatSelectionEnabled="true"/>

      </webHttpEndpoint>

    </standardEndpoints>

  </system.serviceModel>

</구성>

이 기능을 사용하면 이제 서비스에서 XML 또는 JSON 메시지를 처리하고 반환할 수 있습니다. 먼저 요청 메시지에 있는 HTTP 수락 헤더를 검사하여 사용할 형식을 파악합니다. 이 형식이 작동하지 않으면 요청 메시지와 동일한 메시지 형식을 사용하며, XML 또는 JSON이라고 가정하면 특정 작업에 기본 형식을 사용합니다.

이제 HTTP Content-Type 및 Accept 헤더를 통해 사용할 형식을 결정하는 것은 클라이언트의 입니다. Content-Type 헤더는 요청 메시지의 형식을 지정하고 Accept 헤더는 클라이언트가 서비스에서 다시 "수락"하는 형식을 나타냅니다. 예를 들어 클라이언트가 서비스에서 JSON을 다시 받으려는 경우 요청에서 다음 HTTP Accept 헤더를 지정해야 합니다.

Accept: application/json

이는 모든 HTTP 클라이언트 프로그래밍 모델에서 쉽게 수행할 수 있으며 Fiddler와 같은 도구를 사용하여 쉽게 수행할 수도 있습니다. 그림 21에서는 Fiddler를 사용하여 새로운 개선 서비스에서 JSON을 다시 가져오는 방법을 보여 드립니다.

그림 21: HTTP Accept 헤더를 사용하여 JSON 검색

또한 WCF 4는 런타임에 메시지 형식을 명시적으로 쉽게 지정할 수 있는 새로운 API를 제공합니다. 다음 코드에서는 먼저 "형식" 쿼리 문자열 매개 변수를 찾고 그에 따라 응답 형식을 명시적으로 설정하는 코드를 작성하여 GetItem 작업을 확장하는 방법을 보여 드립니다. "format" 매개 변수를 찾지 못하면 이전과 같이 Accept 헤더만 사용합니다.

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItem()

{

    형식 쿼리 문자열 매개 변수가 지정된 경우

    응답 형식을 해당 형식으로 설정합니다. 그렇지 않은 경우

    쿼리 문자열 매개 변수가 있습니다. Accept 헤더가 사용됩니다.

    string formatQueryStringValue =

       WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters[

       "format"];

    if (!string. IsNullOrEmpty(formatQueryStringValue))

    {

        if (formatQueryStringValue.Equals("xml",

           System.StringComparison.OrdinalIgnoreCase))

        {

            WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;

        }

        else if (formatQueryStringValue.Equals("json",

           System.StringComparison.OrdinalIgnoreCase))

        {

            WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;

        }

        else

        {

            는 새 WebFaultException<string>(string)을 throw합니다. Format("지원되지 않는 형식 '{0}'",

               formatQueryStringValue), HttpStatusCode.BadRequest);

        }

    }

    return HandleGet();

}

결국 이러한 새로운 기능을 사용하면 WCF 3.5에서와 같이 메시지 형식 형식을 [WebGet] 및 [WebInvoke] 작업 계약에 하드 코딩할 필요가 없습니다.

RESTful 오류 처리

RESTful 서비스는 SOAP를 사용하지 않으므로 더 이상 표준 SOAP 오류 메커니즘을 사용할 수 없으므로 .NET 예외와 SOAP 오류 메시지 간에 자동으로 매핑할 수 있습니다. WCF 3.5에서 REST 서비스를 빌드할 때 클라이언트로 다시 전송된 HTTP 오류 메시지를 사용자 지정하려고 할 때마다 HTTP 응답 메시지를 수동으로 구성해야 했습니다.

WCF 4에서는 "웹 오류"(예: HTTP 오류)를 소비자에게 훨씬 쉽게 전송할 수 있는 WebFaultException<T> 라는 새 클래스를 찾을 수 있습니다. WCF의 FaultException<T>와 매우 유사하게 작동하지만 HTTP 상태 코드와 세부 정보 유형을 지정하여 자세한 정보를 제공할 수 있습니다.

다음 예제에서는 사용자가 지원되지 않는 형식 형식을 지정할 때 HTTP 400(잘못된 요청) 오류를 반환하는 방법을 보여 줍니다. 세부 정보 유형에 문자열을 사용하기만 하면 됩니다.

if (!string. IsNullOrEmpty(format))

{

    if(형식입니다. Equals("xml", System.StringComparison.OrdinalIgnoreCase))

    {

        WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;

    }

    else if (format. Equals("json", System.StringComparison.OrdinalIgnoreCase))

    {

        WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;

    }

    else

    {

        는 새 WebFaultException<string>(string)을 throw합니다. Format("지원되지 않는 형식 '{0}'",

           format), HttpStatusCode.BadRequest);

    }

}

이 새로운 기능을 사용하면 일반적으로 SOAP 기반 서비스에서와 같은 예외를 throw하여 표준 HTTP 오류 메시지를 훨씬 더 자연스럽게 반환할 수 있습니다.

ASP.NET 경로와 WCF 통합

WCF 4와 ASP.NET 4 모두에서 찾을 수 있는 URL 기반 라우팅 기능 간에는 많은 유사점이 있습니다. 둘 다 동일한 작업을 수행할 수 있습니다. 기본적으로 URL 템플릿을 클래스의 메서드에 매핑합니다. 그러나 두 모델 간에는 한 가지 중요한 차이점이 있습니다.

WCF 4 접근 방식은 개발 중에 클래스 정의에 적용된 [WebGet] 및 [WebInvoke] 특성을 통해 URL 템플릿 디자인을 단일 클래스에 연결합니다. 시간이 지남에 따라 서비스가 성장하고 발전함에 따라 더 작은 청크로 팩터링할 수 없는 대규모 모놀리식 디자인으로 이어질 수 있습니다. 반면에 ASP.NET 4 접근 방식은 대상 클래스 정의에서 라우팅 논리를 분리하므로 원하는 경우 다양한 클래스 정의에 서비스 경로를 매핑할 수 있습니다.

이제 WCF 4는 ASP.NET 라우팅 엔진을 WCF 4 서비스와 통합하여 WCF 서비스 위에 ASP.NET 라우팅 모델을 활용할 수 있는 기능을 제공합니다.

WCF 서비스 클래스에 ASP.NET 경로를 매핑할 수 있는 새 ServiceRoute 클래스를 활용하여 Global.asax RegisterRoutes 메서드에서 이 작업을 수행합니다.

private void RegisterRoutes()

{

   WebServiceHostFactory 팩터리 = 새 WebServiceHostFactory();

   RouteTable.Routes.Add(new ServiceRoute("Bookmarks", factory,

      typeof(BookmarkService)));

   RouteTable.Routes.Add(new ServiceRoute("Users", factory,

      typeof(UserService)));

}

RouteTable.Routes.Add를 두 번 호출하여 두 개의 서로 다른 WCF 서비스 클래스에 대한 새 경로를 추가합니다. 첫 번째 경로는 "/Bookmarks"를 BookmarkService 클래스에 매핑하고 두 번째 경로는 "/Users"를 UserService 클래스에 매핑합니다. WebServiceHostFactory를 사용하도록 두 경로가 어떻게 구성되어 있는지 확인합니다.

이제 WCF 서비스 클래스 정의에서 [WebGet] 및 [WebInvoke] 특성을 사용할 때 상대 경로를 사용하며 여기에 지정된 ASP.NET 경로를 기준으로 합니다.

REST 프로젝트 템플릿

Visual Studio 2010의 깔끔한 기능 중 하나는 도구 | 에서 액세스할 수 있는 확장 관리자입니다. 확장 관리자. 확장 관리자를 사용하면 Microsoft와 다른 타사에서 단추 클릭만으로 새 프로젝트 템플릿, 컨트롤 및 도구를 Visual Studio 2010 환경에 통합할 수 있습니다. Microsoft 제품 팀의 경우 RTM 이후에 제품을 배송하고 Microsoft에서 제공하는 공식 확장을 계속 만들 수 있기 때문에 유용합니다.

확장 관리자를 불러와 "템플릿" 노드를 확장하면 "WCF"라는 자식 노드를 찾을 수 있습니다. "WCF"를 클릭하면 그림 22에 표시된 대로 각 .NET 버전(3.5 대 4.0)과 언어당 하나씩(C# 및 VB.NET)의 4개의 새로운 WCF REST 서비스 템플릿이 표시됩니다.

그림 22: 확장 관리자의 새 WCF REST 프로젝트 템플릿

이러한 새 프로젝트 템플릿을 선택하고 로컬 Visual Studio 2010 설치에 다운로드하고 다른 프로젝트 형식과 같이 사용할 수 있습니다. Visual C# | 아래에서 새 REST 프로젝트 형식을 찾을 수 있습니다. 웹 | WCF REST 서비스 애플리케이션(C# 버전을 설치했다고 가정).

이 프로젝트를 사용하여 새 프로젝트를 만들면 생성되는 WCF REST 서비스 애플리케이션에서 이 섹션 전체에서 강조 표시한 새 WCF 4 기능 대부분을 사용하는 것을 알 수 있습니다.

추가 정보

여기서 설명한 것 외에도 WCF 4에는 사용자 지정 메시지 형식 처리(XML 또는 JSON 아님), 새 T4 기능을 사용하여 템플릿 기반 "보기" 반환, 조건부 GET 및 ETag 지원 구현, 낙관적 동시성 구현 및 아웃바운드 링크 생성과 같은 작업을 간소화하는 몇 가지 고급 REST 기능과 새로운 WCF API 확장이 함께 제공됩니다.

여기에 포함할 공간이 없는 기능을 포함하여 이러한 새로운 WCF 4 기능에 대한 자세한 내용은 .NET 엔드포인트 블로그로 이동하여 .NET 4에서 WCF WebHttp Services 소개에 대한 항목을 찾습니다. 팀은 다양한 샘플 코드 및 단계별 지침과 함께 각각의 새로운 기능 1개 블로그 항목을 한 번에 하나씩 안내하는 철저한 12부 블로그 시리즈를 제공했습니다.

워크플로 서비스

.NET 4에서 가장 주목을 받은 기능 영역 중 하나는 "워크플로 서비스"였습니다. Microsoft는 다양한 애플리케이션을 빌드하기 위한 풍부하고 선언적인 프로그래밍 모델을 제공하기 위해 WCF와 WF 간의 통합을 개선하는 데 많은 투자를 해왔습니다.

Workflow Services 이해

WF는 논리를 작성하는 사용자에 대한 추상화 수준을 높이는 선언적 프로그래밍 모델을 제공합니다. WF가 궁극적으로 제공하는 것은 고유한 비즈니스 도메인 활동 라이브러리를 정의하여 고유한 언어를 작성하기 위한 프레임워크입니다. 그런 다음 이러한 활동을 프로그램에 구성하기 위한 비주얼 디자이너와 해당 프로그램의 실행을 관리하는 방법을 알고 있는 런타임을 제공합니다.

WF는 다른 시스템에서 메시지를 받는 것과 같이 다양한 유형의 외부 이벤트가 발생할 때까지 기다려야 하는 장기 실행 애플리케이션을 구현하기 위한 특히 좋은 모델을 제공합니다. 지속성 모델을 사용하면 실제로 실행 중일 때만 프로그램을 메모리에 유지하여 시스템 리소스를 효율적으로 사용할 수 있습니다. 프로그램이 외부 이벤트가 발생하기를 기다리는 경우 데이터베이스에 유지하여 사용하던 시스템 리소스를 해제할 수 있습니다.

그림 23: 워크플로 서비스

WF를 다른 개발 프레임워크와 다르게 만드는 것은 순차적 흐름 제어 프로그래밍 논리를 사용하여 프로그래밍할 수 있는 동시에 이러한 기능을 제공한다는 것입니다. 이는 일반적으로 개발자가 코드를 읽고 작성하는 것이 훨씬 쉽습니다.

본질적으로 장기 실행되거나 방금 설명한 다른 이점을 활용할 수 있는 WCF 서비스를 빌드하는 경우 WF 워크플로를 사용하여 WCF 서비스를 구현할 수 있습니다. 또한 WF를 사용하여 다른 외부 서비스를 사용하는 논리를 조정할 수 있습니다.

그림 23에서는 이러한 개념을 보여 줍니다.

.NET 3.5 이후 이러한 기능이 가능했지만 .NET 4는 개발자 환경을 개선하고 .NET 3.5에서 누락된 필요한 기능 중 일부를 제공하는 데 상당한 진전을 이루었습니다.

WCF와 WF의 세계를 결합하면 두 세계의 최고를 얻을 수 있습니다. 선언적 프로그래밍 모델, WF 디자이너 덕분에 개발자 친화적인 환경, 장기 실행 서비스를 관리하기 위한 강력한 런타임 및 WCF에서 제공하는 풍부한 통신 유연성을 얻을 수 있습니다.

첫 번째 워크플로 서비스 빌드

새로운 워크플로 서비스 개발자 환경에 대한 느낌을 주기 위해 .NET 4 및 새 Visual Studio 2010 디자이너를 사용하여 새로 빌드하는 전체 예제를 살펴보겠습니다.

Visual Studio 2010을 열고 파일 | 을 선택하는 경우 새 프로젝트 WCF 템플릿 아래에서 새 워크플로 프로젝트를 찾을 수 있습니다. 이를 "WCF 워크플로 서비스 애플리케이션"이라고 합니다. 이 프로젝트 템플릿을 선택하고 이름을 "HelloWorldWorkflowService"로 지정하고 새 프로젝트를 만듭니다.

그림 24: Visual Studio 2010 Workflow Services 프로젝트 템플릿

새 프로젝트가 만들어지면 선언적 워크플로 서비스 정의를 포함하는 Service1.xamlx 파일과 서비스 구성을 포함하는 Web.config 파일이라는 두 개의 파일만 포함됩니다.

.NET 4의 새 워크플로 서비스 모델에서 가장 매력적인 것 중 하나는 전체 서비스 정의를 XAML에서 정의할 수 있다는 것입니다.   새 프로젝트에서 Service1.xamlx 파일에는 서비스 정의가 포함되어 있으며 구현은 단순히 XAML 기반 워크플로입니다. Web.config 파일에는 WCF 서비스 구성이 포함되어 있습니다. 여기서 워크플로 서비스 엔드포인트 및 동작을 정의합니다.

그림 25는 Service1.xamlx 파일에 대한 Visual Studio 2010 디자이너의 모양을 보여 줍니다. 이는 단지 표준 워크플로 디자이너일 뿐이며, 이 특정한 경우에 우리가 디자인하는 워크플로는 WCF 서비스 구현으로 사용됩니다. 이 워크플로 정의를 WCF와 통합하는 핵심은 새 WorkflowServiceHost 및 WCF "메시징" 활동 집합입니다(그림 25의 도구 상자 참조).

그림 25: Visual Studio 2010에서 워크플로 서비스 디자인

이 프로젝트 템플릿과 함께 제공되는 스켈레톤 워크플로 서비스에는 Receive 작업과 보내기 작업이 포함됩니다. Receive 작업에 OperationName 속성이 포함되어 있으며 현재 "GetData"로 설정되어 있습니다. 또한 들어오는 메시지를 시퀀스 작업 내에 정의된 지역 변수에 바인딩하기 위한 Content 속성이 있습니다. 이 경우 변수를 "data"라고 하며 Int32 형식입니다(그림 25의 워크플로 디자인 서비스 아래 변수 창 참조).

수신 활동도 서비스를 활성화하도록 구성됩니다. 즉, 들어오는 메시지에서 워크플로의 새 instance 만들어질 수 있습니다. CanCreateInstance 속성은 그림 25의 오른쪽에 있는 속성 창 내에서 확인됩니다.

이 워크플로 서비스를 조금 사용자 지정해 보겠습니다. 먼저 서비스 파일 이름을 Service1.xamlx에서 HelloWorld.xamlx로 변경합니다. 다음으로 서비스 이름을 적절한 창에서 "HelloWorldService"로 변경합니다. 다음으로 Receive 활동의 OperationName 속성을 "SayHello"로 변경합니다. 마지막으로 시퀀스 내에서 String 형식의 "personName"이라는 새 변수를 정의합니다.

그런 다음 그림 26과 같이 Receive 활동의 Content 속성을 "personName" 변수에 바인딩합니다. 다음으로 보내기 활동의 Content 속성을 "hello {0}!" 형식의 문자열에 바인딩합니다. personName 변수를 자리 표시자에 삽입합니다. 그런 다음 결과 Service1.xamlx 파일을 저장합니다.

그림 26: 수신 작업의 Content 속성 정의

이 시점에서 HelloWorld.xamlx 파일을 열고 해당 내용을 검사합니다. 솔루션 탐색기 파일을 마우스 오른쪽 단추로 클릭하고 "함께 열기..."를 선택하여 이 작업을 수행할 수 있습니다. 다음에 "XML 편집기"가 잇습니다. 이렇게 하면 서비스에 대한 원시 XAML 정의를 볼 수 있습니다. XAML 정의는 전체 서비스 구현을 나타냅니다. C# 코드는 전혀 없습니다.

이 샘플에서는 기본 HTTP 엔드포인트를 사용하고 WCF 구성이 필요하지 않도록 서비스 메타데이터를 자동으로 사용하도록 설정하는 표준 서비스 동작이 있다고 가정합니다.

이제 XAML 기반 워크플로 서비스를 테스트할 준비가 되었습니다. Visual Studio 2010에서 F5 키를 누르는 것만큼 쉽습니다. F5 키를 누르면 워크플로 서비스가 ASP.NET 개발 서버에 로드되고 WCF 테스트 클라이언트가 표시됩니다. WCF 테스트 클라이언트는 워크플로 서비스에 자동으로 연결하고, WSDL 메타데이터를 다운로드하고, 워크플로 서비스 논리를 테스트할 수 있도록 합니다(그림 27 참조).

그림 27: 워크플로 서비스 테스트

이는 워크플로 서비스 인프라가 워크플로 정의 내에서 사용되는 송신 및 수신 활동과 주고받는 메시지 유형을 검사하여 서비스에 대한 WSDL 정의를 동적으로 생성할 수 있음을 보여 줍니다.

이렇게 하면 .NET 4에서 첫 번째 선언적 워크플로 서비스를 빌드하는 간단한 연습이 완료됩니다. 서비스 구현이 XAML에서 완전히 정의되었으며 보내기/받기 활동을 사용하여 워크플로 내의 메시징 상호 작용을 모델링하는 것을 확인했습니다. 또한 .NET 4에는 .xamlx 파일에 대한 호스팅 지원이 제공되어 추가 .svc 파일이 필요하지 않습니다. 다음 섹션에서는 이러한 각 영역을 자세히 살펴보겠습니다.

워크플로 서비스 호스팅

.NET 4에는 워크플로 서비스를 위한 새롭고 향상된 호스팅 인프라가 함께 제공됩니다. WorkflowServiceHost를 사용하여 IIS/WAS 또는 자체 애플리케이션에서 워크플로 서비스를 호스트할 수 있습니다. .NET 4 호스팅 인프라는 장기 실행 워크플로 인스턴스를 관리하고 여러 서비스 인스턴스가 동시에 실행되는 경우 메시지의 상관 관계를 지정하는 데 필요한 부분을 제공합니다. .NET 4는 워크플로 인스턴스를 원격으로 관리하기 위한 표준 워크플로 제어 엔드포인트도 제공합니다.

IIS/ASP.NET에서 호스팅

이전 섹션에서 안내한 간단한 HelloWorldWorkflowService 예제에서는 IIS/ASP.NET에서 워크플로 서비스를 호스트하는 방법을 보여 줍니다. ASP.NET 개발 서버를 사용하여 서비스를 테스트했지만 ASP.NET 4 애플리케이션 풀을 사용하여 IIS 내에서 동일하게 작동했을 것입니다. .NET 4는 백그라운드에서 WorkflowServiceHost 만들기 및 개별 워크플로 인스턴스의 활성화를 처리하는 .xamlx 요청에 필요한 처리기를 설치합니다.

첫 번째 예제에서 "제로 구성" 접근 방식을 사용했지만 다른 WCF 서비스와 마찬가지로 Web.config 내에서 워크플로 서비스를 구성할 수 있습니다. 여기서 사용하려는 WCF 엔드포인트 및 동작을 구성할 수 있습니다. 워크플로 서비스에서 원하는 만큼 엔드포인트를 노출할 수 있지만 instance 특정 통신을 관리하는 새로운 "컨텍스트" 바인딩(예: BasicHttpContextBinding, WSHttpContextBinding 또는 NetTcpContextBinding) 중 하나를 사용하는 것이 좋습니다.

다음 예제에서는 두 개의 HTTP 엔드포인트를 사용하여 워크플로 서비스를 구성하는 방법을 보여 줍니다.

<구성>

  <system.serviceModel>

    <services>

      <service name="HelloWorldWorkflowService">

        <endpoint binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding"

                  contract="IHelloWorld"/>

      </service>

      ...

WCF 동작을 사용하여 워크플로 서비스를 구성할 수도 있습니다. 다음 예제에서는 몇 가지 표준 WCF 동작으로 이 워크플로 서비스를 구성하는 방법을 보여 줍니다.

<구성>

  <system.serviceModel>

    <services>

      <service name="HelloWorldWorkflowService"

        behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

        <endpoint binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding"

                  contract="IHelloWorld"/>

      </service>

     </서비스>

    <behaviors>

      <serviceBehaviors>

        <behavior name="HelloWorldWorkflowService.Service1Behavior">

          <serviceDebug includeExceptionDetailInFaults="False" />

          <serviceMetadata httpGetEnabled="True"/>

        </동작>

      </serviceBehaviors>

      ...

이러한 표준 WCF 동작 외에도 .NET 4에는 워크플로 서비스와 함께 워크플로 지속성, 워크플로 추적 및 기타 워크플로 런타임 동작을 제어하기 위한 몇 가지 새로운 WF 관련 동작이 함께 제공됩니다. 자세한 내용은 .NET 4 SDK 샘플을 참조하세요.

WorkflowServiceHost를 사용하여 자체 호스팅

.NET 3.5는 워크플로 서비스를 호스팅하기 위한 WorkflowServiceHost 클래스와 함께 제공되었지만 .NET 4의 WF 런타임 및 프로그래밍 모델에 대한 모든 변경 내용을 고려하여 다시 디자인해야 했습니다. 따라서 .NET 4에는 System.ServiceModel.Activities 어셈블리에 있는 새 WorkflowServiceHost 클래스가 함께 제공됩니다.

WorkflowServiceHost 클래스를 사용하면 콘솔 애플리케이션, WPF 애플리케이션 또는 Windows 서비스 등 사용자 고유의 애플리케이션에서 워크플로 서비스를 쉽게 호스트할 수 있습니다. 다음 코드 조각에서는 사용자 고유의 애플리케이션 코드 내에서 WorkflowServiceHost를 사용하는 방법을 보여 줍니다.

...

WorkflowServiceHost 호스트 = new WorkflowServiceHost("HelloWorld.xamlx",

    new Uri("https://localhost:8080/helloworld"));

호스트. AddDefaultEndpoints();

호스트. Description.Behaviors.Add(

    new ServiceMetadataBehavior { HttpGetEnabled = true });

호스트. Open();

Console.WriteLine("Host is open");

Console.ReadLine();

...

보듯이 IIS/ASP.NET 또는 자체 애플리케이션에서 워크플로 서비스를 호스트하도록 선택하든 관계없이 WCF 서비스만큼 쉽게 호스트할 수 있습니다.

WorkflowControlEndpoint

워크플로 서비스 호스팅은 메시지를 활성화하는 것이 노출된 엔드포인트 중 하나를 통해 도착할 때 WF 런타임을 초기화하고 새 워크플로 인스턴스를 활성화하는 작업을 처리합니다. 이 기본 호스팅 기능 외에도 이러한 실행 중인 워크플로 인스턴스의 구성 및 실행을 원격으로 관리할 수 있어야 합니다. .NET 4를 사용하면 워크플로 서비스에 노출할 수 있는 표준 WorkflowControlEndpoint를 제공하여 이 작업을 쉽게 수행할 수 있습니다.

다음 예제에서는 사용자 지정 호스팅 시나리오에서 표준 워크플로 제어 엔드포인트를 서비스에 추가하는 방법을 보여 줍니다.

...

WorkflowServiceHost 호스트 = new WorkflowServiceHost("HelloWorld.xamlx",

    new Uri("https://localhost:8080/helloworld"));

호스트. AddDefaultEndpoints();

WorkflowControlEndpoint wce = new WorkflowControlEndpoint(

    new NetNamedPipeBinding(),

    new EndpointAddress("net.pipe://localhost/helloworld/WCE"));

호스트. AddServiceEndpoint(wce);

호스트. Open();

...

IIS/ASP.NET에서 호스팅하는 경우 다음과 같이 표준 WorkflowControlEndpoint를 추가할 수 있습니다.

<구성>

  <system.serviceModel>

    <services>

      <service name="HelloWorldWorkflowService"

          behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

        <endpoint address="" binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="wce" binding="wsHttpBinding" kind="workflowControlEndpoint"/>

      </service>

      ...

WorkflowControlEndpoint를 사용하면 워크플로 서비스를 다양한 호스팅 환경 내에서 관리할 수 있습니다. 이러한 환경 중 하나는 Windows Server AppFabric에서 가능하며, 향후 버전의 Windows Server에서 사용할 수 있습니다.

활동 보내기/받기

.NET 3.5에는 WCF를 사용하여 메시지를 보내고 받기 위한 두 가지 메시징 활동인 송신 및 수신이 제공되었지만 기능 측면에서는 상당히 제한적이었습니다. .NET 4는 몇 가지 추가 기능(예: 상관 관계)을 사용하여 보내기 및 수신 활동을 향상시키고, 요청-회신 작업 모델링을 간소화하는 SendReply 및 ReceiveReply라는 몇 가지 메시징 활동을 추가합니다.

워크플로 서비스 내에서 보내기/받기 작업을 사용하는 경우 기본적으로 WSDL 정의를 통해 클라이언트에 노출될 서비스 계약을 모델링하는 데 사용합니다. 수신 작업을 사용하는 경우 작업 이름을 지정하고 들어오는 메시지를 .NET 형식에 매핑합니다. 지금까지 간단한 문자열을 사용해 왔지만 복잡한 사용자 정의 데이터 계약도 사용할 수 있습니다. 다음 데이터 계약 형식을 사용하도록 HelloWorldWorkflowService를 업데이트해 보겠습니다.

[DataContract(Namespace="")]

public class Person

{

    [DataMember]

    public 문자열 ID;

    [DataMember]

    public 문자열 FirstName;

    [DataMember]

    public 문자열 LastName;

}

이 클래스 정의를 웹 프로젝트에 추가하고 HelloWorld.xamlx로 돌아가면 Person 형식(위에 정의된 데이터 계약)의 "personMsg"라는 새 변수를 정의할 수 있습니다. 그런 다음 ReceiveRequest 및 SendResponse 작업을 모두 "Content" 속성을 통해 personMsg 변수에 매핑할 수 있습니다. 이렇게 하려면 각 작업을 선택하고 "콘텐츠" 단추를 눌러 "콘텐츠 정의" 창을 표시하기만 하면 됩니다. 그런 다음 "메시지 데이터" 텍스트 상자에 "personMsg"를 입력하고 "메시지 유형" 텍스트 상자에 "Person"을 입력합니다. 두 작업 모두에 대해 이 작업을 수행해야 합니다.

또한 보내기/받기 작업을 사용하면 런타임에 사용할 작업 이름, 서비스 계약 이름, 작업, 알려진 형식 컬렉션, 보호 수준 및 직렬 변환기(예: DataContractSerializer 및 XmlSerializer)와 같은 WCF 서비스의 다른 측면을 구성할 수 있습니다. 보내기 작업에서 대상 엔드포인트 세부 정보도 지정합니다. 이러한 모든 설정은 보내기/받기 작업이 선택된 경우 속성 창 통해 구성할 수 있습니다.

이러한 변경 내용을 적용하면 HelloWorld.xamlx를 다시 테스트하여 SayHello 작업이 Person 형식의 메시지를 받고 반환하도록 정의되어 있는지 확인할 수 있습니다.

Request-Reply 작업 정의

요청-회신 작업을 보다 쉽게 모델링할 수 있도록 .NET 4에는 이러한 유형의 상호 작용을 모델링하기 위한 몇 가지 새로운 활동이 도입되었습니다. 하나는 수신 활동과 결합하여 서비스 내에서 요청-회신 작업을 구현할 수 있는 SendReply 활동입니다. 워크플로 내에서 외부 서비스를 호출할 때 Send 작업과 결합할 수 있는 ReceiveReply 작업도 있습니다.

.NET 4에는 Visual Studio 2010 도구 상자 내에서 볼 수 있는 ReceiveAndSendReply 및 SendAndReceiveReply라는 몇 가지 상위 수준 작업도 함께 제공됩니다. 이러한 활동은 SendReply/ReceiveReply를 사용하여 각각 Receive/Send를 작성하여 쉽게 사용할 수 있도록 합니다. 워크플로 디자인 화면으로 끌어다 놓으면 보내기 또는 받기 작업과 적절한 "회신" 활동이 포함된 시퀀스로 확장되는 것을 볼 수 있습니다.

에서

또한 Visual Studio 2010은 외부 서비스를 사용할 때 작업을 더 쉽게 수행할 수 있도록 클라이언트 프록시 클래스 정의를 생성하는 대신 클라이언트 쪽 활동 집합을 생성하는 것을 제외하고는 예상대로 작동하는 "서비스 참조 추가" 기능을 제공합니다. "서비스 참조 추가"를 선택하고 WSDL 정의의 주소를 지정하면 Visual Studio에서 WSDL을 다운로드하고 WSDL 정의에 있는 각 작업에 대한 사용자 지정 작업을 생성합니다.

간단한 예제를 살펴보겠습니다. 워크플로 서비스에서 사용하려는 추가, 빼기, 곱하기 및 나누기 작업이 있는 CalculatorService가 있다고 가정합니다. 그림 28과 같이 "서비스 참조 추가"를 선택하고 CalculatorService WSDL 정의의 위치를 지정할 수 있습니다.

그림 28: 서비스 참조 추가

확인을 눌러 서비스 참조를 추가하면 Visual Studio에서 WSDL 정의를 다운로드하고 도구 상자에 표시되는 네 가지 사용자 지정 작업을 생성합니다. 이제 워크플로 내에서 외부 서비스를 호출하는 데 쉽게 사용할 수 있는 추가, 빼기, 곱하기 및 나누기 작업이 있습니다.

Correlation

장기 실행 워크플로 서비스로 구성된 시스템을 빌드할 때 동일한 이벤트가 발생할 때까지 동시에 실행되는 단일 워크플로 서비스의 여러 인스턴스가 있는 것이 일반적입니다(예: 계속하기 전에 특정 메시지가 도착할 때까지 대기). 이 시나리오의 과제는 들어오는 메시지를 올바른 워크플로 instance 상호 연결하는 방법이 필요하다는 것입니다. 일반적으로 올바른 워크플로 instance 확인하는 방법은 들어오는 메시지의 내용을 검사하는 것입니다.

.NET 4에는 방금 설명한 보내기 및 받기 활동과 함께 사용할 수 있는 정교한 콘텐츠 기반 메시지 상관 관계 기능이 함께 제공됩니다. 이 기능의 구현은 .NET 4의 또 다른 새로운 개념인 "상관 관계 핸들"을 중심으로 진행됩니다.

상관 관계 사용을 시작하려면 먼저 CorrelationHandle 형식의 워크플로 변수를 정의해야 합니다. 이 변수는 (잠재적으로) 두 개의 서로 다른 메시지에서 데이터 조각을 연결하기 위한 랑데부 지점이라고 생각할 수 있습니다(서로 다른 두 메시징 활동에 의해 처리됨). Send 및 Receive 활동은 CorrelationHandle 변수를 지정하기 위한 CorrelatesWith 속성을 제공합니다.

여러 송신/받기 활동에서 보내는 메시지의 상관 관계를 지정하려면 상관 관계에 참여하려는 모든 활동에서 동일한 상관 관계 핸들을 지정해야 합니다. 그런 다음 각 작업에서 특정 작업에서 처리되는 메시지에 매핑되는 상관 관계 키를 구성합니다(예: 한 메시지의 SSN 요소는 다른 메시지의 CustomerId 요소와 상관 관계가 있을 수 있음). 메시지에 대해 평가되는 XPath 식을 사용하여 상관 관계 키를 정의합니다.

HelloWorldWorkflowService를 확장하여 작동 방식의 예를 살펴보겠습니다. 현재 작업 중인 샘플은 Person 메시지를 수신하고 클라이언트에 다시 반환합니다. 워크플로 아래쪽의 SendResponse 작업 바로 아래에 다른 ReceiveAndSendReply 작업을 추가해 보겠습니다. 이렇게 하면 다른 Receive와 다른 SendReply가 포함된 시퀀스가 추가됩니다. 수신 활동에 "Finish"라는 작업 이름을 지정하고 최종 인사말 응답을 생성하는 데 사용할 Finish 메시지에서 클라이언트가 인사말을 제공하도록 요구합니다.

즉, 클라이언트는 먼저 SayHello를 호출하여 전체 이름을 제공하여 새 워크플로 서비스 instance 시작합니다. 그런 다음, 워크플로 instance 클라이언트가 인사말 제공 완료를 호출할 때까지 기다립니다(워크플로가 지속될 수 있는 시간 동안 몇 분, 시간 또는 며칠이 걸릴 수 있음). 클라이언트가 인사말을 제공하는 Finish를 호출하면 워크플로는 인사말과 원래 이름을 사용하여 인사말을 빌드하고 반환합니다. 이 시나리오에서는 마침 작업이 호출될 때까지 여러 실행 중인 워크플로 인스턴스를 쉽게 대기할 수 있으므로 Finish 메시지와 이전 SayHello 메시지의 상관 관계를 확실히 지정해야 합니다. 이 경우 "Finish"에 대한 Receive 작업을 "SayHello" 작업(nameHandle)에 지정한 것과 동일한 상관 관계 핸들과 연결해야 합니다.

이제 이 두 활동 간에 상관 관계를 지정할 메시지 콘텐츠를 살펴보겠습니다. 이 예제에서는 다음 두 데이터 계약 형식을 사용하여 메시지를 모델링합니다.

[DataContract(Namespace="")]

public class Person

{

    [DataMember]

    public string FirstName { get; set; }

    [DataMember]

    public string LastName { get; set; }

}

[DataContract(Namespace = "")]

public 클래스 인사말

{

    [DataMember]

    public string Salutation { get; set; }

    [DataMember]

    public string NameKey { get; set; }

}

"SayHello"에 대한 수신 활동은 Person 메시지를 사용하도록 구성되고 "마침"에 대한 수신 활동은 인사말 메시지를 사용하도록 구성됩니다. LastName 값은 항상 고유하므로 상관 관계에 대한 고유 값으로 사용할 수 있다고 가정합니다. 따라서 클라이언트가 "Finish" 메시지를 보낼 때 이전 "SayHello" 메시지에 사용된 것과 동일한 LastName 값을 제공해야 합니다.

이제 이를 설정하도록 상관 관계 핸들을 구성하는 방법을 살펴보겠습니다. "handle"이라는 시퀀스 내에서 CorrelationHandle 변수를 이미 정의했습니다. 가장 먼저 해야 할 일은 "SayHello" 수신 작업 내에서 상관 관계 핸들을 "초기화"하는 것입니다. 따라서 "SayHello" 수신 활동을 선택하고 "CorrelationInitializers" 텍스트 상자 옆에 있는 단추를 누릅니다.

여기서 드롭다운 상자에서 "쿼리 상관 관계 이니셜라이저"를 선택한 다음 쿼리 필드에 대해 "LastName" 속성을 선택할 수 있어야 합니다(그림 29에 설명된 대로 "sm:body()/xg0:Person/xg0:LastName"의 XPath 식이 생성됩니다.

그런 다음 동일한 핸들에서 상관 관계가 있는 "마침" 수신 작업을 지정해야 합니다. "마침" 수신 활동을 선택하고 "CorrelatesOn" 단추를 누릅니다. 그런 다음, "CorrelatesWith" 핸들에 "handle"을 지정한 다음 쿼리 필드에 대해 "NameKey"를 선택합니다(그림 30 참조).

그림 29: "SayHello"에 대한 상관 관계 키 정의

그림 30: "마침"에 대한 상관 관계 키 정의

이는 궁극적으로 Person 메시지의 LastName 요소가 두 개의 개별 요청에서 Greeting 메시지의 NameKey 요소와 일치해야 했음을 의미합니다. 이를 통해 워크플로 인프라는 자동으로 메시지를 상호 연결하고 들어오는 "마침" 메시지를 올바른 워크플로 instance 라우팅할 수 있습니다("LastName/NameKey"기반).

최종 SendReply 작업은 원래 "personMsg" 및 새 "greetingMsg"의 정보를 포함하여 다음 형식의 문자열을 호출자에게 반환합니다.

String.Format("{0}{1}{2}!",

   greetingMsg.Salutation, personMsg.FirstName, personMsg.LastName)

WCF 테스트 클라이언트를 사용하여 여러 FirstName 및 LastName 값으로 SayHello를 여러 번 호출하여 여러 워크플로 인스턴스를 시작하여 상관 관계 기능을 테스트하겠습니다. 이 작업을 수행한 후에는 워크플로 서비스의 여러 실행 중인 인스턴스가 있어야 합니다. 이제 SayHello 메시지 중 하나에 사용되는 동일한 LastName 값 중 하나를 지정하는 Finish 작업을 호출할 수 있으며 클라이언트에 반환된 마지막 인사말에 사용된 해당 FirstName 값이 표시됩니다(그림 31 참조).

이는 .NET 4와 함께 제공되는 강력한 워크플로 서비스 기능인 작동 중인 콘텐츠 기반 상관 관계를 보여 줍니다. .NET 3.5에서 수행한 것처럼 채널 및 프로토콜 수준 데이터를 기반으로 상관 관계를 수행할 수도 있습니다(예: 채널 또는 워크플로 instance ID 사용). 콘텐츠 기반 상관 관계는 동일한 작업을 수행하는 보다 유연하고 정교한 접근 방식입니다.

그림 31: 콘텐츠 기반 상관 관계 예제 테스트

그러면 워크플로 서비스 적용 범위가 종료됩니다. 이 문서에서는 워크플로 서비스의 표면만 긁을 수 있었지만 .NET 4 SDK 샘플 및 온라인에서 찾은 증가하는 MSDN 설명서에서 추가 정보를 찾을 수 있습니다. 보시는 것처럼 WCF와 WF 4의 조합은 두 프레임워크가 제공하는 최상의 기능을 누릴 수 있는 선언적, 장기 실행 및 비동기 서비스를 빌드하기 위한 완전히 새로운 개발 모델의 문을 엽니다.

기타 고급 기능

이 문서에서 설명한 다른 모든 것 외에도 WCF 4에는 유용할 수 있는 몇 가지 고급 기능이 제공됩니다. 이러한 고급 기능에는 DataContractResolver를 통한 향상된 형식 확인 지원, ReceiveContext를 사용하여 경쟁 큐 소비자를 처리하는 기능, 새로운 바이트 스트림 인코더 및 고성능 ETW 기반 추적이 포함됩니다.

DataContractResolver를 사용하는 형식 확인

WCF 3.x에는 "알려진 형식"이라고 하는 형식 확인 기능이 있습니다. 역직렬화하는 동안 직렬 변환기가 선언된 형식과 형식이 다른 instance 발견하면 선언된 "알려진 형식" 목록을 검사하여 사용할 형식을 파악합니다. 서비스의 작성자는 [KnownType] 또는 [ServiceKnownType] 특성을 사용하여 형식/메서드에 주석을 달고 가능한 대체 목록을 정의할 수 있습니다. 이 기능은 상속 및 다형성을 지원하는 데 일반적으로 사용됩니다.

아쉽게도 WCF 3.x는 런타임에 이러한 유형의 동적 형식 확인을 수행할 때 DataContractSerializer에서 사용하는 형식 매핑 알고리즘을 재정의하는 쉬운 방법을 제공하지 않습니다. 이 문제를 해결하기 위해 WCF 4는 사용자 고유의 사용자 지정 형식 확인 알고리즘을 구현하기 위해 파생할 수 있는 추상 DataContractResolver 클래스를 제공합니다.  다음은 시작하는 방법을 보여줍니다.

class MyDataContractResolver: DataContractResolver

{

    어셈블리 어셈블리;

    public MyDataContractResolver(Assembly assembly)

    {

        this.assembly = assembly;

    }

    역직렬화 시 사용

    사용자가 xsi:type 이름을 모든 형식에 매핑할 수 있습니다.

    public override Type ResolveName(string typeName, string typeNamespace,

        type declaredType, DataContractResolver knownTypeResolver)

    {

        ... // 매핑 구현

    }

    serialization 시 사용

    모든 형식을 새 xsi:type 표현에 매핑합니다.

    public override bool TryResolveType(Type type, Type declaredType,

        DataContractResolver knownTypeResolver, out XmlDictionaryString typeName,

        out XmlDictionaryString typeNamespace)

    {

        ... // 매핑 구현

    }

}

사용자 지정 DataContractResolver가 구현되면 다음과 같이 DataContractSerializer에 제공할 수 있습니다.

DataContractSerializer dcs = new DataContractSerializer(

    typeof(Object), null, int. MaxValue, false, true, null,

    new MyDataContractResolver(assembly));

이제 이 DataContractSerializer instance 사용하여 개체를 직렬화/역직렬화하면 사용자 지정 DataContractResolver가 호출되어 사용자 지정 형식 확인을 수행합니다.

사용자 지정 DataContractResolver를 백그라운드에서 WCF 런타임에 삽입하려면 DataContractSerializerOperationBehavior에 연결하고 기본 확인자를 재정의하는 WCF 계약 동작을 작성해야 합니다. .NET 4 SDK에는 계약 동작 및 [KnownAssembly]라는 사용자 지정 특성을 통해 이 작업을 수행하는 방법을 보여 주는 전체 예제가 제공됩니다.

사용자 지정 형식 확인은 DataContractSerializer 기본값을 재정의하거나, 직렬화에 사용되는 형식을 정확하게 제어하거나, 알려진 형식을 동적으로 관리하려는 경우에 유용할 수 있습니다.

ReceiveContext를 사용하여 큐에 대기 중인 메시지 처리

WCF 3.x를 사용하면 트랜잭션 큐를 사용하고 MSMQ 트랜잭션에 WCF 서비스 작업을 참여시켜 NetMsmqBinding을 사용할 때 메시지를 정확히 한 번 배달할 수 있습니다. 메시지를 처리하는 동안 예외가 throw되면 WCF는 메시지를 큐에 반환하여 메시지가 손실되지 않도록 합니다(구성에 따라 원래 큐, 포이즌 메시지 큐 또는 배달 못한 편지 큐로 반환될 수 있음).

이 기능은 중요하지만 일반적으로 발생하는 몇 가지 문제가 있습니다. 하나는 트랜잭션 비용이 많이 들고 큐를 사용하여 많은 읽기/쓰기를 생성하므로 오버헤드와 복잡성이 더 높아집니다. 또 다른 문제는 동일한 서비스가 다음에 큐에서 끌어올 때 메시지를 처리하도록 할 수 있는 방법이 없다는 것입니다(예: 특정 서비스가 메시지를 "잠글" 방법이 없음). 이는 특정 시나리오에서 만들려는 보장입니다.

이러한 문제를 해결하기 위해 WCF 4에서는 큐에 대기 중인 메시지를 처리하기 위한 ReceiveContext라는 새 API를 도입했습니다. ReceiveContext를 사용하면 서비스가 큐에서 메시지를 "피킹"하여 처리를 시작할 수 있으며, 문제가 발생하여 예외가 throw되면 큐에 남아 있습니다. 서비스에서 나중에 다시 처리하기 위해 메시지를 "잠글" 수도 있습니다. ReceiveContext는 메시지를 처리한 후 큐에서 제거할 수 있도록 메시지를 "완료"하는 메커니즘을 제공합니다.

이 방법은 메시지를 더 이상 네트워크를 통해 큐에 읽고 다시 쓰지 않으며 처리 중에 개별 메시지가 다른 서비스 인스턴스에서 수신 거부되지 않기 때문에 여러 전선에서 작업을 간소화합니다. 작동 방식을 설명하는 간단한 예제를 살펴보겠습니다.

다음 예제에서는 ReceiveContext를 사용하여 큐에 도착하는 메시지를 처리하는 방법을 보여줍니다.

...

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]

[ReceiveContextEnabled(ManualControl = true)]

public void CalculateProduct(int firstNumber, int secondNumber)

{

    ReceiveContext receiveContext;

    (! ReceiveContext.TryGet(OperationContext.Current.IncomingMessageProperties,

         out receiveContext))

    {

        Console.WriteLine("ReceiveContext가 이 컴퓨터에 설치/검색되지 않았습니다.");

        return;

    }

    if ((firstNumber * secondNumber) % 2 == (receiveCount % 2))

    {

        receiveContext.Complete(TimeSpan.MaxValue);

        Console.WriteLine("{0} x {1} = {2}", firstNumber, secondNumber,

            firstNumber * secondNumber);

    }

    else

    {

        receiveContext.Abandon(TimeSpan.MaxValue);

        Console.WriteLine("{0}&{1} not processed", firstNumber, secondNumber);

    }

    receiveCount++;

}

...

성공적으로 통과했다고 가정하면 ReceiveContext.Complete를 호출하여 메시지 처리를 완료하여 기본 큐에서 제거됩니다. 그렇지 않으면 Abandon를 호출합니다. 그러면 나중에 다시 시도하기 위해 큐에 메시지가 남습니다. .NET 4 SDK에는 이 새로운 기능을 보다 자세히 살펴보는 데 사용할 수 있는 전체 샘플이 함께 제공됩니다.

ByteStreamMessageEncodingBindingElement를 사용하여 인코딩 간소화

일부 메시징 시나리오에서는 래핑이나 추가 처리 없이 이진 데이터의 "Blob"을 전송하려고 합니다. 이 시나리오를 간소화하기 위해 WCF 4에는 이를 수행하는 새로운 ByteStreamMessageEncodingBindingElement가 함께 제공됩니다. 안타깝게도 .NET 4에는 이 인코더에 대한 새 바인딩이 제공되지 않으므로 이를 사용하려면 사용자 지정 바인딩을 작성해야 합니다.

.NET 4 SDK에는 사용자 지정 바인딩 클래스를 통해 ByteStreamMessageEncodingBindingElement를 사용하는 사용자 지정 바인딩을 정의하는 방법을 보여 주는 전체 예제가 제공됩니다. 새 바인딩 클래스가 배치되면 바이트 스트림 인코더를 서비스에서 사용하기가 매우 쉬워집니다.

고성능 ETW 기반 추적

또한 WCF 4는 추적 및 진단 전면을 개선합니다. 이제 WCF 4는 추적에 ETW를 사용하여 추적 성능을 크게 향상시키고 Windows Workflow Foundation, Windows Server AppFabric 및 Windows Server에 있는 다양한 관리 기술과 같은 다른 관련 기술과 더 나은 통합을 제공하여 플랫폼에 더 나은 모델을 제공합니다.

ETW를 사용하면 이벤트 공급자가 세션에 이벤트를 쓰고 세션은 필요에 따라 해당 이벤트를 로그에 유지할 수 있습니다. 소비자는 실시간 세션 이벤트를 수신 대기하거나 사실 이후에 로그에서 해당 이벤트를 읽을 수 있습니다. ETW 컨트롤러는 세션을 사용/사용하지 않도록 설정하고 공급자를 세션과 연결해야 합니다.

.NET 4 SDK는 WCF 서비스와 함께 이 새로운 고성능 추적 아키텍처를 활용하는 방법을 보여 주는 간단한 예제를 제공합니다.

결론

WCF 4는 오늘날 가장 일반적인 통신 시나리오 중 일부를 해결하는 다양한 개선 사항과 몇 가지 완전히 새로운 기능을 제공합니다. 무엇보다도 WCF 4는 간소화된 구성 모델을 통해 더 쉽게 사용하고 일반적인 기본값을 더 잘 지원합니다.

또한 WCF 4는 대부분의 엔터프라이즈 환경 및 대규모 SOA 이니셔티브에서 일반적인 요구 사항인 서비스 검색 및 라우팅에 대한 최고 수준의 지원을 제공합니다. 이러한 기능만으로도 WCF는 여러 경쟁 프레임워크와 차별화됩니다. 또한 WCF 4는 REST 기반 서비스 개발을 간소화하고 현재 몇 가지 특정 문제를 해결하는 몇 가지 고급 WCF 기능을 제공합니다.

이 모든 것 외에도 WCF 4는 선언적 워크플로 서비스를 개발하기 위한 새로운 모델을 제공하기 위해 WF와 정교한 통합을 제공합니다. 워크플로 서비스를 사용하면 WF 프로그래밍 모델 및 기본 런타임의 이점을 활용하는 장기 실행 및 비동기 서비스를 개발할 수 있습니다. 또한 새로운 WCF 기반 활동과 Visual Studio 2010 내에서 발견된 디자이너 지원 덕분에 이 새로운 프로그래밍 모델은 서비스 제작을 위한 일류 옵션이 되고 있습니다.

.NET 4에서는 WCF와 WF의 세계가 함께 병합되어 두 세계가 제공하는 최상의 프로그램을 제공하는 응집력 있는 프로그래밍 모델을 제공합니다. WF 4의 새로운 내용에 대한 자세한 내용은 .NET 4에서 개발자의 Windows 워크플로 파운데이션 소개를 검사.

저자 정보

Aaron Skonnard는 강사 주도 및 주문형 .NET 개발자 과정을 모두 제공하는 Microsoft 교육 공급자인 Pluralsight의 공동 창업자입니다. 요즘 아론은 Pluralsight 주문형을 녹음하는 데 대부분의 시간을 보냅니다! 클라우드 컴퓨팅, Windows Azure, WCF 및 REST에 중점을 두는 과정입니다. Aaron은 전 세계의 전문 개발자를 작성하고, 말하고, 가르치는 데 수년을 보냈습니다. 및 http://twitter.com/skonnard에서 http://pluralsight.com/aaron 그에게 연락할 수 있습니다.

추가 리소스