Udostępnij za pośrednictwem


Wprowadzenie dewelopera do programu Windows Communication Foundation 4

Aaron Skonnard, Pluralsight

Oryginał: listopad 2009 r.

Zaktualizowano do RTM: kwiecień 2010 r.

Przegląd

Platforma .NET 4 oferuje kilka atrakcyjnych nowych funkcji i mile widziane ulepszenia w obszarze programu Windows Communication Foundation (WCF). Te ulepszenia WCF koncentrują się głównie na upraszczaniu środowiska deweloperów, włączaniu większej liczby scenariuszy komunikacyjnych i zapewnianiu rozbudowanej integracji z platformą Windows Workflow Foundation (WF), dzięki czemu "usługi przepływu pracy" są w pierwszej klasie obywatelem.

Dobrą wiadomością jest większość zmian WCF 4 koncentruje się na ułatwianiu dzisiejszych typowych scenariuszy i ułatwianiu nowych scenariuszy komunikacyjnych i stylów programowania. W związku z tym przeniesienie istniejących rozwiązań WCF do platformy .NET 4 będzie dość bezproblemowe pod względem migracji. Następnie po prostu decydujesz, które funkcje programu WCF 4 chcesz wykorzystać w swoich rozwiązaniach. W pozostałej części tego artykułu przedstawiono każdy z nowych obszarów funkcji WCF 4 i pokazuje, jak działają.

Co nowego w programie WCF 4

Program WCF 4 zawiera szeroką gamę konkretnych funkcji, ale rysunek 1 opisuje główne obszary funkcji, na których skupimy się w całym dokumencie poniżej. Te obszary funkcji zawierają podsumowanie większości nowości w programie WCF 4 i podkreślają możliwości najwyższego poziomu oferowane przez tę wersję platformy .NET Framework.

Rysunek 1. Obszary funkcji programu WCF 4

Obszar funkcji Opis

Uproszczona konfiguracja

Uproszczenie sekcji konfiguracji programu WCF dzięki obsłudze domyślnych punktów końcowych, powiązań i konfiguracji zachowania. Te zmiany umożliwiają hostowanie usług bez konfiguracji, co znacznie upraszcza środowisko deweloperskie w przypadku najbardziej typowych scenariuszy WCF.

Odkrycie

Nowa obsługa struktury dla zachowań odnajdywania usług ad hoc i zarządzanych, które są zgodne ze standardowym protokołem WS-Discovery.

Usługa routingu

Nowa obsługa platformy dla konfigurowalnej usługi routingu, której można używać w rozwiązaniach WCF. Udostępnia funkcje routingu opartego na zawartości, mostkowania protokołu i obsługi błędów.

Ulepszenia rest

Ulepszenia usług WCF WebHttp Services z dodatkowymi funkcjami i narzędziami, które upraszczają tworzenie usługi REST.

Usługi przepływu pracy

Rozbudowana obsługa platformy do integrowania programu WCF z platformą WF w celu zaimplementowania deklaratywnych długotrwałych usług przepływu pracy. Ten nowy model programowania zapewnia najlepsze platformy do zaoferowania (WCF & WF).

Po zakończeniu obsługi tych głównych obszarów funkcji krótko omówimy niektóre bardziej zaawansowane funkcje WCF niższego poziomu, które są dostarczane z platformą .NET 4, w tym elementy, takie jak ulepszone możliwości rozpoznawania typów, obsługa kolejek z konkurencyjnymi konsumentami ("odbieranie kontekstu"), obsługa nieprzepisanych danych binarnych za pośrednictwem kodera strumienia bajtowego i obsługa śledzenia opartego na technologii ETW o wysokiej wydajności.

Gdy skończymy, zobaczysz, że program WCF 4 staje się łatwiejszy w użyciu i zapewnia bardziej wbudowaną obsługę niektórych z dzisiejszych najbardziej typowych scenariuszy i stylów programowania.

Uproszczona konfiguracja

Ujednolicony model programowania oferowany przez usługę WCF w wersji 3.x jest zarówno błogosławieństwem, jak i przekleństwem — upraszcza pisanie logiki usługi dla różnych scenariuszy komunikacji, jednak zwiększa również złożoność po stronie konfiguracji rzeczy, ponieważ zapewnia tak wiele różnych podstawowych opcji komunikacji, które należy zrozumieć przed rozpoczęciem pracy.

Rzeczywistość jest konfiguracja WCF zwykle staje się najbardziej kosztownym obszarem korzystania z usługi WCF w praktyce dzisiaj, a znaczna część tej złożoności znajduje się na personelu IT/operacji, którzy nie są przygotowani do radzenia sobie z nim.

Biorąc pod uwagę tę rzeczywistość, jeśli rozważasz złożoność sieciową korzystania z programu WCF 3.x, można rozsądnie stwierdzić, że użycie jest trudniejsze niż jego poprzednik ASP.NET usług sieci Web (ASMX). Za pomocą środowiska ASMX można było zdefiniować operację [WebMethod], a środowisko uruchomieniowe automatycznie dostarczyło konfigurację domyślną dla podstawowej komunikacji. W przypadku przechodzenia do programu WCF 3.x deweloperzy muszą wiedzieć wystarczająco dużo o różnych opcjach konfiguracji programu WCF, aby zdefiniować co najmniej jeden punkt końcowy. A trudna liczba opcji konfiguracji często przeraża niektórych deweloperów.

W celu zapewnienia ogólnego środowiska WCF równie prostego, jak ASMX, WCF 4 jest dostarczany z nowym "domyślnym modelem konfiguracji", który całkowicie eliminuje potrzebę dowolnej konfiguracji programu WCF. Jeśli nie podasz żadnej konfiguracji programu WCF dla określonej usługi, środowisko uruchomieniowe programu WCF 4 automatycznie konfiguruje usługę przy użyciu niektórych standardowych punktów końcowych i domyślnych konfiguracji powiązań/zachowań. Dzięki temu znacznie łatwiej jest uzyskać usługę WCF i uruchomić, zwłaszcza dla tych, którzy nie znają różnych opcji konfiguracji programu WCF i chętnie akceptują wartości domyślne, przynajmniej rozpocząć pracę.

Domyślne punkty końcowe

W programie WCF 3.x, jeśli spróbujesz hostować usługę bez skonfigurowanych punktów końcowych, wystąpienie serviceHost zgłosi wyjątek informujący o konieczności skonfigurowania co najmniej jednego punktu końcowego. W przypadku programu WCF 4 nie jest to już możliwe, ponieważ środowisko uruchomieniowe automatycznie dodaje jeden lub więcej "domyślnych punktów końcowych", dzięki czemu usługa będzie można używać bez żadnej konfiguracji.

Oto jak to działa. Gdy aplikacja hosta wywołuje metodę Otwórz w wystąpieniu serviceHost, kompiluje wewnętrzny opis usługi z pliku konfiguracji aplikacji wraz z wszystkimi elementami, które aplikacja hosta mogła jawnie skonfigurować, a jeśli liczba skonfigurowanych punktów końcowych jest nadal równa zero, wywołuje metodę AddDefaultEndpoints, nową metodę publiczną znalezioną w klasie ServiceHost. Ta metoda dodaje jeden lub więcej punktów końcowych do opisu usługi na podstawie adresów podstawowych usługi (w scenariuszach usług IIS jest to adres svc). Ponieważ metoda jest publiczna, można ją również wywołać bezpośrednio w niestandardowych scenariuszach hostingu.

Aby dokładnie określić, implementacja addDefaultEndpoints dodaje jeden domyślny punkt końcowy dla każdego adresu podstawowego dla każdego kontraktu usługi zaimplementowanego przez usługę. Jeśli na przykład usługa implementuje dwa kontrakty usług i skonfigurujesz hosta przy użyciu jednego adresu podstawowego, punkty AddDefaultEndpoints skonfigurują usługę z dwoma domyślnymi punktami końcowymi (po jednym dla każdego kontraktu usługi). Jeśli jednak usługa implementuje dwa kontrakty usług, a host jest skonfigurowany z dwoma adresami podstawowymi (jeden dla protokołu HTTP i jeden dla protokołu TCP), punkty AddDefaultEndpoints skonfigurują usługę z czterema domyślnymi punktami końcowymi.

Przyjrzyjmy się kompletnemu przykładowi, aby zilustrować to działanie ho'w. Załóżmy, że masz następujące kontrakty usług WCF i następującą implementację usługi:

[ServiceContract]

interfejs publiczny IHello

{

    [OperationContract]

    void SayHello(nazwa ciągu);

}

[ServiceContract]

interfejs publiczny IGoodbye

{

    [OperationContract]

    void SayGoodbye(nazwa ciągu);

}

public class GreetingService: IHello, IGoodbye // usługa implementuje oba kontrakty

{

    public void SayHello(nazwa ciągu)

    {

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

    }

    public void SayGoodbye(nazwa ciągu)

    {

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

    }

}

W programie WCF 4 można teraz używać klasy ServiceHost do hostowania usługi GreetingService bez żadnej konfiguracji aplikacji. W przypadku korzystania z elementu ServiceHost w niestandardowych scenariuszach hostingu należy określić co najmniej jeden adres podstawowy do użycia. Poniżej pokazano, jak hostować usługę GreetingService w aplikacji konsolowej i ponownie można założyć, że nie ma pliku app.config skojarzonego z tym programem:

class Program

{

    static void Main(string[] args)

    {

        Host jest skonfigurowany z dwoma adresami podstawowymi: jeden dla protokołu HTTP i jeden dla protokołu TCP

        ServiceHost host = new ServiceHost(typeof(GreetingService),

            nowy identyfikator URI("https://localhost:8080/greeting"),

            nowy identyfikator URI("net.tcp://localhost:8081/greeting"));

        gospodarz. Open();

        foreach (serviceEndpoint se na hoście. Description.Endpoints)

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

                Se. Adres, se.Binding.Name, se.Contract.Name);

        Console.WriteLine("Naciśnij <Wprowadź>, aby zatrzymać usługę".");

        Console.ReadLine();

        gospodarz. Close();

    }

}

W tym przykładzie skonfigurowano host ServiceHost z dwoma adresami podstawowymi: jeden dla protokołu HTTP i drugi dla protokołu TCP. Po uruchomieniu tego programu zobaczysz cztery punkty końcowe wydrukowane w oknie konsoli, jak pokazano na rysunku 2. Otrzymasz dwa adres podstawowy HTTP, jeden na kontrakt i dwa dla podstawowego adresu TCP, ponownie jeden na kontrakt. To wszystko jest udostępniane w tle przez wystąpienie ServiceHost.

Rysunek 2. Domyślne punkty końcowe wyświetlane w oknie konsoli

Zwróć uwagę, że program WCF wybiera użycie parametru BasicHttpBinding dla domyślnych punktów końcowych HTTP i NetTcpBinding dla domyślnych punktów końcowych TCP. Pokażę, jak wkrótce zmienić te ustawienia domyślne.

Pamiętaj, że to domyślne zachowanie punktu końcowego jest uruchamiane tylko wtedy, gdy usługa nie została skonfigurowana z żadnymi punktami końcowymi. Jeśli zmienię aplikację konsolową w celu skonfigurowania usługi z co najmniej jednym punktem końcowym, w danych wyjściowych nie będzie już widoczny żaden z tych domyślnych punktów końcowych. Aby to zilustrować, po prostu dodaję następujący wiersz kodu, który wywołuje polecenie AddServiceEndpoint po utworzeniu wystąpienia serviceHost:

...

ServiceHost host = new ServiceHost(typeof(GreetingService),

    nowy identyfikator URI("https://localhost:8080/greeting"),

    nowy identyfikator URI("net.tcp://localhost:8081/greeting"));

gospodarz. AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "myendpoint");

...

Jeśli uruchomisz aplikację konsolową z wstawionym wierszem kodu, zauważysz, że w danych wyjściowych pojawi się tylko jeden punkt końcowy — ten, który skonfigurowaliśmy ręcznie w powyższym kodzie (zobacz Rysunek 3).

Rysunek 3. Dane wyjściowe konsoli po skonfigurowaniu hosta przy użyciu jednego punktu końcowego

Jednak zawsze możesz wywołać funkcję AddDefaultEndpoints samodzielnie, jeśli nadal chcesz dodać zestaw domyślnych punktów końcowych wraz z własnymi. Poniższy przykład kodu ilustruje, jak to zrobić:

...

ServiceHost host = new ServiceHost(typeof(GreetingService),

    nowy identyfikator URI("https://localhost:8080/greeting"),

    nowy identyfikator URI("net.tcp://localhost:8081/greeting"));

gospodarz. AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "myendpoint");

gospodarz. AddDefaultEndpoints();

...

Jeśli ponownie uruchomisz aplikację konsolową z tą zmianą, zobaczysz pięć punktów końcowych wyświetlanych w oknie konsoli — skonfigurowany ręcznie wraz z czterema domyślnymi punktami końcowymi (zobacz Rysunek 4).

Rysunek 4. Dane wyjściowe konsoli po ręcznym wywołaniu funkcji AddDefaultEndpoints

Teraz, gdy rozumiemy algorytm i mechanikę dodawania domyślnych punktów końcowych do usług w czasie wykonywania, następnym pytaniem jest, w jaki sposób program WCF decyduje, które powiązanie ma być używane dla określonego adresu opartego?

Domyślne mapowanie protokołu

Odpowiedź na to pytanie jest prosta. Program WCF definiuje domyślne mapowanie protokołów między schematami protokołów transportu (np. http, net.tcp, net.pipe itp.) i wbudowanymi powiązaniami WCF. Domyślne mapowanie protokołu znajduje się w pliku komentarzy platformy .NET 4 machine.configi wygląda następująco:

<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>

   ...

Te mapowania można zastąpić na poziomie maszyny, dodając tę sekcję do machine.config i modyfikując mapowanie dla każdego schematu protokołu. Jeśli chcesz zastąpić ją tylko w zakresie aplikacji, możesz zastąpić tę sekcję w pliku konfiguracji aplikacji/sieci Web.

Jeśli na przykład organizacja koncentruje się głównie na tworzeniu usług RESTful za pomocą usługi WCF, warto zmienić domyślne powiązanie dla schematu protokołu "http" na webHttpBinding. W poniższym przykładzie pokazano, jak to zrobić w pliku konfiguracji aplikacji:

<konfiguracji>

  <system.serviceModel>

    <protocolMapping>

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

    </protocolMapping>

  </system.serviceModel>

</configuration>

Teraz, jeśli uruchomię ponownie aplikację konsolową pokazaną wcześniej z tym app.config, dwa domyślne punkty końcowe oparte na protokole HTTP będą teraz pokazywać, że korzystają z narzędzia WebHttpBinding (zobacz Rysunek 5).

Rysunek 5. Dane wyjściowe konsoli po zastąpieniu domyślnego mapowania protokołu HTTP

Gdy program WCF określi, które powiązanie ma być używane za pośrednictwem tabeli mapowania protokołu, używa domyślnej konfiguracji powiązania podczas konfigurowania domyślnego punktu końcowego. Jeśli nie jesteś zadowolony z wbudowanych ustawień domyślnych powiązania, możesz również zastąpić konfigurację domyślną dla określonego powiązania.

Domyślne konfiguracje powiązań

Każde powiązanie WCF zawiera domyślną konfigurację, która jest używana, chyba że jawnie zastąpi aplikację hosta dla określonego punktu końcowego. Każde używane wystąpienie powiązania zawsze jest dostarczane z wbudowanymi wartościami domyślnymi, chyba że zdecydujesz się zastąpić, stosując jawną konfigurację powiązania.

W programie WCF 3.x można to zrobić, definiując nazwaną konfigurację powiązania, którą można zastosować do definicji punktów końcowych za pomocą atrybutu bindingConfiguration. Mechanika robienia tego prawidłowo jest kłopotliwa i podatna na błędy.  Poniższy plik konfiguracji przedstawia typowy przykład:

<konfiguracji>

  <system.serviceModel>

    <powiązania>

      <basicHttpBinding>

        <nazwa powiązania="BasicWithMtom" messageEncoding="Mtom"/>

      </basicHttpBinding>

    </bindings>

    > usług <

      <nazwa usługi="GreetingService">

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

                  bindingConfiguration="BasicWithMtom"

                  contract="IHello"/>

      </service>

    </services>

  </system.serviceModel>

</configuration>

W powyższym przykładzie konfiguracja powiązania "BasicWithMtom" zastępuje wartości domyślne dla parametru BasicHttpBinding, zmieniając kodowanie komunikatów na MTOM. Jednak ta konfiguracja powiązania ma zastosowanie tylko wtedy, gdy stosujesz ją do określonego punktu końcowego za pomocą atrybutu "bindingConfiguration" — jest to krok, który często wymyka się deweloperom i pracownikom operacyjnym, powodując problemy z konfiguracją.

W programie WCF 4 można teraz definiować domyślne konfiguracje powiązań, po prostu pomijając nazwę konfiguracji powiązania podczas definiowania nowej konfiguracji. Następnie program WCF będzie używać tej domyślnej konfiguracji dla wszystkich punktów końcowych przy użyciu tego powiązania, które nie ma jawnej konfiguracji powiązania ustawionej na nich.

Jeśli na przykład dodamy następujący plik app.config do wyświetlonej wcześniej aplikacji konsolowej, dwa domyślne punkty końcowe HTTP będą pobierać tę domyślną konfigurację BasicHttpBinding, która włącza funkcję MTOM:

<konfiguracji>

  <system.serviceModel>

    <powiązania>

      <basicHttpBinding>

        <komunikat powiązaniaEncoding="Mtom"/><!-- zauważ, że nie ma atrybutu name ->

      </basicHttpBinding>

    </bindings>

  </system.serviceModel>

</configuration>

Oczywiście można również dodać te domyślne konfiguracje powiązań, aby machine.config, jeśli chcesz, aby zaczęły obowiązywać we wszystkich usługach uruchomionych na maszynie lub można je zdefiniować na aplikacji według aplikacji, dodając domyślne konfiguracje powiązań w pliku konfiguracji aplikacji.

Ta funkcja zapewnia prosty mechanizm definiowania standardowego zestawu powiązań domyślnych, których można używać we wszystkich usługach bez nakładania złożoności konfiguracji powiązań na innych deweloperów lub pracowników it/operacyjnych. Mogą po prostu wybrać odpowiednie powiązanie i mieć pewność, że właściwa konfiguracja domyślna zostanie udostępniona przez środowisko hostingu.

Oprócz domyślnych konfiguracji powiązań, inne kwestie, które należy wziąć pod uwagę w przypadku usług i punktów końcowych, jest to, jaka powinna być ich domyślna konfiguracja zachowania.

Domyślne konfiguracje zachowania

Program WCF 4 umożliwia również zdefiniowanie domyślnych konfiguracji zachowania dla usług i punktów końcowych, co może uprościć elementy, gdy chcesz udostępnić standardową konfigurację zachowania domyślnego we wszystkich usługach lub punktach końcowych uruchomionych na maszynie lub w rozwiązaniu.

W programie WCF 3.x należy zdefiniować nazwane konfiguracje zachowania, które jawnie mają zastosowanie do usług i punktów końcowych za pomocą atrybutu "behaviorConfiguration". W programie WCF 4 można zdefiniować domyślne konfiguracje zachowania, pomijając nazwę w definicji konfiguracji. Jeśli dodasz te domyślne zachowania do machine.config, będą one stosowane do wszystkich usług lub punktów końcowych hostowanych na maszynie. Jeśli dodasz je do app.config, zostaną one zastosowane tylko w zakresie aplikacji hosta. Oto przykład:

<konfiguracji>

  <system.serviceModel>

    <zachowania>

      <serviceBehaviors>

        <zachowanie><!-- zauważyć brak atrybutu nazwy —>

          <serviceMetadata httpGetEnabled="true"/>

        </behavior>

       </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

Ten przykład włącza metadane usługi dla każdej usługi, która nie zawiera jawnej konfiguracji zachowania. Jeśli dodamy tę domyślną konfigurację zachowania do pliku app.config dla aplikacji konsolowej wyświetlanej wcześniej, a następnie ponownie uruchomimy aplikację, możemy przejść do podstawowego adresu HTTP, aby pobrać stronę pomocy usługi i definicję WSDL usługi (zobacz Rysunek 6).

Rysunek 6. Przechodzenie do metadanych usługi włączone do domyślnej konfiguracji zachowania

Kolejną nową funkcją w programie WCF 4 jest to, że konfiguracje zachowania obsługują teraz model dziedziczenia. Jeśli aplikacja definiuje konfigurację zachowania przy użyciu takiej samej nazwy jak określona w machine.config, konfiguracja zachowania specyficznego dla aplikacji zostanie scalona z konfiguracją całego komputera, dodając wszelkie dodatkowe zachowania do pochodnej konfiguracji zachowania złożonego.

Punkty końcowe w warstwie Standardowa

Powiązane z domyślnymi punktami końcowymi to kolejna nowa funkcja WCF 4 znana jako "standardowe punkty końcowe". Standardowy punkt końcowy można traktować jako typową wstępnie skonfigurowaną definicję punktu końcowego wbudowaną w strukturę WCF 4, której można po prostu użyć. Punkty końcowe w warstwie Standardowa definiują konfigurację punktów końcowych w warstwie Standardowa, której zwykle nie zmieniasz, chociaż możesz to zrobić, jeśli musisz to zobaczyć wkrótce.

Rysunek 7 opisuje standardowe punkty końcowe dostarczane z usługą WCF 4. Zapewniają one standardowe definicje punktów końcowych dla niektórych z najbardziej typowych funkcji i scenariuszy komunikacji WCF 4. Na przykład w przypadku punktu końcowego MEX zawsze trzeba będzie określić IMetadataExchange dla kontraktu usługi i najprawdopodobniej wybrać protokół HTTP. Dlatego zamiast wymuszać ręczne wykonywanie tych czynności, usługa WCF udostępnia standardową definicję punktu końcowego dla wymiany metdata o nazwie "mexEndpoint", która jest łatwa w użyciu.

Rysunek 7. Standardowe punkty końcowe w programie WCF 4

Standardowa nazwa punktu końcowego Opis

mexEndpoint

Definiuje standardowy punkt końcowy dla środowiska MEX skonfigurowany za pomocą interfejsu IMetadataExchange dla kontraktu usługi, mexHttpBinding jako domyślne powiązanie (można to zmienić) i pusty adres.

dynamicEndpoint

Definiuje standardowy punkt końcowy skonfigurowany do używania odnajdywania WCF w aplikacji klienckiej WCF. W przypadku korzystania z tego standardowego punktu końcowego adres nie jest wymagany, ponieważ podczas pierwszego wywołania klient wykona zapytanie o punkt końcowy usługi pasujący do określonego kontraktu i automatycznie nawiąż z nim połączenie. Domyślnie zapytanie odnajdywania jest wysyłane za pośrednictwem protokołu UDP multiemisji, ale można określić powiązanie odnajdywania i kryteria wyszukiwania do użycia w razie potrzeby.

discoveryEndpoint

Definiuje standardowy punkt końcowy, który jest wstępnie skonfigurowany do operacji odnajdywania w aplikacji klienckiej. Użytkownik musi określić adres i powiązanie podczas korzystania z tego standardowego punktu końcowego.

udpDiscoveryEndpoint

Definiuje standardowy punkt końcowy, który jest wstępnie skonfigurowany do operacji odnajdywania w aplikacji klienckiej przy użyciu powiązania UDP na adresie multiemisji. Pochodzi z odnajdywaniaEndpoint.

anonsEndpoint

Definiuje standardowy punkt końcowy, który jest wstępnie skonfigurowany dla funkcji anonsowania odnajdywania. Użytkownik musi określić adres i powiązanie podczas korzystania z tego standardowego punktu końcowego.

udpAnnouncementEndpoint

Definiuje standardowy punkt końcowy, który jest wstępnie skonfigurowany dla funkcji anonsu za pośrednictwem powiązania UDP na adresie multiemisji. Ten punkt końcowy pochodzi z anonsEndpoint.

workflowControlEndpoint

Definiuje standardowy punkt końcowy do kontrolowania wykonywania wystąpień przepływu pracy (tworzenie, uruchamianie, wstrzymywanie, kończenie itp.).

webHttpEndpoint

Definiuje standardowy punkt końcowy skonfigurowany za pomocą biblioteki WebHttpBinding i webHttpBehavior. Użyj polecenia , aby uwidocznić usługi REST.

webScriptEndpoint

Definiuje standardowy punkt końcowy skonfigurowany za pomocą elementu WebHttpBinding i webScriptEnablingBehavior. Użyj polecenia , aby uwidocznić usługi Ajax.

Możesz użyć dowolnego z tych standardowych punktów końcowych we własnych konfiguracjach usługi, po prostu odwołując się do nich według nazwy. Element <endpoint> zawiera teraz atrybut "kind", którego można użyć do określenia nazwy standardowego punktu końcowego. Na przykład poniższy przykład konfiguruje element GreetingService z punktem końcowym MEX przy użyciu standardowej definicji "mexEndpoint":

<konfiguracji>

  <system.serviceModel>

    > usług <

      <nazwa usługi="GreetingService">

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

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

      </service>

    </services>

  </system.serviceModel>

</configuration>

Mimo że standardowe punkty końcowe chronią Cię przed większością szczegółów konfiguracji (np. przy użyciu punktu końcowego mexEndpoint nie musiałem określać powiązania lub kontraktu), może być jeszcze kilka razy, kiedy chcesz ich używać, ale trzeba nieco inaczej skonfigurować standardowe definicje punktów końcowych. 

W tym celu możesz użyć sekcji <standardEndpoints> i zastąpić konfigurację punktu końcowego dla standardowego punktu końcowego. Następnie możesz odwołać się do tej konfiguracji podczas definiowania nowego punktu końcowego <> za pośrednictwem atrybutu endpointConfiguration, jak pokazano poniżej:

<konfiguracji>

  <system.serviceModel>

    > usług <

      <nazwa usługi="GreetingService">

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

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

      </service>

    </services>

    <standardEndpoints>

      < > udpDiscoveryEndpoint

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

      </udpDiscoveryEndpoint>

    </standardEndpoints>

    <zachowania>

      <serviceBehaviors>

        <zachowania>

          <serviceDiscovery/>

          <serviceMetadata httpGetEnabled="true"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

Ten przykład dotyczy zmiany domyślnej wersji WS-Discovery dla standardowego punktu końcowego o nazwie "udpDiscoveryEndpoint" (wkrótce omówimy więcej informacji na temat odnajdywania usług).

Upraszczanie hostingu usług IIS/ASP.NET

Biorąc pod uwagę te nowe funkcje domyślnych punktów końcowych, domyślne konfiguracje powiązań i domyślne konfiguracje zachowania, hosting w usługach IIS/ASP.NET staje się znacznie łatwiejszy w programie WCF 4. ASP.NET deweloperzy, którzy są przyzwyczajeni do pracy z usługami ASMX, mogą teraz definiować usługi WCF, które są równie proste w naturze.

W rzeczywistości sprawdź, jak prosta jest następująca definicja usługi WCF:

<!-- HelloWorld.svc —>

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

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

[ServiceContract]

public, klasa HelloWorldService

{

    [OperationContract]

    ciąg publiczny HelloWorld()

    {

        return "hello, world";

    }

}

Jest to najprostsza forma definicji usługi WCF, ponieważ nie używamy oddzielnej definicji interfejsu do definiowania kontraktu usługi i wszystko jest zdefiniowane w jednym pliku HelloWorld.svc (uwaga: nie zalecamy tego podejścia, tylko zauważając, że możliwe jest porównanie z ASMX). Powinno to wydawać się bardzo podobne do typowych usług ASMX, co jest podstawową różnicą w nazwach atrybutów używanych w klasie usługi (np. [WebService] i [WebMethod]). Na pewno jest mniej ruchomych części.

Dzięki nowym funkcjom programu WCF 4 opisanym w poprzedniej sekcji możesz teraz przejść do witryny HelloWorld.svc bez dodatkowej konfiguracji programu WCF, a logika aktywacji programu WCF utworzy wystąpienie serviceHost w tle i skonfiguruje je przy użyciu jednego domyślnego punktu końcowego HTTP. Jeśli dodano domyślne zachowanie usługi do pliku machine.config włączania metadanych usługi, zobaczysz stronę pomocy programu WCF i link do definicji WSDL podczas przeglądania witryny HelloWorld.svc (zobacz Rysunek 8).

Rysunek 8. Strona pomocy HelloWorldService

Jeśli nie włączono obsługi metadanych usługi dla całej maszyny, możesz ją włączyć w aplikacji internetowej, dodając następującą domyślną konfigurację zachowania do pliku web.config:

...

<system.serviceModel>

  <zachowania>

    <serviceBehaviors>

      <zachowanie><!-- zauważ, że nie ma atrybutu name —>

         <serviceMetadata httpGetEnabled="true"/>

      </behavior>

    </serviceBehaviors>

  </behaviors>

</system.serviceModel>

...

Możesz również zmienić inne ustawienia domyślne, postępując zgodnie z procedurami opisanymi w poprzednich sekcjach. Można na przykład zmienić domyślne mapowanie protokołu, dodać domyślne konfiguracje powiązań lub dodatkowe domyślne konfiguracje zachowania. Jeśli usługa implementuje więcej niż jeden kontrakt usługi, wynikowe wystąpienie serviceHost zostanie skonfigurowane z jednym punktem końcowym HTTP na kontrakt.

Załóżmy na przykład, że hostujemy naszą usługę GreetingService (z wcześniejszej wersji) za pośrednictwem pliku svc pokazanego tutaj:

<!-- GreetingService.svc —>

<%@ServiceHost Service="GreetingService"%>

Biorąc pod uwagę naszą definicję greetingService, po raz pierwszy przejdziesz do elementu GreetingService.svc, logika aktywacji programu WCF utworzy wystąpienie ServiceHost i doda dwa domyślne punkty końcowe HTTP dla typu GreetingService (jeden dla każdego kontraktu usługi). Możesz to sprawdzić, przechodząc do definicji WSDL i znajdziesz dwa elementy <portów> w elemecie> usługi <.

Ogólnie rzecz biorąc, te uproszczenia konfiguracji WCF powinny znacznie ułatwić deweloperom ASP.NET uzyskanie usług WCF w swoich aplikacjach internetowych i przybliżenie najprostszego przypadku deweloperów do korzystania z usług ASP.NET sieci Web.

Aktywacja bez plików

Mimo że pliki .svc ułatwiają uwidacznienie usług WCF, jeszcze łatwiejsze byłoby zdefiniowanie punktów końcowych aktywacji wirtualnej w Web.config, co spowoduje całkowite usunięcie potrzeby plików svc.

W programie WCF 4 można zdefiniować punkty końcowe aktywacji usługi wirtualnej mapujące typy usług na Web.config. Dzięki temu można aktywować usługi WCF bez konieczności obsługi fizycznych plików svc (np. "aktywacja bez plików"). W poniższym przykładzie pokazano, jak skonfigurować punkt końcowy aktywacji:

<konfiguracji>

  <system.serviceModel>

    <serviceHostingEnvironment>

      <serviceActivations>

        <dodać element relativeAddress="Greeting.svc" service="GreetingService"/>

      </serviceActivations>

    </serviceHostingEnvironment>

  </system.serviceModel>

</configuration>

Dzięki temu można teraz aktywować usługę GreetingService przy użyciu względnej ścieżki "Greeting.svc" (względem podstawowego adresu aplikacji internetowej). Aby to zilustrować, utworzono aplikację usług IIS na mojej maszynie o nazwie "GreetingSite", którą przypisano do puli aplikacji "ASP.NET w wersji 4.0" i zamapowano ją do katalogu projektu GreetingService, który zawiera web.config pokazane powyżej. Teraz mogę po prostu przejść do https://localhost/GreetingSite/Greeting.svc bez fizycznego pliku svc na dysku. Na rysunku 9 pokazano, jak wygląda to w przeglądarce.

Rysunek 9. Przykład aktywacji bez plików

Odkrycie

Kolejną główną funkcją WCF 4, o której będziemy dyskutować, jest odnajdywanie usług. W niektórych wyspecjalizowanych środowiskach zorientowanych na usługi istnieją usługi, których lokalizacja środowiska uruchomieniowego jest dynamiczna i stale się zmienia. Rozważmy na przykład środowiska, w których różne typy urządzeń z obsługą usług stale dołączają i opuszczają sieć w ramach ogólnego rozwiązania biznesowego. Obsługa tej rzeczywistości wymaga od klientów dynamicznego odnajdywania lokalizacji środowiska uruchomieniowego punktów końcowych usługi.

WS-Discovery to specyfikacja OASIS, która definiuje protokół oparty na protokole SOAP na potrzeby dynamicznego odnajdywania lokalizacji punktów końcowych usługi w czasie wykonywania. Protokół umożliwia klientom sondowanie punktów końcowych usługi spełniających określone kryteria w celu pobrania listy odpowiednich kandydatów. Klient może następnie wybrać konkretny punkt końcowy z listy odnalezionych i użyć jego bieżącego adresu punktu końcowego środowiska uruchomieniowego.

WS-Discovery definiuje dwa podstawowe tryby działania: tryb ad hoc i tryb zarządzany. W trybie ad hoc klienci sonduje usługi, wysyłając komunikaty multiemisji. Platforma zapewnia mechanizm multiemisji UDP dla tego trybu ad hoc. Usługi zgodne z sondą odpowiadają bezpośrednio klientowi. Aby zminimalizować potrzebę sondowania klientów, usługi mogą również "ogłaszać" się podczas dołączania lub opuszczania sieci przez wysłanie komunikatu multiemisji do klientów, którzy mogą "nasłuchiwać". Odnajdywanie ad hoc jest ograniczone przez protokół używany do multiemisji komunikatów, w przypadku protokołu UDP tylko usługi nasłuchiwania w podsieci lokalnej będą mogły odbierać komunikaty.

Dzięki odnajdywaniem usługi zarządzanej udostępniasz serwer proxy odnajdywania w sieci, który "zarządza" punktami końcowymi odnajdywania usługi. Klienci komunikują się bezpośrednio z serwerem proxy odnajdywania, aby zlokalizować usługi na podstawie kryteriów sondowania. Serwer proxy odnajdywania wymaga repozytorium usług, które może być zgodne z zapytaniem. Jak serwer proxy jest wypełniany tymi informacjami, jest szczegółem implementacji. Serwery proxy odnajdywania można łatwo połączyć z repozytorium usługi, można je wstępnie skonfigurować z listą punktów końcowych lub serwer proxy odnajdywania może nawet nasłuchiwać anonsów w celu zaktualizowania pamięci podręcznej. W trybie zarządzanym anonsy mogą być emisją pojedynczą bezpośrednio do adresata, potencjalnie przez serwer proxy odnajdywania.

Platforma .NET 4.0 udostępnia klasy podstawowe, które należy zaimplementować własny serwer proxy odnajdywania. Klasy podstawowe wyodrębniają szczegóły protokołu odnajdywania, dzięki czemu można po prostu skupić się na logice, która ma zawierać serwer proxy odnajdywania. Na przykład wystarczy zdefiniować, co serwer proxy odnajdywania zrobi w odpowiedzi na komunikat sondy, komunikaty anonsu i rozwiąż komunikaty.

Program WCF 4 zapewnia pełną implementację protokołu WS-Discovery i zapewnia obsługę trybów odnajdywania ad hoc i zarządzanych. Przyjrzymy się pokrótce każdemu z poniższych elementów.

Proste odnajdywanie usług

Najprostszym sposobem włączenia odnajdywania usług jest tryb ad hoc. Program WCF ułatwia odnajdywanie usług w aplikacjach hosta usługi, zapewniając niektóre standardowe punkty końcowe odnajdywania i zachowanie odnajdywania usługi. Aby skonfigurować usługę na potrzeby odnajdywania, wystarczy dodać standardowy punkt końcowy "udpDiscoveryEndpoint", a następnie włączyć <serviceDiscovery> zachowanie w usłudze.

Oto kompletny przykład pokazujący, jak to zrobić:

<konfiguracji>

    <system.serviceModel>

      > usług <

        > nazwa usługi <="CalculatorService"

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

          <!-- dodać standardowy punkt końcowy odnajdywania UDP —>

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

        </service>

      </services>

      <zachowania>

        <serviceBehaviors>

          <zachowania>

            <serviceDiscovery/><!-- włączanie zachowania odnajdywania usługi —>

          </behavior>

        </serviceBehaviors>

      </behaviors>

    </system.serviceModel>

</configuration>

Dzięki temu usługa staje się odnajdywalna za pośrednictwem protokołu UDP w podsieci lokalnej. Klienci mogą następnie korzystać z WS-Discovery w czasie wykonywania, aby "odnaleźć" rzeczywisty adres uruchomionej usługi. Program WCF 4 ułatwia klientom osiągnięcie tego celu za pośrednictwem standardowego punktu końcowego dynamicEndpoint.

Po prostu użyj istniejącego punktu końcowego klienta do nawiązania połączenia z usługą, usuń adres i dodaj tag kind="dynamicEndpoint".

<konfiguracji>

    <system.serviceModel>

        > klienta <

          punkt końcowy <

              name="calculatorEndpoint"

              kind="dynamicEndpoint"

              binding="wsHttpBinding"

              contract="ICalculatorService">

          </endpoint>

        </client>

    </system.serviceModel>

</configuration>

Po utworzeniu pierwszego wywołania usługi klient wyśle zapytanie multiemisji, które będzie pasować do kontraktu ICalculatorService i spróbuje nawiązać połączenie z jednym. Różne ustawienia umożliwiają dostosowanie serach, dostosowanie powiązań odnajdywania i sterowanie procesem odnajdywania. Możesz również wykonać wszystkie te czynności programowo przy użyciu klasy DiscoveryClient.

Poniższy przykład idzie o krok dalej, pokazując sposób programowego odnajdywania punktu końcowego UdpDiscoveryEndpoint w celu odnalezienia punktu końcowego ICalculatorService, a następnie wywołania go:

Tworzenie elementu DiscoveryClient

DiscoveryClient DiscoveryClient =

    new DiscoveryClient(new UdpDiscoveryEndpoint());

Znajdowanie punktów końcowych ICalculatorService w określonym zakresie

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

FindResponse findResponse = discoveryClient.Find(findCriteria);

Wystarczy wybrać pierwszy odnaleziony punkt końcowy

Adres EndpointAddress = findResponse.Endpoints[0]. Adres;

Tworzenie klienta usługi docelowej

CalculatorServiceClient client =

    new CalculatorServiceClient("calculatorEndpoint");

Nawiązywanie połączenia z odnalezionym punktem końcowym usługi

klient. Endpoint.Address = address;

Console.WriteLine("Wywoływanie kalkulatoraservice w {0}", adres);

Wywołaj operację Dodaj usługę.

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

Console.WriteLine("Add({0},{1}) = {2}", 100, 15,99, wynik);

Po pobraniu kolekcji odnalezionych punktów końcowych program kliencki może użyć jednego z nich do faktycznego wywołania usługi docelowej. Rysunek 10 przedstawia dane wyjściowe uruchomienia kodu klienta pokazanego powyżej przy założeniu, że usługa jest również uruchomiona w tym samym czasie. Uwaga: w tym przykładzie operacja Znajdź na kliencie odnajdywania jest synchroniczna; odnajdywanie zapewnia również obsługę asynchronicznych operacji znajdowania.

Rysunek 10. Dane wyjściowe uruchamiania kodu klienta odnajdywania

Używanie zakresów podczas odnajdywania punktów końcowych

W poprzednim przykładzie klient po prostu sondował usługi na podstawie typu kontraktu usługi. Klienci mogą zawęzić wyniki odnajdywania, podając dodatkowe informacje określające zakres podczas wysyłania sond odnajdywania. Przyjrzyjmy się prostemu przykładowi, aby zobaczyć, jak "zakresy" mogą być używane podczas odnajdywania.

Najpierw usługa musi skojarzyć co najmniej jeden zakres z każdym punktem końcowym, który zostanie opublikowany na potrzeby odnajdywania. Program WCF 4 zawiera <endpointDiscovery> zachowanie, którego można użyć do definiowania zestawu zakresów, które można skojarzyć z definicją punktu końcowego. W poniższym przykładzie pokazano, jak skojarzyć dwa zakresy z pojedynczym punktem końcowym zdefiniowanym w usłudze:

<konfiguracji>

    <system.serviceModel>

      > usług <

        <nazwa usługi="CalculatorService"

                 behaviorConfiguration="calculatorServiceBehavior">

          <endpoint binding="wsHttpBinding"

                    contract="ICalculatorService"

                    behaviorConfiguration="ep1Behavior" />

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

        </service>

      </services>

      <zachowania>

        <serviceBehaviors>

          <nazwa zachowania="calculatorServiceBehavior">

            <serviceDiscovery/>

          </behavior>

        </serviceBehaviors>

        <endpointBehaviors>

          <zachowanie name="ep1Behavior">

            <endpointDiscovery>

               <!-- zakresy skojarzone z tym zachowaniem punktu końcowego —>

              zakresy <>

                <dodać zakres="http://www.example.org/calculator"/>

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

              </scopes>

            </endpointDiscovery>

          </behavior>

         </endpointBehaviors>

      </behaviors>

    </system.serviceModel>

</configuration>

Klienci mogą sondować punkty końcowe usługi na podstawie określonych zakresów w czasie wykonywania. Mogą to zrobić, dodając listę zakresów docelowych do wystąpienia FindCriteria, które podajesz do operacji Znajdź. Poniższy kod ilustruje sposób odnajdywania punktów końcowych ICalculatorService pasujących do określonego zakresu LDAP:

...

Tworzenie elementu DiscoveryClient

DiscoveryClient discoveryClient = new DiscoveryClient("udpDiscoveryEndpoint");

Znajdowanie punktów końcowych ICalculatorService w określonym zakresie

Zakres identyfikatora URI = nowy identyfikator URI("ldap:///ou=engineering,o=exampleorg,c=us");

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

findCriteria.Scopes.Add(scope);

FindResponse findResponse = discoveryClient.Find(findCriteria);

...

Dzięki wykorzystaniu zakresów można dostosować implementację odnajdywania, aby klienci mogli łatwiej odnajdywać interesujące je punkty końcowe usługi. Odnajdywanie umożliwia również dalsze dostosowywanie. Na przykład usługi mogą dodawać niestandardowe metadane XML do punktu końcowego. Te informacje są wysyłane do klienta w odpowiedzi na zapytanie klienta.

Ogłoszenia dotyczące usług

Program WCF 4 ułatwia również konfigurowanie usług w celu "ogłaszania" punktów końcowych podczas uruchamiania. Dzięki temu klienci , którzy "nasłuchują", mogą poznać nowe punkty końcowe usługi bezpośrednio, gdy dołączają do sieci, zmniejszając w ten sposób ilość sondowania (i obsługi komunikatów multiemisji) wykonywanych przez klientów.

Usługę z punktem końcowym anonsu można skonfigurować przy użyciu zachowania><serviceDiscovery. Zachowanie <serviceDiscovery> umożliwia zdefiniowanie kolekcji punktów końcowych anonsu, które zostaną ujawnione przez usługę. W większości przypadków można użyć standardu "udpAnnouncementEndpoint".

Nadal musisz również skonfigurować usługę przy użyciu standardowego "udpDiscoveryEndpoint", jeśli chcesz, aby odpowiadała na sondy odnajdywania inicjowane przez klientów. W poniższym przykładzie przedstawiono typową konfigurację:

<konfiguracji>

  <system.serviceModel>

    > usług <

      > nazwa usługi <="CalculatorService"

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

        <endpoint kind="udpDiscoveryEndpoint"/>

      </service>

    </services>

    <zachowania>

      <serviceBehaviors>

        <zachowania>

          <serviceDiscovery>

            <anonsEndpoints>

              <endpoint kind="udpAnnouncementEndpoint"/>

            </announcementEndpoints>

          </serviceDiscovery>

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

Po skonfigurowaniu tej konfiguracji usługa będzie ogłaszać się w trybie online i będzie również ogłaszać, kiedy przechodzi w tryb offline. Aby móc korzystać z tych anonsów, musisz specjalnie zaprojektować klientów, aby nasłuchiwać ich w czasie wykonywania. W tym celu należy hostować usługę anonsowania w aplikacji klienckiej, która implementuje protokół anonsu WS-Discovery.

WCF 4 zawiera klasę o nazwie AnnouncementService zaprojektowaną specjalnie w tym celu. Usługa AnnouncementService udostępnia dwa programy obsługi zdarzeń: OnlineAnnouncementReceived i OfflineAnnouncementReceived. Aplikacje klienckie mogą po prostu hostować wystąpienie usługi AnonsService przy użyciu klasy ServiceHost i rejestrować programy obsługi zdarzeń dla tych dwóch zdarzeń.

Za każdym razem, gdy usługa jest w trybie online i ogłasza się, usługa Anons hostowana przez klienta otrzyma ogłoszenie "online", a usługa OnlineAnnouncementReceived zostanie wyzwolona w kliencie. Gdy usługa przejdzie w tryb offline, wyśle anons "offline", a w kliencie zostanie wyzwolony komunikat OfflineAnnouncementReceived. Poniżej przedstawiono przykładową aplikację kliencką, która hostuje usługę AnnouncementService i implementuje programy obsługi dla dwóch zdarzeń anonsu:

klasa Klient

{

    public static void Main()

    {

        Tworzenie wystąpienia usługi AnonsService

        AnonsServiceService = new AnnouncementService();

        Subskrybowanie zdarzeń anonsu

        announcementService.OnlineAnnouncementReceived += OnOnlineEvent;

        announcementService.OfflineAnnouncementReceived += OnOfflineEvent;

        Tworzenie elementu ServiceHost dla elementu AnnouncementService

        using (ServiceHost announcementServiceHost =

            new ServiceHost(announcementService))

        {

            Nasłuchiwanie anonsów wysyłanych za pośrednictwem multiemisji UDP

            announcementServiceHost.AddServiceEndpoint(

                nowy element UdpAnnouncementEndpoint());

            announcementServiceHost.Open();

            Console.WriteLine("Nasłuchiwanie anonsów usług".");

            Console.WriteLine();

            Console.WriteLine("Naciśnij <ENTER> zakończyć.");

            Console.ReadLine();

        }

    }

    static void OnOnlineEvent(nadawca obiektów, AnonsEventArgs e)

    {

        Console.WriteLine();

        Console.WriteLine("Odebrano ogłoszenie online z {0}:",

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);

    }

    static void OnOfflineEvent(nadawca obiektów, AnonsEventArgs e)

    {

        Console.WriteLine();

        Console.WriteLine("Odebrano anons offline z {0}:",

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);

    }

    ...

}

Rysunek 11. Nasłuchiwanie komunikatów o anonsach odnajdywania

Teraz załóżmy, że uruchamiam ten program kliencki i odchodzię od jakiegoś czasu. Następnie uruchomię kilka wystąpień aplikacji hosta usługi. Po uruchomieniu każdego z nich w oknie konsoli klienta zostanie wyświetlony komunikat "online". Po zamknięciu każdej aplikacji hosta usługi w oknie konsoli klienta zostanie wyświetlony komunikat anonsu "offline". Rysunek 11 przedstawia wynikowe okno konsoli klienta po wykonaniu opisanych czynności.

Pamiętaj, że tryb odnajdywania ad hoc działa tylko w podsieci lokalnej. Jeśli chcesz użyć WS-Discovery poza granicami sieci lokalnej, musisz włączyć tryb odnajdywania zarządzanego. Program WCF 4 zapewnia również obsługę tworzenia niezbędnych składników odnajdywania zarządzanego.

Odnajdywanie usługi zarządzanej

Implementowanie trybu odnajdywania zarządzanego jest nieco bardziej zaangażowane niż tryb ad hoc, ponieważ wymaga zaimplementowania usługi serwera proxy odnajdywania. Usługa serwera proxy odnajdywania jest składnikiem, który będzie śledzić wszystkie dostępne punkty końcowe usługi. W tym przykładzie używamy funkcji anonsu do aktualizowania serwera proxy odnajdywania. Istnieje wiele innych sposobów zapewnienia serwera proxy odnajdywania z odpowiednimi informacjami dotyczącymi odnajdywania, na przykład można połączyć istniejącą bazę danych punktów końcowych i przechwycić dane z tego miejsca. Jak zaimplementować usługę serwera proxy odnajdywania?

Program WCF 4 zawiera klasę bazową o nazwie DiscoveryProxy, z której można korzystać, aby zaimplementować usługę serwera proxy odnajdywania. Rysunek 12 przedstawia początek implementacji niestandardowej usługi serwera proxy odnajdywania. Przykłady zestawu .NET 4 SDK zawierają kompletną przykładową implementację dla Dokumentacji. Po zakończeniu implementowania usługi serwera proxy odnajdywania należy go hostować gdzieś.

Rysunek 12. Implementowanie niestandardowej usługi serwera proxy odnajdywania

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,

    ConcurrencyMode = ConcurrencyMode.Multiple)]

public class MyDiscoveryProxy : DiscoveryProxyBase

{

    Repozytorium do przechowywania elementu EndpointDiscoveryMetadata.

    Zamiast tego można użyć bazy danych lub pliku prostego.

    Słownik<EndpointAddress, EndpointDiscoveryMetadata> onlineServices;

    public MyDiscoveryProxy()

    {

        this.onlineServices =

            new Dictionary<EndpointAddress, EndpointDiscoveryMetadata>();

    }

    OnBeginOnlineAnnouncement jest wywoływany po odebraniu komunikatu hello przez serwer proxy

    chronione zastąpienie IAsyncResult OnBeginOnlineAnnouncement(

        DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, wywołanie zwrotne AsyncCallback, stan obiektu)

    {

        ten. AddOnlineService(endpointDiscoveryMetadata);

        zwróć nowy element OnOnlineAnnouncementAsyncResult(wywołanie zwrotne, stan);

    }

    chronione zastąpienie void OnEndOnlineAnnouncement(wynik IAsyncResult)

    {

        OnOnlineAnnouncementAsyncResult.End(result);

    }

    OnBeginOfflineAnnouncement jest wywoływany, gdy komunikat Bye jest odbierany przez serwer proxy

    chronione zastąpienie IAsyncResult OnBeginOfflineAnnouncement(

        DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, wywołanie zwrotne AsyncCallback, stan obiektu)

    {

        ten. RemoveOnlineService(endpointDiscoveryMetadata);

        zwróć nowy element OnOfflineAnnouncementAsyncResult(wywołanie zwrotne, stan);

    }

    chronione zastąpienie void OnEndOfflineAnnouncement(wynik IAsyncResult)

    {

        OnOfflineAnnouncementAsyncResult.End(result);

    }

    Funkcja OnBeginFind jest wywoływana, gdy komunikat o żądaniu sondy jest odbierany przez serwer proxy

    chronione zastąpienie IAsyncResult OnBeginFind(

        FindRequestContext findRequestContext, wywołanie zwrotne AsyncCallback, stan obiektu)

    {

        ten. MatchFromOnlineService(findRequestContext);

        zwróć nowy element OnFindAsyncResult(wywołanie zwrotne, stan);

    }

    chronione zastąpienie void OnEndFind(wynik IAsyncResult)

    {

        OnFindAsyncResult.End(result);

    }

    ...

W tym przykładzie po prostu będę hostować usługę MyDiscoveryProxy w aplikacji konsolowej.  Skonfiguruję hosta z dwoma punktami końcowymi: punktem końcowym odnajdywania i punktem końcowym anonsu. W poniższym przykładzie pokazano, jak prawidłowo hostować usługę MyDiscoveryProxy z obydwoma tymi punktami końcowymi:

class Program

{

    public static void Main()

    {

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

        Ogłoszenie identyfikatora URIEndpointAddress =

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

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

        Odnajdywanie punktów odnajdywania Punktu końcowego = nowe odnajdywanieEndpoint(

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

        discoveryEndpoint.IsSystemEndpoint = false;

        AnonsEndpoint anonsEndpoint = nowy anonsEndpoint(

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

        proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);

        proxyServiceHost.AddServiceEndpoint(announcementEndpoint);

        proxyServiceHost.Open();

        Console.WriteLine("Usługa serwera proxy została uruchomiona".");

        Console.WriteLine();

        Console.WriteLine("Naciśnij <ENTER>, aby zakończyć działanie usługi.");

        Console.WriteLine();

        Console.ReadLine();

        proxyServiceHost.Close();

    }

}

Po skonfigurowaniu i uruchomieniu usługi serwera proxy odnajdywania możesz skonfigurować usługi, aby ogłaszać się bezpośrednio w usłudze serwera proxy odnajdywania. Podobnie można skonfigurować aplikacje klienckie w celu bezpośredniego sondowania usługi serwera proxy odnajdywania (nie ma więcej komunikatów multiemisji).

Usługę można skonfigurować tak, aby ogłaszała się bezpośrednio w usłudze serwera proxy odnajdywania, określając adres anonsu serwera proxy odnajdywania podczas tworzenia punktu anonsowania w aplikacji hosta usługi. W poniższym przykładzie pokazano, jak to zrobić:

...

Identyfikator URI baseAddress = nowy identyfikator 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), nowy ciąg NetTcpBinding(). Puste);

Tworzenie punktu końcowego anonsu wskazującego usługę hostowanego serwera proxy

AnonsEndpoint anonsEndpoint = nowy anonsEndpoint(

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

ServiceDiscoveryBehavior serviceDiscoveryBehavior = new ServiceDiscoveryBehavior();

serviceDiscoveryBehavior.AnnouncementEndpoints.Add(announcementEndpoint);

serviceHost.Description.Behaviors.Add(serviceDiscoveryBehavior);

serviceHost.Open();

...

Następnie można skonfigurować aplikacje klienckie tak, aby komunikowały się bezpośrednio z usługą serwera proxy odnajdywania, określając adres sondy serwera proxy odnajdywania podczas tworzenia punktu odnajdywania w aplikacji klienckiej. Poniższy przykład ilustruje jeden ze sposobów, aby to zrobić:

...

Utwórz punkt końcowy odnajdywania wskazujący usługę serwera proxy.

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

Odnajdywanie punktów odnajdywania Punktu końcowego = nowe odnajdywanieEndpoint(

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

Tworzenie elementu DiscoveryClient przy użyciu utworzonego wcześniej odnajdywaniaEndpoint

DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint);

Znajdowanie punktów końcowych ICalculatorService

FindResponse findResponse = discoveryClient.Find(

    new FindCriteria(typeof(ICalculatorService)));

...

Teraz omówimy kompletny przykład. Najpierw uruchomię aplikację serwera proxy odnajdywania, aby usługa serwera proxy odnajdywania jest dostępna do użycia. Następnie uruchomię wystąpienie aplikacji hosta usługi, które ogłosi się serwerem proxy odnajdywania. Gdy tak się stanie, zobaczymy komunikat wydrukowany w oknie konsoli aplikacji serwera proxy odnajdywania (zobacz Rysunek 13). To pokazuje, że usługa ogłosiła się pomyślnie na serwerze proxy odnajdywania, a serwer proxy odnajdywania zapisał informacje o nowym punkcie końcowym usługi "online". Teraz, jeśli uruchomimy kod klienta pokazany powyżej, będzie sondować serwer proxy odnajdywania bezpośrednio i pobierać adres punktu końcowego aktualnie uruchomionej usługi docelowej.

Rysunek 13. Dane wyjściowe z usługi serwera proxy odnajdywania w czasie wykonywania

Piękno odnajdywania usługi zarządzanej polega na tym, że działa przez granice sieci (oparte na tradycyjnych wywołaniach usług) i zmniejsza potrzebę obsługi komunikatów multiemisji w rozwiązaniu odnajdywania. Ponadto, ponieważ klienci przechodzą przez serwer proxy odnajdywania, aby szukać usług, same usługi nie muszą być uruchomione przez cały czas, aby można je było odnaleźć.

Zaawansowane użycie serwera proxy odnajdywania

Model programowania WCF zapewnia dużą elastyczność podczas implementowania serwera proxy odnajdywania. Odbieranie anonsów to jeden ze sposobów wypełniania listy usług; jednak nie jest to jedyna metoda. Jeśli na przykład środowisko zawiera już repozytorium usług, można łatwo skompilować fasadę serwera proxy odnajdywania na tym magazynie, aby umożliwić odnajdywanie repozytorium w czasie wykonywania.

Serwer proxy odnajdywania można skonfigurować w trybie ad hoc lub w trybie zarządzania. Podczas pracy w trybie zarządzanym klienci komunikują się z serwerem proxy bezpośrednio w sposób emisji pojedynczej przy użyciu anonsów, sond i rozpoznawania. Serwer proxy przesyła również odpowiedź w sposób emisji pojedynczej z powrotem do nadawcy.

Jeśli działa w trybie ad hoc serwer proxy może nasłuchiwać komunikatów odnajdywania multiemisji i odpowiadać bezpośrednio do nadawcy. W tym trybie ad hoc serwer proxy można również skonfigurować do pomijania komunikatów multiemisji. Oznacza to, że jeśli serwer proxy odbiera komunikat multiemisji, informuje nadawcę o swojej obecności i informuje nadawcę o kierowaniu dalszych zapytań na serwerze proxy, unikając w ten sposób dalszych komunikatów multiemisji.

Aby uzyskać więcej informacji na temat tych zaawansowanych scenariuszy odnajdywania, zobacz WS-Discovery Primer w witrynie http://www.oasis-open.org/committees/download.php/32184/WS-D-primer-wd-04.docx.

Usługa routingu

W niektórych środowiskach zorientowanych na usługi często warto korzystać ze scentralizowanych usług "routingu", które działają jako brokerzy lub bramy do rzeczywistych usług biznesowych rozproszonych wokół organizacji. To oddzielenie użytkowników od rzeczywistych usług biznesowych i umożliwia wykonywanie różnych typów przetwarzania pośredniego w węźle routingu.

Na przykład niektóre środowiska używają routingu do implementowania scentralizowanej granicy zabezpieczeń, przez którą muszą przechodzić wszystkie komunikaty przychodzące. Niektóre używają technik routingu opartego na zawartości, aby określić, która usługa docelowa ma być używana na podstawie zawartości określonego komunikatu przychodzącego. Inni używają routingu do implementowania mostkowania protokołu, dzięki czemu konsumenci mogą używać jednego zestawu protokołów do komunikacji, podczas gdy router używa innego zestawu protokołów do komunikowania się z usługą docelową. Nie rzadko zdarza się również używać routingu dla różnych technik równoważenia obciążenia, a nawet obsługi wersji usług.

Niezależnie od przyczyny, wzorzec "routingu pośredniego" jest typowym wymaganiem podczas tworzenia obecnie rozwiązań SOA na dużą skalę. W programie WCF 3.x nie było oficjalnej obsługi routingu. Mimo że platforma dostarczyła niezbędne interfejsy API do zaimplementowania własnych usług routingu, wiele pracy nad tym trzeba było wykonać prawidłowo. W magazynie MSDN Magazine opublikowano kilka artykułów pokazujących, jak to zrobić.

Ponieważ routing jest takim typowym wymaganiem w dzisiejszych czasach, usługa WCF 4 jest teraz dostarczana z oficjalną "usługą routingu" w ramach, którą można po prostu hostować i konfigurować we własnych rozwiązaniach.

Opis usługi RoutingService

Program WCF 4 zawiera nową klasę o nazwie RoutingService, która zapewnia ogólną implementację routingu WCF do użycia w aplikacjach. Usługa RoutingService może obsługiwać routing komunikatów za pośrednictwem dowolnego protokołu obsługiwanego przez usługę WCF przy użyciu różnych wzorców obsługi komunikatów, takich jak jednokierunkowa, żądanie-odpowiedź i dwukierunkowa obsługa komunikatów. Poniżej przedstawiono definicję klasy RoutingService:

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any,

    InstanceContextMode = InstanceContextMode.PerSession,

    UseSynchronizationContext = false, ValidateMustUnderstand = false),

 AspNetCompatibilityRequirements(RequirementsMode =

    AspNetCompatibilityRequirementsMode.Allowed)]

public sealed class RoutingService : // contracts zezwalają na różne wzorce komunikacji

    ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter,

    IDuplexSessionRouter, IDisposable

{

    ... // implementacja pominięta

}

Jak widać, klasa RoutingService pochodzi z wielu kontraktów usług w celu obsługi wielu wzorców obsługi komunikatów. Każdy kontrakt usługi zapewnia obsługę innego wzorca obsługi komunikatów, w tym obsługę komunikacji opartej na sesji, jeśli jest to konieczne.

Cała usługa RoutingService służy do odbierania przychodzących komunikatów od użytkowników i "kierowania" ich do odpowiedniej usługi podrzędnej. RouterService określa, która usługa docelowa ma być używana przez ocenę każdego przychodzącego komunikatu względem zestawu filtrów komunikatów. W związku z tym jako deweloper kontrolujesz zachowanie routingu, definiując filtry komunikatów, zazwyczaj w pliku konfiguracji. Usługi docelowe mogą znajdować się na tej samej maszynie co RouterService, ale nie muszą — mogą być one również dystrybuowane przez sieć i mogą wymagać różnych protokołów.

Hostowanie usługi RoutingService

Usługę RoutingService można hostować w aplikacji, tak jak w przypadku dowolnej innej usługi WCF. Wystarczy utworzyć wystąpienie serviceHost i określić wartość RoutingService dla typu usługi. Po wywołaniu polecenia Otwórz w wystąpieniu serviceHost usługa RoutingService będzie gotowa do "kierowania" komunikatów, jak pokazano poniżej:

przy użyciu systemu;

przy użyciu elementu System.ServiceModel;

przy użyciu elementu System.ServiceModel.Routing;

public static void Main()

{

    Utwórz element ServiceHost dla typu RoutingService.

    using (ServiceHost serviceHostHost =

        new ServiceHost(typeof(RoutingService)))

    {

        próbować

        {

            serviceHost.Open();

            Console.WriteLine("Usługa routingu jest teraz uruchomiona".");

            Console.WriteLine("Naciśnij <ENTER>, aby przerwać router".");

            Dostęp do usługi można teraz uzyskać.

            Console.ReadLine();

            serviceHost.Close();

        }

        catch (CommunicationException)

        {

            serviceHost.Abort();

        }

    }

}

Należy również skonfigurować usługę RoutingService tak jak dowolną inną usługę i w tym miejscu definiuje się filtry routingu. Najpierw należy skonfigurować go przy użyciu co najmniej jednego punktu końcowego. Podczas definiowania punktu końcowego routingu należy wybrać powiązanie WCF i jeden z kontraktów usługi routingu zaimplementowanych przez usługę RoutingService pokazaną powyżej (np. ISimplexDatagramRouter, IRequestReplyRouter itp.). Możesz uwidocznić więcej niż jeden punkt końcowy w usłudze RoutingService, jeśli chcesz obsługiwać wiele wzorców obsługi komunikatów lub powiązań WCF.

W poniższym przykładzie pokazano, jak skonfigurować usługę RoutingService z czterema punktami końcowymi routingu: dwa, które używają metody BasicHttpBinding (jednokierunkowa i żądanie-odpowiedź) oraz dwóch, które używają metody WSHttpBinding (jednokierunkowej i żądania-odpowiedź). Zwróć uwagę, że tak samo jak w przypadku konfigurowania dowolnej innej usługi WCF:

<konfiguracji>

  <system.serviceModel>

    > usług <

      <!--ROUTING SERVICE —>

      <zachowanie usługiConfiguration="routingData"

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

        > hosta <

          <baseAddresses>

            <dodać element baseAddress="https://localhost:8000/routingservice/router"/>

          </baseAddresses>

        </host>

        <!--

          Definiowanie i konfigurowanie punktu końcowego, na który ma nasłuchiwać router, oraz

          Kontrakt, którego chcemy użyć. Kontrakty dostarczane przez router są następujące:

          ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter i

          IDuplexSessionRouter.

         -->

        <adres punktu końcowego="oneway-basic"

                  binding="basicHttpBinding"

                  name="onewayEndpointBasic"

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

        <endpoint address="oneway-ws"

                  binding="wsHttpBinding"

                  name="onewayEndpointWS"

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

        <adres punktu końcowego="twoway-basic"

                  binding="basicHttpBinding"

                  name="reqReplyEndpointBasic"

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

        <adres punktu końcowego="twoway-ws"

                  binding="wsHttpBinding"

                  name="reqReplyEndpointWS"

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

      </service>

    </services>

    ...

Interfejsy ISimplexDatagramRouter i IRequestReplyRouter definiują ogólne definicje jednokierunkowe i kontrakty usługi request-reply, które mogą być używane w połączeniu z kontraktami usług specyficznymi dla firmy. Poniżej przedstawiono sposób definiowania tych interfejsów w programie WCF:

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

    SessionMode = SessionMode.Allowed)]

publiczny interfejs ISimplexDatagramRouter

{

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

    IAsyncResult BeginProcessMessage(Komunikat, wywołanie zwrotne AsyncCallback,

        stan obiektu);

    void EndProcessMessage(wynik IAsyncResult);

}

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

    SessionMode = SessionMode.Allowed)]

publiczny interfejs IRequestReplyRouter

{

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

        ReplyAction = "*")]

    [GenericTransactionFlow(TransactionFlowOption.Allowed)]

    IAsyncResult BeginProcessRequest(Komunikat, Wywołanie zwrotne AsyncCallback,

        stan obiektu);

    Komunikat EndProcessRequest(wynik IAsyncResult);

}

Konfiguracja punktu końcowego powyżej uwidacznia punkty końcowe routingu dla użytkowników do użycia.  Aplikacje klienckie będą wybierać jeden z tych punktów końcowych do użycia w kodzie klienta i będzie kierować wszystkie wywołania usług bezpośrednio do usługi RoutingService. Gdy usługa RoutingService odbiera komunikat za pośrednictwem jednego z tych punktów końcowych, ocenia filtry komunikatów routingu, aby określić, gdzie przekazać dalej komunikat.

Konfigurowanie usługi RoutingService za pomocą filtrów komunikatów

Usługę RoutingService można skonfigurować za pomocą filtrów komunikatów za pomocą kodu lub konfiguracji (podobnie jak wszystko inne w programie WCF). Program WCF 4 udostępnia element RoutingBehavior do zarządzania filtrami komunikatów routingu. Najpierw należy włączyć element RoutingBehavior w usłudze RouterService, a następnie określić nazwę tabeli filtrów, której chcesz użyć z tym konkretnym wystąpieniem usługi RoutingService:

<konfiguracji>

  <system.serviceModel>

    ...

    <zachowania>

      <serviceBehaviors>

        <nazwa zachowania="routingData">

          <serviceMetadata httpGetEnabled="True"/>

          <!-- Zdefiniuj zachowanie routingu i określ nazwę tabeli filtru —>

          <filterTableName="filterTable1" />

        </behavior>

      </serviceBehaviors>

    </behaviors>

    ...

Jeśli przyjrzysz się poprzedniemu przykładowi, w którym skonfigurowaliśmy usługę RoutingService z punktami końcowymi, zobaczysz, że do usługi zastosowano zachowanie "routingData" za pomocą atrybutu behaviorConfiguration. Następnie należy zdefiniować tabelę filtrów o nazwie "filterTable1".

Jednak zanim będzie można zdefiniować tabelę filtrów, potrzebujemy definicji punktów końcowych dla usług docelowych, do których zamierzamy kierować. Te docelowe punkty końcowe są definiowane w ramach <klienta programu WCF> konfiguracji, ponieważ usługa RoutingService jest zasadniczo "klientem" podczas przekazywania komunikatów do usługi docelowej. W poniższym przykładzie pokazano, jak zdefiniować dwa docelowe punkty końcowe, do których możemy kierować:

<konfiguracji>

    ...

    <!-- Zdefiniuj punkty końcowe klienta, z którymi ma się komunikować router.

         Są to miejsca docelowe, do których router będzie wysyłać komunikaty. -->

    > klienta <

      <nazwa punktu końcowego="CalculatorService1"

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

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

      <nazwa punktu końcowego="CalculatorService2"

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

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

    </client>

    ...

Teraz możemy zdefiniować rzeczywistą tabelę filtrów, która określi logikę routingu w czasie wykonywania. Należy zdefiniować wpisy tabeli filtru w <filterTables> elementu. Każdy wpis w <filterTable> definiuje mapowanie między routingiem "filter" i docelowym punktem końcowym. Definiujesz "filtry", które mają być używane w filtrach <> elementu — każdy <filtr> wpis określa, jakiego typu filtru chcesz użyć wraz z danymi specyficznymi dla filtru (np. wartością akcji, wyrażeniem XPath itp.).

W poniższym przykładzie pokazano, jak skonfigurować tabelę filtrów przy użyciu pojedynczego filtru mapowanego na punkt końcowy CalculatorService1. W takim przypadku filtr "MatchAll" pasuje do wszystkich komunikatów przychodzących:

<konfiguracji>

    ...

    SEKCJA <!--ROUTING —>

    > routingu <

      <!-- Zdefiniuj filtry, które mają być używane przez router. -->

      <filtry>

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

      </filters>

      <!-- Zdefiniuj tabelę filtrów zawierającą filtr matchAll —>

      <filterTables>

        <filterTable name="filterTable1">

            <!-- Zamapuj filtr na wcześniej zdefiniowany punkt końcowy klienta.

                 Komunikaty pasujące do tego filtru zostaną wysłane do tego miejsca docelowego. -->

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

        </filterTable>

      </filterTables>

    </routing>

  </system.serviceModel>

</configuration>

Możemy sprawdzić, czy routing działa prawidłowo, uruchamiając aplikację hosta usługi routingu, aplikację hosta CalculatorService1 i klienta, który został zaprojektowany do wysyłania komunikatów do jednego z punktów końcowych routera. Po uruchomieniu klienta powinny zostać wyświetlone komunikaty docierające do aplikacji CalculatorService 1 po tym, jak są one "kierowane" przez pośrednią usługę routingu (zobacz Rysunek 14, Rysunek 15 i Rysunek 16).

Rysunek 14. Aplikacja hosta RoutingService

Rysunek 15. Klient docelowy usługi RoutingService w https://localhost:8000/routingservice/router

Rysunek 16. Usługa docelowa (CalculatorService1)

Filtry komunikatów i routing oparty na zawartości

Program WCF zawiera kilka wbudowanych klas MessageFilter, których można używać w połączeniu z filtrami komunikatów routingu w celu sprawdzenia zawartości komunikatów przychodzących.

Na przykład program WCF udostępnia filtr ActionMessageFilter, który umożliwia dopasowanie określonych wartości WS-Addressing "akcji". WCF udostępnia również element EndpointAddressMessageFilter, EndpointNameMessageFilter i PrefixEndpointAddressMessageFilter, który pozwala dopasować szczegóły określonego punktu końcowego. Jednym z najbardziej elastycznych jest XPathMessageFilter, który umożliwia ocenę wyrażeń XPath względem przychodzących komunikatów. Wszystkie te filtry umożliwiają wykonywanie routingu opartego na zawartości w rozwiązaniu.

Oprócz tych wbudowanych typów MessageFilter program WCF 4 umożliwia również zdefiniowanie niestandardowych filtrów komunikatów, co może być jednym z głównych punktów rozszerzalności dla usługi RoutingService.

Przyjrzyjmy się przykładowi wykonywania routingu opartego na zawartości na podstawie wartości akcji. Załóżmy, że chcemy kierować połowę operacji CalculatorService do calculatorService1, a druga połowa na CalculatorService2. Można to zrobić, definiując filtry dla każdej z różnych wartości akcji CalculatorService i mapując połowę z nich na każdy docelowy punkt końcowy usługi, jak pokazano poniżej:

<konfiguracji>

    ...

    SEKCJA <!--ROUTING —>

    > routingu <

      <!-- Zdefiniuj filtry, które mają być używane przez router. -->

     <filtry>

        <nazwa filtru="addFilter" filterType="Action"

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

         <nazwa filtru="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"/>

      </filters>

      <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>

    </routing>

  </system.serviceModel>

</configuration>

Teraz, gdy uruchomimy rozwiązanie i wykonamy klienta, który wywołuje wszystkie cztery operacje, zobaczymy połowę operacji wyświetlanych w każdym oknie konsoli usługi (zobacz Rysunek 17 i Rysunek 18).

Rysunek 17. Dane wyjściowe aplikacji CalculatorService1

Rysunek 18. Dane wyjściowe aplikacji CalculatorService2

Filtr XPathMessageFilter zapewnia jeszcze większą elastyczność, ponieważ można podać różne wyrażenia XPath do oceny względem przychodzących komunikatów. Wyrażenia XPath mogą oceniać dowolną część komunikatu przychodzącego, w tym nagłówki PROTOKOŁU SOAP lub treść protokołu SOAP. Zapewnia to dużą elastyczność podczas tworzenia filtrów komunikatów opartych na zawartości. Aby zrozumieć mechanikę biblioteki XPathMessageFilter, poniżej przedstawiono sposób ponownego pisania ostatniego przykładu przy użyciu wyrażeń XPath:

<konfiguracji>

    ...

    SEKCJA <!--ROUTING —>

    > routingu <

      <!-- Zdefiniuj filtry, które mają być używane przez router. -->

     <filtry>

        <nazwa filtru="addFilter" filterType="XPath"

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

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

        <nazwa filtru="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'"/>

      </filters>

      <przestrzeni nazwTable>

        <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>

    </routing>

  </system.serviceModel>

</configuration>

Zwróć uwagę, że atrybut filterData zawiera wyrażenie XPath, które będzie oceniane względem komunikatu przychodzącego (wyrażenia po prostu sprawdzają wartości akcji w tym przykładzie). Zwróć uwagę, że zdefiniowano również zestaw powiązań prefiksu przestrzeni nazw przy użyciu elementu <namespaceTable>. Jest to konieczne, jeśli chcesz używać prefiksów przestrzeni nazw w wyrażeniach XPath, takich jak powyżej. Ponowne uruchomienie rozwiązania przy użyciu tej konfiguracji powoduje wygenerowanie tych samych wyników co poprzednio (zobacz Rysunek 17 i Rysunek 18).

Należy użyć tej techniki filtrowania XPath za każdym razem, gdy musisz kierować komunikaty na podstawie niestandardowych nagłówków protokołu SOAP lub na podstawie zawartości znalezionej w treści komunikatu PROTOKOŁU SOAP.

Mostkowanie protokołu

W poprzednich przykładach używaliśmy tego samego powiązania WCF (WSHttpBinding) do komunikacji między klientem a routerem oraz między routerem a usługami docelowymi. Usługa RoutingService umożliwia mostkowanie komunikacji między większością powiązań WCF. Na przykład można skonfigurować router, aby klienci komunikowali się z nim za pośrednictwem usługi WSHttpBinding, ale następnie router komunikuje się z podrzędnymi usługami docelowymi przy użyciu narzędzia NetTcpBinding lub NetNamedPipeBinding.

Zobaczmy, jak skonfigurować usługę RoutingService do obsługi tego scenariusza. Pozostawimy konfigurację punktu końcowego RoutingService tak samo jak powyżej, co umożliwia konsumentom komunikowanie się z usługą RoutingService za pośrednictwem warstwy BasicHttpBinding lub WSHttpBinding. Teraz zmienimy definicje punktów końcowych klienta dla usług docelowych tak, aby korzystały z parametrów NetTcpBinding i NetNamedPipeBinding, jak pokazano poniżej:

<konfiguracji>

    ...

    <!-- Zdefiniuj punkty końcowe klienta, z którymi ma się komunikować router.

         Są to miejsca docelowe, do których router będzie wysyłać komunikaty. -->

    > klienta <

      <nazwa punktu końcowego="CalculatorService1"

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

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

      <nazwa punktu końcowego="CalculatorService2"

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

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

    </client>

    ...

Oczywiście musimy zaktualizować aplikacje CalculatorService1 i CalculatorService2, aby obsługiwały odpowiednio zgodne punkty końcowe NetTcpBinding i NetNamedPipeBinding. Dzięki tej konfiguracji użytkownicy mogą komunikować się z usługą RoutingService przy użyciu metody BasicHttpBinding/WSHttpBinding, a router komunikuje się z usługami docelowymi przy użyciu polecenia NetTcpBinding lub NetNamedPipeBinding w zależności od usługi, do której jest kierowany komunikat.

Błąd podczas przekazywania i odporności na uszkodzenia

Usługa RoutingService udostępnia również wbudowany mechanizm do obsługi błędów komunikacji w czasie wykonywania i obsługi podstawowego poziomu odporności na uszkodzenia. Podczas definiowania tabeli filtrów można zdefiniować różne listy alternatywnych punktów końcowych, które będą używane przez usługę RoutingService, jeśli komunikacja z początkowym docelowym punktem końcowym powoduje wystąpienie błędu. Zasadniczo umożliwia to wyświetlanie list punktów końcowych "kopii zapasowej".

Poniższy przykład ilustruje sposób definiowania listy punktów końcowych kopii zapasowej w <backupLists> element, który możemy skojarzyć z naszymi wpisami tabeli filtru:

<konfiguracji>

    ...

    SEKCJA <!--ROUTING —>

    > routingu <

      ... <!-- Zdefiniuj filtry, które mają być używane przez router. -->

      <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>

    </routing>

  </system.serviceModel>

</configuration>

Zwróć uwagę, że w tym przykładzie skonfigurowano wszystkie wpisy tabeli filtru do przekazywania do elementu CalculatorService1, ponieważ funkcja CalculatorService2 jest teraz naszym punktem końcowym "kopii zapasowej", który będzie używany tylko wtedy, gdy funkcja CalculatorService1 spowoduje wystąpienie wyjątku TimeoutException, wyjątek CommunicationException lub typ wyjątku pochodnego. Jeśli na przykład ponownie uruchomię rozwiązanie i zamknę aplikację CalculatorService1, a następnie uruchomimy program kliencki, zobaczymy wszystkie komunikaty w aplikacji CalculatorService2. Należy pamiętać, że po raz kolejny cała ta konfiguracja routingu może być wykonywana dynamicznie w kodzie aplikacji hosta.

Zachowanie routingu multiemisji

Usługa RoutingService obsługuje również automatyczne kierowanie określonego komunikatu przychodzącego do wielu miejsc docelowych w sposób "multiemisji". Gdy komunikat przychodzący pasuje do wielu filtrów znalezionych w skonfigurowanej tabeli filtrów, usługa RoutingService automatycznie kieruje komunikat do każdego z docelowych punktów końcowych skojarzonych z filtrami "dopasowanymi".

W poniższym przykładzie przedstawiono dwa wpisy routingu skonfigurowane z tym samym filtrem wieloznacznym, który odpowiada wszystkim komunikatom przychodzącym:

<konfiguracji>

    ...

    SEKCJA <!--ROUTING —>

    > routingu <

      <!-- Zdefiniuj filtry, które mają być używane przez router. -->

     <filtry>

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

      </filters>

      <filterTables>

        <filterTable name="filterTable1">

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

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

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

        </filterTable>

      </filterTables>

    </routing>

  </system.serviceModel>

</configuration>

Po skonfigurowaniu tej konfiguracji każdy przychodzący komunikat PROTOKOŁU SOAP będzie automatycznie kierowany do wszystkich docelowych punktów końcowych, niezależnie od tego, co można znaleźć w komunikatach.

To zachowanie multiemisji komponuje się z funkcjami mostkowania protokołu i obsługi błędów omówionymi w poprzednich sekcjach. Jedynym problemem jest, że multiemisji działa tylko w przypadku komunikacji jednokierunkowej lub dwukierunkowej, ale nie komunikacji żądań odpowiedzi, ponieważ podstawowy system musi zachować stosunek jeden do jednego między żądaniami wychodzącymi i przychodzącymi odpowiedziami.

Ulepszona obsługa rest

Program WCF 4 zawiera kilka nowych funkcji, które przydają się podczas kompilowania usług RESTful przy użyciu usługi WCF.  Ten zestaw funkcji jest teraz nazywany usługami WCF WebHttp Services. Obejmują one obsługę automatycznej strony pomocy, która opisuje usługę RESTful dla użytkowników, uproszczone buforowanie HTTP, wybór formatu komunikatów, wyjątki przyjazne dla rest, ASP.NET integrację routingu, niektóre nowe szablony projektów programu Visual Studio i inne. Nie będziemy mieć miejsca na pokrycie wszystkich tych funkcji tutaj szczegółowo, ale dam ci krótkie wprowadzenie do kilku moich ulubionych poniżej, wraz z linkami do dodatkowych informacji na temat reszty.

Wiele z tych funkcji zostało po raz pierwszy wprowadzonych przez zestaw startowy REST WCF w zeszłym roku i teraz przekształca je w oficjalną strukturę. W przyszłości może pojawić się więcej funkcji zestawu startowego REST WCF.

Strona automatycznej pomocy

W przypadku korzystania z klasy WebServiceHost w programie WCF 4 usługi RESTful będą automatycznie korzystać z zalet funkcji automatycznej strony pomocy. Jest to bardzo potrzebne dodanie w przypadku korzystania z interfejsu REST, biorąc pod uwagę brak metadanych WSDL i generowania kodu po stronie klienta — znacznie ułatwia konsumentom ustalenie, jak rozpocząć pracę z usługą — dlatego zazwyczaj dobrym pomysłem jest włączenie tej nowej funkcji.

Gdy używasz klasy WebServiceHost do hostowania usługi, automatycznie konfiguruje usługę za pomocą elementu WebHttpBehavior i dodaje domyślny punkt końcowy HTTP skonfigurowany za pomocą elementu WebHttpBinding (pod podstawowym adresem HTTP). Począwszy od programu WCF 4, klasa WebHttpBehavior jest dostarczana z właściwością HelpEnabled, która kontroluje, czy nowa strona pomocy jest włączona na hoście. W poniższym przykładzie konfiguracji pokazano, jak włączyć funkcję automatycznej strony pomocy dla określonego punktu końcowego REST:

<konfiguracji>

  <system.serviceModel>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

    <zachowania>

      <endpointBehaviors>

        <nazwa zachowania="HelpBehavior">

          <webHttp helpEnabled="true" />

        </behavior>

      </endpointBehaviors>

    </behaviors>

    > usług <

      <nazwa usługi="CounterResource">

        <zachowanie punktu końcowegoConfiguration="HelpBehavior"

                  binding="webHttpBinding"

                  contract="CounterResource" />

      </service>

    </services>

  </system.serviceModel>

</configuration>

Stronę pomocy można wyświetlić, przechodząc do adresu podstawowego usługi z dołączonym do końca adresu URL (patrz Rysunek 19).

Rysunek 19: Strona automatycznej pomocy dotyczącej usług RESTFul

Strona pomocy zawiera czytelny dla człowieka opis każdej operacji z adnotacjami [WebGet] lub [WebInvoke], a dla każdego z nich opisuje szablon identyfikatora URI, obsługiwaną operację HTTP i obsługiwane formaty komunikatów, w zasadzie wszystko, co użytkownik musi wiedzieć (zobacz Rysunek 20). Można również podać bardziej przyjazny dla człowieka opis, stosując atrybut [Description] do każdej operacji.

Dla każdego żądania/odpowiedzi strona pomocy zawiera również schemat XML i odpowiadające mu przykładowe wystąpienie XML, którego użytkownicy mogą używać do integracji z usługą. Użytkownicy mogą używać schematu do generowania odpowiednich typów możliwych do serializacji po stronie klienta lub po prostu sprawdzić przykładowy dokument XML, aby ręcznie określić sposób pisania odpowiedniego kodu przetwarzania XML. Oba podejścia są przydatne.

Rysunek 20. Strona pomocy automatycznej dla określonej operacji

Ta nowa funkcja strony pomocy automatycznie ułatwia odnajdywanie usług RESTful, co ostatecznie ułatwia innym użytkownikom korzystanie. Użytkownicy mogą odnaleźć projekt identyfikatora URI usługi, obsługiwane operacje HTTP i formaty żądań/odpowiedzi, a opis będzie zawsze synchronizowany z kodem WCF — podobnie jak w przypadku pracy z usługami sieci Web ASP.NET.

Obsługa buforowania HTTP

Jedną z głównych zalet funkcji REST jest buforowanie HTTP. Aby jednak zrealizować tę korzyść, musisz skorzystać z różnych nagłówków buforowania HTTP w komunikatach żądania i odpowiedzi. Można to zrobić w ramach operacji usługi WCF, ręcznie korzystając z nagłówków żądania/odpowiedzi za pośrednictwem wystąpienia WebOperationContext, ale nie jest to proste do wykonania prawidłowo.

W związku z tym program WCF 4 jest wyposażony w prostszy model kontroli buforowania za pomocą atrybutu [AspNetCacheProfile], który można deklaratywnie zastosować do operacji GET. Ten atrybut umożliwia określenie nazwy profilu buforowania ASP.NET dla każdej operacji i w tle znajduje się inspektor buforowania (CachingParameterInspector), który zajmuje się obsługą wszystkich podstawowych szczegółów buforowania HTTP.

Implementacja [AspNetCacheProfile] opiera się na standardowym mechanizmie buforowania danych wyjściowych ASP.NET. W poniższym przykładzie pokazano, jak zastosować atrybut [AspNetCacheProfile] do operacji [WebGet]:

...

[AspNetCacheProfile("CacheFor60Seconds")]

[WebGet(UriTemplate=XmlItemTemplate)]

[OperationContract]

publiczny licznik GetItemInXml()

{

    return HandleGet();

}

...

W tym miejscu należy zdefiniować profil buforowania danych wyjściowych ASP.NET o nazwie "CacheFor60Seconds" w pliku web.config. W poniższych web.config pokazano, jak można to zrobić:

<konfiguracji>

  <system.web>

    <buforowanie>

      <outputCacheSettings>

        <outputCacheProfiles>

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

        </outputCacheProfiles>

      </outputCacheSettings>

    </buforowanie>

  </system.web>

  <system.serviceModel>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

  </system.serviceModel>

</configuration>

Zwróć uwagę, że profil buforowania ASP.NET jest ustawiony na buforowanie danych wyjściowych przez 60 sekund i jest skonfigurowany tak, aby zmieniała pamięć podręczną według zmiennej ciągu zapytania "format". Jest to ważne, ponieważ usługa, o której mowa, obsługuje zarówno format XML, jak i JSON, które można kontrolować za pomocą zmiennej formatu (np. "?format=json"). Usługa musi buforować odpowiedzi XML i JSON niezależnie od siebie.

Ten plik konfiguracji ilustruje również sposób włączania trybu zgodności ASP.NET, który jest wymagany, gdy chcesz korzystać z różnych funkcji ASP.NET, takich jak buforowanie danych wyjściowych.

Atrybut [AspNetCacheProfile] znacznie ułatwia korzystanie z buforowania HTTP bez konieczności bezpośredniej pracy z nagłówkami buforowania HTTP. Podstawowe zachowanie programu WCF zajmuje się wstrzykiwaniem kontrolki pamięci podręcznej HTTP, daty, wygasania i różnicowania nagłówków HTTP w odpowiedzi, które klienci mogą również wykorzystać w celu określenia odpowiednich semantyki buforowania w przyszłych rundach.

Wybór formatu komunikatu

Jeśli spojrzysz wstecz na Rysunek 19, zauważysz, że usługa CounterResource obsługuje formaty XML i JSON dla operacji GET, POST i PUT. Jest to możliwe od czasu, gdy WCF 3.5 za pośrednictwem właściwości RequestFormat i ResponseFormat odnaleziono atrybuty [WebGet] i [WebInvoke].

Udało mi się to w usłudze CounterResource, definiując oddzielny kontrakt operacji dla każdej wersji — jedną dla wersji XML, a drugą dla wersji JSON — jak pokazano poniżej:

...

[WebGet(UriTemplate="")]

[OperationContract]

publiczny licznik GetItemInXml()

{

    return HandleGet();

}

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

[OperationContract]

publiczny licznik GetItemInJson()

{

    return HandleGet();

}

...

Niestety oznacza to, że w przypadku każdej operacji logicznej potrzebne są dwa kontrakty operacji, jeśli chcesz obsługiwać formaty XML i JSON. W przypadku usługi CounterResource wymagane było posiadanie sześciu kontraktów operacji w celu obsługi zarówno xml, jak i JSON dla operacji GET, POST i PUT.

Program WCF 4 znacznie ułatwia obsługę tego scenariusza, zapewniając obsługę automatycznego zaznaczenia formatu na podstawie nagłówków "Accept" protokołu HTTP, co jest lepszym sposobem jego wykonania. Wyjaśnijmy, jak to działa.

Najpierw potrzebujemy tylko jednego kontraktu operacji dla każdej operacji logicznej:

[WebGet(UriTemplate="")]

[OperationContract]

publiczny licznik GetItem()

{

    return HandleGet();

}

Następnie wybór automatycznego formatu w standardowej aplikacji webHttpEndpoint, jak pokazano poniżej:

<konfiguracji>

  <system.serviceModel>

    <standardEndpoints>

      <webHttpEndpoint>

        <!-- standardowy punkt końcowy jest używany do automatycznego tworzenia internetowego punktu końcowego. -->

        <standardEndpoint name="" helpEnabled="true"

            automaticFormatSelectionEnabled="true"/>

      </webHttpEndpoint>

    </standardEndpoints>

  </system.serviceModel>

</configuration>

Dzięki temu usługa może teraz obsługiwać i zwracać komunikaty XML lub JSON. Określa format, który ma być używany, najpierw sprawdzając nagłówek HTTP Accept znajdujący się w komunikacie żądania. Jeśli to nie zadziała, będzie używać tego samego formatu komunikatu co komunikat żądania, zakładając, że jest to kod XML lub JSON, w przeciwnym razie użyje domyślnego formatu dla określonej operacji.

Teraz do klienta należy określenie, który format ma być używany za pośrednictwem typu zawartości HTTP i akceptowania nagłówków. Nagłówek Content-Type określa format w komunikacie żądania, a nagłówek Accept wskazuje format klienta "akceptuje" z powrotem z usługi. Jeśli na przykład klient chce odebrać kod JSON z usługi, powinien określić następujący nagłówek HTTP Accept w żądaniu:

Akceptuj: application/json

Jest to łatwe w każdym modelu programowania klienta HTTP i jest również łatwe w użyciu narzędzi, takich jak Fiddler. Rysunek 21 pokazuje, jak za pomocą programu Fiddler odzyskać kod JSON z naszej nowej i ulepszonej usługi.

Rysunek 21. Pobieranie JSON przy użyciu nagłówka Http Accept

WCF 4 udostępnia również nowe interfejsy API, które ułatwiają jawne określanie formatu komunikatu w czasie wykonywania. Poniższy kod pokazuje, jak możemy rozszerzyć operację GetItem, pisząc kod, który najpierw szuka parametru ciągu zapytania "format" i jawnie ustawia format odpowiedzi odpowiednio. Jeśli nie znajdzie parametru "format", będzie po prostu polegać na nagłówku Accept, tak jak wcześniej.

[WebGet(UriTemplate="")]

[OperationContract]

publiczny licznik GetItem()

{

    jeśli określono parametr ciągu zapytania w formacie,

    ustaw format odpowiedzi na to. Jeśli tak nie

    parametr ciągu zapytania istnieje, że zostanie użyty nagłówek Accept

    format ciąguQueryStringValue =

       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;

        }

        inaczej

        {

            throw new WebFaultException<ciąg>(ciąg. Format("Nieobsługiwany format "{0}"",

               formatQueryStringValue), HttpStatusCode.BadRequest);

        }

    }

    return HandleGet();

}

W końcu te nowe funkcje sprawiają, że nie trzeba już kodować typu formatu komunikatu do kontraktów operacji [WebGet] i [WebInvoke], takich jak w programie WCF 3.5.

Obsługa błędów RESTful

Ponieważ usługi RESTful nie korzystają z protokołu SOAP, nie masz już standardowego mechanizmu błędów protokołu SOAP, który umożliwia automatyczne mapowania między wyjątkami platformy .NET i komunikatami o błędach protokołu SOAP. Podczas tworzenia usług REST w programie WCF 3.5 trzeba było ręcznie skonstruować komunikat odpowiedzi HTTP za każdym razem, gdy chcesz dostosować komunikat o błędzie HTTP wysłany z powrotem do klienta.

W programie WCF 4 znajdziesz nową klasę o nazwie WebFaultException<T>, która znacznie ułatwia przesyłanie "błędów internetowych" (np. błędów HTTP) z powrotem do użytkowników. Działa bardzo podobnie jak BłądException<T> w programie WCF, ale można określić kod stanu HTTP i typ szczegółów, aby uzyskać więcej szczegółów.

W poniższym przykładzie pokazano, jak zwrócić błąd HTTP 400 (nieprawidłowe żądanie), gdy użytkownik określa nieobsługiwany typ formatu — po prostu używam ciągu dla typu szczegółów:

if (!string). IsNullOrEmpty(format))

{

    if (format. 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;

    }

    inaczej

    {

        throw new WebFaultException<ciąg>(ciąg. Format("Nieobsługiwany format "{0}"",

           format), HttpStatusCode.BadRequest);

    }

}

Ta nowa funkcja sprawia, że jest o wiele bardziej naturalne, aby zwracać standardowe komunikaty o błędach HTTP, po prostu zgłaszając wyjątki, takie jak zwykle w usługach opartych na protokole SOAP.

Integrowanie programu WCF z trasami ASP.NET

Istnieje wiele podobieństw między funkcjami routingu opartymi na adresach URL znajdującymi się zarówno w programie WCF 4, jak i ASP.NET 4. Obie umożliwiają wykonywanie tych samych czynności — zasadniczo mapują szablony adresów URL na metody w klasach. Istnieje jednak jedna znacząca różnica między dwoma modelami.

Podejście WCF 4 wiąże projekt szablonu adresu URL z pojedynczą klasą za pomocą atrybutów [WebGet] i [WebInvoke] zastosowanych do definicji klasy podczas programowania. Wraz ze wzrostem i rozwojem usługi w miarę upływu czasu może to prowadzić do dużego monolitycznego projektu, który nie może być uwzględniany w mniejszych fragmentach. Z drugiej strony podejście ASP.NET 4 rozdziela logikę routingu z definicji klasy docelowej, umożliwiając mapowanie tras usługi między wieloma definicjami klas w razie potrzeby.

Program WCF 4 umożliwia teraz integrację aparatu routingu ASP.NET z usługami WCF 4, dzięki czemu można korzystać z modelu routingu ASP.NET na podstawie usług WCF.

Można to zrobić w metodzie Global.asax RegisterRoutes, korzystając z nowej klasy usługi ServiceRoute, która umożliwia mapowanie trasy ASP.NET do klasy usługi WCF:

private void RegisterRoutes()

{

   Fabryka WebServiceHostFactory = nowa webServiceHostFactory();

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

      typeof(BookmarkService)));

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

      typeof(UserService)));

}

Wywoływanie metody RouteTable.Routes.Add dwa razy w celu dodania nowych tras dla dwóch różnych klas usług WCF. Pierwsza trasa mapuje ciąg "/Zakładki" na klasę BookmarkService, podczas gdy druga trasa mapuje ciąg "/Users" na klasę UserService. Zwróć uwagę, że obie trasy są skonfigurowane do używania elementu WebServiceHostFactory.

Teraz, gdy używamy atrybutów [WebGet] i [WebInvoke] w definicjach klas usługi WCF, użyjemy ścieżek względnych — i będą one względne względem trasy ASP.NET określonej tutaj.

Szablony projektów REST

Jedną z schludnych funkcji programu Visual Studio 2010 jest Menedżer rozszerzeń, do którego można uzyskać dostęp z poziomu narzędzi | Menedżer rozszerzeń. Menedżer rozszerzeń umożliwia firmie Microsoft i innym firmom integrowanie nowych szablonów projektów, kontrolek i narzędzi z programem Visual Studio 2010 za pomocą prostego kliknięcia przycisku. W przypadku zespołów produktów firmy Microsoft jest to doskonałe rozwiązanie, ponieważ umożliwia dostarczanie rzeczy po RTM i nadal ich oficjalne rozszerzenia udostępniane przez firmę Microsoft.

Jeśli wyświetlisz Menedżera rozszerzeń i rozwiń węzeł "Szablony", znajdziesz węzeł podrzędny o nazwie "WCF". Kliknij pozycję "WCF" i powinny zostać wyświetlone cztery nowe szablony usługi REST WCF — po jednym dla każdej wersji platformy .NET (3.5 vs 4.0) i jeden na język (C# a VB.NET), jak pokazano na rysunku 22.

Rysunek 22. Nowe szablony projektów REST WCF w menedżerze rozszerzeń

Możesz wybrać te nowe szablony projektów i pobrać je do lokalnej instalacji programu Visual Studio 2010 i użyć ich jak dowolnego innego typu projektu. Nowy typ projektu REST znajdziesz w obszarze Visual C# | Sieć Web | Aplikacja usługi REST WCF (przy założeniu, że zainstalowano wersję języka C#).

Gdy używasz go do tworzenia nowego projektu, zauważysz, że aplikacja usługi REST WCF generuje większość nowych funkcji WCF 4 wyróżnionych w tej sekcji.

Więcej informacji

Oprócz omówionych tutaj funkcji WCF 4 jest dostarczanych z kilkoma bardziej zaawansowanymi funkcjami REST i nowymi rozszerzeniami interfejsu API WCF, które upraszczają obsługę niestandardowych formatów komunikatów (nie XML lub JSON), zwracania "widoków" opartych na szablonach przy użyciu nowej funkcji T4, implementowania obsługi warunkowego get i ETag, implementowania optymistycznej współbieżności i generowania linków wychodzących.

Aby uzyskać więcej informacji na temat wszystkich tych nowych funkcji WCF 4, w tym tych, które nie mieliśmy miejsca na pokrycie tutaj, przejdź do bloga punktu końcowego platformy .NET i znajdź wpis w temacie Introducing WCF WebHttp Services in .NET 4 (Wprowadzenie do usług WebHttp Services WCF na platformie .NET 4). Zespół przedstawił dokładną 12-częściową serię blogów, która przeprowadzi cię przez każdą nową funkcję po jednym wpisie w blogu, wraz z dużą ilością przykładowego kodu i instrukcjami krok po kroku.

Usługi przepływu pracy

Jednym z obszarów funkcji, które zwróciły największą uwagę na platformie .NET 4, było "usługi przepływu pracy". Firma Microsoft w dużym stopniu inwestuje w poprawę integracji między platformami WCF i WF w celu zapewnienia rozbudowanego i deklaratywnego modelu programowania na potrzeby tworzenia szerokiej gamy aplikacji.

Omówienie usług przepływu pracy

WF zapewnia deklaratywny model programowania, który podnosi poziom abstrakcji dla tych, którzy piszą logikę. To, co WF ostatecznie daje, to struktura do pisania własnych języków przez zdefiniowanie własnej biblioteki działań domeny biznesowej. Następnie udostępnia projektanta wizualnego do tworzenia tych działań w programach oraz środowiska uruchomieniowego, które wie, jak zarządzać wykonywaniem tych programów.

Platforma WF zapewnia szczególnie dobry model do implementowania długotrwałych aplikacji, które muszą czekać na wystąpienie różnych typów zdarzeń zewnętrznych, takich jak odbieranie komunikatu z innego systemu. Jego model trwałości umożliwia efektywne korzystanie z zasobów systemowych, utrzymując program w pamięci tylko wtedy, gdy jest on rzeczywiście uruchomiony. Gdy program oczekuje na wystąpienie zdarzenia zewnętrznego, można go utrwalić w bazie danych, zwalniając w ten sposób zasoby systemowe, z których korzysta.

Rysunek 23. Usługi przepływu pracy

To, co sprawia, że WF różni się od innych struktur programistycznych jest to, że zapewnia te funkcje, jednocześnie pozwalając programować przy użyciu sekwencyjnej logiki programowania sterowania przepływem, która jest zwykle znacznie łatwiejsza dla deweloperów czytanie i pisanie kodu do zrozumienia.

Jeśli tworzysz usługi WCF, które są długotrwałe lub mogą korzystać z niektórych innych korzyści, które właśnie opisałem, możesz zaimplementować usługi WCF przy użyciu przepływu pracy WF. Za pomocą platformy WF można koordynować logikę korzystania z innych usług zewnętrznych.

Rysunek 23 ilustruje te pojęcia.

Mimo że jest to możliwe od platformy .NET 3.5, platforma .NET 4 poczyniła znaczne postępy w ulepszaniu środowiska deweloperów i udostępnia niektóre potrzebne funkcje, których brakuje na platformie .NET 3.5.

Łącząc światy WCF i WF, uzyskujesz najlepsze z obu światów. Otrzymujesz model programowania deklaratywnego, przyjazne dla deweloperów środowisko pracy dzięki projektantom WF, zaawansowanemu środowisku uruchomieniowemu do zarządzania długotrwałymi usługami oraz bogatej elastyczności komunikacji oferowanej przez usługę WCF.

Tworzenie pierwszej usługi przepływu pracy

Aby dać ci wrażenie dla nowego środowiska dewelopera usług przepływu pracy, omówię kompletny przykład tworzenia jednego przy użyciu platformy .NET 4 i nowego projektanta programu Visual Studio 2010.

Jeśli otworzysz program Visual Studio 2010 i wybierz pozycję Plik | Nowy projekt znajdziesz nowy projekt przepływu pracy w szablonach WCF — jest to "Aplikacja usługi przepływu pracy WCF". Wybierzę ten szablon projektu i nadaję mu nazwę "HelloWorldWorkflowService" i utworzymy nowy projekt.

Rysunek 24: Szablony projektów usług przepływu pracy programu Visual Studio 2010

Po utworzeniu nowy projekt będzie zawierać po prostu dwa pliki — plik Service1.xamlx zawierający definicję usługi deklaratywnego przepływu pracy i plik Web.config zawierający konfigurację usługi.

Jedną z najbardziej atrakcyjnych kwestii dotyczących nowego modelu usług przepływu pracy na platformie .NET 4 jest to, że całą definicję usługi można zdefiniować w języku XAML.   W naszym nowym projekcie plik Service1.xamlx zawiera definicję usługi, a implementacja jest po prostu przepływem pracy opartym na języku XAML. Plik Web.config zawiera konfigurację usługi WCF — w tym miejscu zdefiniujesz punkty końcowe i zachowania usługi przepływu pracy.

Rysunek 25 przedstawia wygląd projektanta programu Visual Studio 2010 dla pliku Service1.xamlx. Zwróć uwagę, że jest to tylko standardowy projektant przepływu pracy, tylko w tym konkretnym przypadku projektowy przepływ pracy będzie służyć jako implementacja usługi WCF. Kluczem do zintegrowania tej definicji przepływu pracy z usługą WCF jest nowy element WorkflowServiceHost i zestaw działań "Obsługa komunikatów" programu WCF (zobacz Przybornik na rysunku 25).

Rysunek 25. Projektowanie usługi przepływu pracy w programie Visual Studio 2010

Usługa szkieletowego przepływu pracy dostarczona z tym szablonem projektu zawiera działanie Odbierz, a następnie działanie Wyślij. Zwróć uwagę, że działanie Odbieranie zawiera właściwość OperationName i jest obecnie ustawiona na "GetData". Ma również właściwość Content do powiązania komunikatu przychodzącego ze zmienną lokalną zdefiniowaną w działaniu Sekwencja — w tym przypadku zmienna jest nazywana "danymi" i ma typ Int32 (zobacz okno Zmienne pod usługą projektowania przepływu pracy na rysunku 25).

Działanie Odbieranie jest również skonfigurowane do aktywowania usługi, co oznacza, że w komunikacie przychodzącym może spowodować utworzenie nowego wystąpienia przepływu pracy. Zwróć uwagę, że właściwość CanCreateInstance jest zaznaczona w oknie Właściwości po prawej stronie na rysunku 25).

Dostosujmy nieco tę usługę przepływu pracy. Najpierw zmienię nazwę pliku usługi z Service1.xamlx na HelloWorld.xamlx. Następnie zmienię nazwę usługi na "HelloWorldService" w odpowiednim oknie. Następnie zmienię właściwość OperationName działania Receive na "SayHello". Na koniec zdefiniuję nową zmienną o nazwie "personName" typu String w sekwencji.

Następnie powiążę właściwość Content działania Odbierz ze zmienną "personName", jak pokazano na rysunku 26. Następnie powiążę właściwość Content działania Wyślij z ciągiem w formacie "hello {0}!" wstawia zmienną personName do symbolu zastępczego. Następnie zapiszę wynikowy plik Service1.xamlx.

Rysunek 26. Definiowanie właściwości Content dla działania Odbieranie

W tym momencie otwórz plik HelloWorld.xamlx i sprawdź jego zawartość. Możesz to zrobić, klikając prawym przyciskiem myszy plik w Eksploratorze rozwiązań i wybierając polecenie "Otwórz za pomocą..." a następnie "Edytor XML". Dzięki temu można przyjrzeć się nieprzetworzonej definicji XAML dla usługi. Należy pamiętać, że definicja XAML reprezentuje kompletną implementację usługi. W ogóle nie ma kodu w języku C#.

W tym przykładzie będziemy polegać na domyślnym punkcie końcowym HTTP i zakładamy, że mamy standardowe zachowanie usługi, które automatycznie włącza metadane usługi, więc nie potrzebujemy żadnej konfiguracji programu WCF.

Teraz możemy przetestować naszą usługę przepływu pracy opartą na języku XAML. Jest to tak proste, jak naciśnięcie F5 w programie Visual Studio 2010. Naciśnięcie F5 spowoduje załadowanie usługi przepływu pracy do serwera deweloperów ASP.NET i wyświetlenie klienta testowego programu WCF. Klient testowy WCF automatycznie łączy się z usługą przepływu pracy, pobiera metadane WSDL i umożliwia testowanie logiki usługi przepływu pracy (patrz Rysunek 27).

Rysunek 27. Testowanie usługi przepływu pracy

Ilustruje to, że infrastruktura usług przepływu pracy jest w stanie dynamicznie utworzyć definicję WSDL dla usługi, sprawdzając działania Wyślij i Odbierz używane w definicji przepływu pracy oraz typy komunikatów, które wysyłają i odbierają.

Ten przewodnik zawiera prosty przewodnik tworzenia pierwszej deklaratywnej usługi przepływu pracy na platformie .NET 4. Zobaczyliśmy, że implementacja usługi jest całkowicie zdefiniowana w języku XAML i że używasz działań Wyślij/Odbierz do modelowania interakcji obsługi komunikatów w przepływie pracy. Zobaczyliśmy również, że platforma .NET 4 jest dostarczana z obsługą hostowania plików xamlx, co pozwala usunąć konieczność użycia dodatkowych plików svc. Będziemy dalej zagłębiać się w każdy z tych obszarów bardziej szczegółowo w kolejnych sekcjach.

Hostowanie usług przepływu pracy

Platforma .NET 4 oferuje nową i ulepszoną infrastrukturę hostingu dla usług przepływu pracy. Usługi przepływu pracy można hostować w usługach IIS/WAS lub we własnych aplikacjach przy użyciu elementu WorkflowServiceHost. Infrastruktura hostingu platformy .NET 4 zapewnia niezbędne elementy do zarządzania długotrwałymi wystąpieniami przepływu pracy oraz do korelowania komunikatów, gdy masz wiele wystąpień usługi uruchomionych jednocześnie. Platforma .NET 4 udostępnia również standardowy punkt końcowy kontroli przepływu pracy do zdalnego zarządzania wystąpieniami przepływu pracy.

Hosting w usługach IIS/ASP.NET

Prosty przykład HelloWorldWorkflowService omówiony w poprzedniej sekcji ilustruje sposób hostowania usług przepływu pracy w usługach IIS/ASP.NET. Mimo że przetestowaliśmy usługę przy użyciu serwera ASP.NET Development Server, działałoby to samo w usługach IIS przy użyciu puli aplikacji ASP.NET 4. Platforma .NET 4 instaluje niezbędną procedurę obsługi żądań xamlx, która obsługuje tworzenie elementu WorkflowServiceHost w tle i aktywację poszczególnych wystąpień przepływu pracy.

Mimo że w naszym pierwszym przykładzie użyliśmy podejścia "zero config", można skonfigurować usługi przepływu pracy w ramach Web.config jak każda inna usługa WCF. W tym miejscu należy skonfigurować wszystkie punkty końcowe i zachowania programu WCF, których chcesz użyć. Możesz uwidocznić dowolną liczbę punktów końcowych w usługach przepływu pracy, ale należy rozważyć użycie jednego z nowych powiązań "kontekstu" (np. BasicHttpContextBinding, WSHttpContextBinding lub NetTcpContextBinding), które zarządzają komunikacją specyficzną dla wystąpienia.

W poniższym przykładzie pokazano, jak skonfigurować usługę przepływu pracy z dwoma punktami końcowymi HTTP:

<konfiguracji>

  <system.serviceModel>

    > usług <

      <nazwa usługi="HelloWorldWorkflowService">

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

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

                  contract="IHelloWorld"/>

      </service>

      ...

Możesz również skonfigurować usługę przepływu pracy przy użyciu zachowań programu WCF. W poniższym przykładzie pokazano, jak skonfigurować tę usługę przepływu pracy z kilkoma standardowymi zachowaniami WCF:

<konfiguracji>

  <system.serviceModel>

    > usług <

      <nazwa usługi="HelloWorldWorkflowService"

        behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

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

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

                  contract="IHelloWorld"/>

      </service>

     </services>

    <zachowania>

      <serviceBehaviors>

        <zachowanie name="HelloWorldWorkflowService.Service1Behavior">

          <serviceDebug includeExceptionDetailInFaults="False" />

          <serviceMetadata httpGetEnabled="True"/>

        </behavior>

      </serviceBehaviors>

      ...

Oprócz tych standardowych zachowań WCF platforma .NET 4 zawiera nowe zachowania specyficzne dla platformy WF do kontrolowania trwałości przepływu pracy, śledzenia przepływu pracy i innych zachowań środowiska uruchomieniowego przepływu pracy w połączeniu z usługami przepływu pracy. Aby uzyskać więcej informacji, zobacz przykłady zestawu .NET 4 SDK.

Samodzielne hostowanie za pomocą elementu WorkflowServiceHost

Mimo że platforma .NET 3.5 zawiera klasę WorkflowServiceHost do hostowania usług przepływu pracy, należy przeprojektować wszystkie zmiany w środowisku uruchomieniowym I modelu programowania WF na platformie .NET 4. W związku z tym platforma .NET 4 zawiera nową klasę WorkflowServiceHost znajdującą się w zestawie System.ServiceModel.Activities.

Klasa WorkflowServiceHost ułatwia hostowanie usług przepływu pracy we własnej aplikacji niezależnie od tego, czy jest to aplikacja konsolowa, aplikacja WPF, czy usługa systemu Windows. Poniższy fragment kodu ilustruje sposób użycia elementu WorkflowServiceHost we własnym kodzie aplikacji:

...

WorkflowServiceHost host = new WorkflowServiceHost("HelloWorld.xamlx",

    nowy identyfikator URI("https://localhost:8080/helloworld"));

gospodarz. AddDefaultEndpoints();

gospodarz. Description.Behaviors.Add(

    new ServiceMetadataBehavior { HttpGetEnabled = true });

gospodarz. Open();

Console.WriteLine("Host jest otwarty");

Console.ReadLine();

...

Jak widać, niezależnie od tego, czy chcesz hostować usługi przepływu pracy w usługach IIS/ASP.NET, czy we własnych aplikacjach, są one równie łatwe do hostowania jak każda usługa WCF.

WorkflowControlEndpoint

Hostowanie usługi przepływu pracy zajmuje się inicjowaniem środowiska uruchomieniowego platformy WF i aktywowaniem nowych wystąpień przepływu pracy podczas aktywowania komunikatów dostarczanych przez jeden z uwidocznionych punktów końcowych. Oprócz tej podstawowej funkcji hostingu ważne jest również, aby móc zdalnie zarządzać konfiguracją i wykonywaniem tych uruchomionych wystąpień przepływu pracy. Platforma .NET 4 ułatwia osiągnięcie tego celu, zapewniając standardowy punkt WorkflowControlEndpoint, który można uwidocznić w usługach przepływu pracy.

Poniższy przykład ilustruje sposób dodawania standardowego punktu końcowego kontrolki przepływu pracy do usługi w niestandardowym scenariuszu hostingu:

...

WorkflowServiceHost host = new WorkflowServiceHost("HelloWorld.xamlx",

    nowy identyfikator URI("https://localhost:8080/helloworld"));

gospodarz. AddDefaultEndpoints();

WorkflowControlEndpoint wce = nowy WorkflowControlEndpoint(

    nowy NetNamedPipeBinding(),

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

gospodarz. AddServiceEndpoint(wce);

gospodarz. Open();

...

Jeśli hostujesz w usługach IIS/ASP.NET, możesz dodać standardowy element WorkflowControlEndpoint w następujący sposób:

<konfiguracji>

  <system.serviceModel>

    > usług <

      <nazwa usługi="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>

      ...

Element WorkflowControlEndpoint umożliwi zarządzanie usługą przepływu pracy w różnych środowiskach hostingu. Jedno z takich środowisk jest możliwe przez program AppFabric systemu Windows Server, który będzie dostępny w przyszłej wersji systemu Windows Server.

Działania wysyłania/odbierania

Platforma .NET 3.5 miała dwie działania obsługi komunikatów — Wysyłanie i odbieranie — do wysyłania i odbierania komunikatów przy użyciu programu WCF, ale były one dość ograniczone pod względem ich funkcjonalności. Platforma .NET 4 rozszerza działania wysyłania i odbierania przy użyciu niektórych dodatkowych funkcji (np. korelacji) i dodaje kilka kolejnych działań obsługi komunikatów — SendReply i ReceiveReply — które upraszczają modelowanie operacji żądań i odpowiedzi.

W przypadku korzystania z działań Wyślij/Odbierz w usłudze przepływu pracy zasadniczo używasz ich do modelowania kontraktu usługi, który będzie udostępniany klientom za pomocą definicji WSDL. W przypadku korzystania z działania Odbierz nadaj mu nazwę operacji i zamapujesz komunikat przychodzący na typ platformy .NET. Mimo że do tej pory używaliśmy prostych ciągów, można również używać złożonych kontraktów danych zdefiniowanych przez użytkownika. Zaktualizujmy usługę HelloWorldWorkflowService, aby użyć następującego typu kontraktu danych:

[DataContract(Namespace="")]

osoba klasy publicznej

{

    [DataMember]

    identyfikator ciągu publicznego;

    [DataMember]

    public string FirstName;

    [DataMember]

    public string LastName;

}

Jeśli dodamy tę definicję klasy do projektu internetowego i wrócimy do pliku HelloWorld.xamlx, możemy zdefiniować nową zmienną o nazwie "personMsg" typu Person (kontrakt danych zdefiniowany powyżej). Następnie możemy mapować działania ReceiveRequest i SendResponse na zmienną personMsg za pomocą właściwości "Content". Aby to zrobić, wystarczy wybrać każde działanie i nacisnąć przycisk "Zawartość", aby wyświetlić okno "Definicja zawartości". Następnie wprowadź ciąg "personMsg" w polu tekstowym "Dane wiadomości" i "Person" w polu tekstowym "Typ wiadomości". Należy to zrobić dla obu działań.

Działania Wyślij/Odbierz umożliwiają również skonfigurowanie innych aspektów usługi WCF, takich jak nazwa operacji, nazwa kontraktu usługi, akcja, kolekcja znanych typów, poziom ochrony i serializator do użycia w czasie wykonywania (np. DataContractSerializer a XmlSerializer). W działaniu Wyślij należy również określić szczegóły docelowego punktu końcowego. Wszystkie te ustawienia można skonfigurować za pośrednictwem okna Właściwości, gdy wybrano działanie Wyślij/Odbierz.

Po wprowadzeniu tych zmian można ponownie przetestować plik HelloWorld.xamlx, aby zobaczyć, że operacja SayHello jest teraz zdefiniowana w celu odbierania i zwracania komunikatów typu Person.

Definiowanie operacji Request-Reply

Aby ułatwić modelowanie operacji żądań i odpowiedzi, platforma .NET 4 wprowadza kilka nowych działań do modelowania tego typu interakcji. Jednym z nich jest działanie SendReply, które można połączyć z działaniem Odbierz, aby zaimplementować operację żądania-odpowiedź w usłudze. Istnieje również działanie ReceiveReply, które można połączyć z działaniem Wyślij podczas wywoływania usługi zewnętrznej w przepływie pracy.

Platforma .NET 4 zawiera również kilka działań wyższego poziomu o nazwie ReceiveAndSendReply i SendAndReceiveReply, które będą widoczne w przyborniku programu Visual Studio 2010. Te działania po prostu tworzą odbieranie/wysyłanie za pomocą polecenia SendReply/ReceiveReply i ułatwiają ich używanie. Po przeciągnięciu ich na powierzchni projektowej przepływu pracy zobaczysz, że rozszerzają się one do sekwencji zawierającej działanie Wyślij lub Odbierz, a następnie odpowiednie działanie "odpowiedz".

Dodawanie odwołania do usługi

Aby ułatwić korzystanie z usług zewnętrznych, program Visual Studio 2010 udostępnia również funkcję "Dodaj odwołanie do usługi", która działa tak, jakby się spodziewała, z wyjątkiem tego, że zamiast generowania definicji klasy serwera proxy klienta generuje zestaw działań po stronie klienta. Po wybraniu pozycji "Dodaj odwołanie do usługi" i określeniu adresu definicji WSDL program Visual Studio pobiera plik WSDL i generuje działanie niestandardowe dla każdej operacji znalezionej w definicji WSDL.

Przyjrzyjmy się prostego przykładu. Załóżmy, że istnieje funkcja CalculatorService z operacjami dodawania, odejmowania, mnożenia i dzielenia, których chcemy użyć z naszej usługi przepływu pracy. Możemy po prostu wybrać pozycję "Dodaj odwołanie do usługi" i określić lokalizację definicji WSDL CalculatorService, jak pokazano na rysunku 28.

Rysunek 28. Dodawanie odwołania do usługi

Po naciśnięciu przycisku OK w celu dodania odwołania do usługi program Visual Studio pobierze definicję WSDL i wygeneruje cztery działania niestandardowe, które będą wyświetlane w przyborniku. Teraz masz działania Dodawania, Odejmowania, Mnożenia i Dzielenia, które są łatwe w użyciu w przepływach pracy w celu wywołania usługi zewnętrznej.

Korelacja

W przypadku tworzenia systemów, które składają się z długotrwałych usług przepływu pracy, często istnieje wiele wystąpień pojedynczej usługi przepływu pracy uruchomionej jednocześnie oczekujących na wystąpienie tego samego zdarzenia (np. oczekiwanie na nadejście określonego komunikatu przed kontynuowaniem). Wyzwanie związane z tym scenariuszem polega na tym, że potrzebny jest sposób skorelowania komunikatu przychodzącego z odpowiednim wystąpieniem przepływu pracy. Zazwyczaj sposobem określenia prawidłowego wystąpienia przepływu pracy jest sprawdzenie zawartości komunikatu przychodzącego.

Platforma .NET 4 zawiera zaawansowaną funkcję korelacji komunikatów opartych na zawartości, której można używać w połączeniu z właśnie omówionymi działaniami Wysyłanie i odbieranie. Implementacja tej funkcji koncentruje się na tym, co jest nazywane "uchwytami korelacji", inną nową koncepcją na platformie .NET 4.

Aby rozpocząć korzystanie z korelacji, należy najpierw zdefiniować zmienną przepływu pracy typu CorrelationHandle. Tę zmienną można traktować jako punkt spotkania na potrzeby łączenia fragmentu danych z (potencjalnie) dwóch różnych komunikatów (przetwarzanych przez dwie różne działania obsługi komunikatów). Zarówno działania Wyślij, jak i Odbieraj zapewniają właściwość CorrelationsWith do określania zmiennej CorrelationHandle.

Aby skorelować komunikaty wysyłane przez wiele działań wysyłania/odbierania, należy określić ten sam uchwyt korelacji we wszystkich działaniach, które mają uczestniczyć w korelacji. Następnie w każdym działaniu skonfigurujesz klucz korelacji, który zostanie zamapowany na komunikat przetwarzany przez to konkretne działanie (np. element SSN w jednym komunikacie może skorelować się z elementem CustomerId w innym komunikacie). Klucze korelacji definiuje się przy użyciu wyrażeń XPath, które są oceniane względem komunikatów.

Rozszerzmy naszą usługę HelloWorldWorkflowService, aby zobaczyć przykład działania tej funkcji. Obecnie przykład, z którym pracujemy, otrzymuje komunikat Person i zwraca go z powrotem do klienta. Dodajmy kolejne działanie ReceiveAndSendReply tuż poniżej działania SendResponse w dolnej części przepływu pracy. Spowoduje to dodanie sekwencji zawierającej inną funkcję Odbierz, a następnie inną funkcję SendReply. Dam działanie Odbierz nazwę operacji "Zakończ" i będziemy wymagać od klienta podania pozdrowień w komunikacie Zakończ, który zostanie użyty do utworzenia ostatecznej odpowiedzi powitania.

Innymi słowy, klienci najpierw wywołają funkcję SayHello, podając pełną nazwę, aby rozpocząć nowe wystąpienie usługi przepływu pracy. Następnie wystąpienie przepływu pracy będzie czekać, aż klient wywoła zakończenie dostarczania pozdrowień (i może to potrwać kilka minut, godzin lub dni, w którym może utrwałyć przepływ pracy). Po wywołaniu klienta zakończenie podawania pozdrowień przepływ pracy tworzy powitanie przy użyciu pozdrowień i oryginalnej nazwy i zwraca ją. W tym scenariuszu można łatwo mieć wiele uruchomionych wystąpień przepływu pracy oczekujących na wywołanie operacji Zakończ, dlatego na pewno musimy skorelować komunikat Zakończ z poprzednim komunikatem SayHello. Ponieważ tak jest, muszę skojarzyć działanie Odbieranie dla "Finish" z tym samym uchwytem korelacji, które określono w działaniu "SayHello" (nameHandle).

Teraz przyjrzyjmy się zawartości komunikatu, która zostanie skorelowana między tymi dwoma działaniami. W tym przykładzie użyję następujących dwóch typów kontraktów danych do modelowania komunikatów:

[DataContract(Namespace="")]

osoba klasy publicznej

{

    [DataMember]

    ciąg publiczny FirstName { get; set; }

    [DataMember]

    ciąg publiczny LastName { get; set; }

}

[DataContract(Przestrzeń nazw = "")]

powitanie klasy publicznej

{

    [DataMember]

    publiczny ciąg salutation { get; set; }

    [DataMember]

    public string NameKey { get; set; }

}

Działanie Odbierz dla "SayHello" jest skonfigurowane do używania wiadomości Person i działanie Odbierz dla "Zakończ" jest skonfigurowane do korzystania z komunikatu Powitanie. Załóżmy, że wartość LastName jest zawsze unikatowa, więc możemy użyć jej jako unikatowej wartości korelacji. W związku z tym po wysłaniu komunikatu "Finish" (Zakończ) klient musi podać tę samą wartość LastName używaną w poprzednim komunikacie "SayHello".

Teraz zobaczmy, jak skonfigurować uchwyt korelacji, aby to skonfigurować. Zdefiniowano już zmienną CorrelationHandle w sekwencji o nazwie "handle". Pierwszą rzeczą, którą musimy zrobić, jest "inicjowanie" uchwytu korelacji w działaniu "SayHello" Receive. Wybierz działanie "SayHello" Receive i naciśnij przycisk obok pola tekstowego "CorrelationInitializers".

W tym miejscu należy wybrać pozycję "Inicjator korelacji zapytania" z pola listy rozwijanej, a następnie wybrać właściwość "LastName" dla pola zapytania (powinno to spowodować wygenerowanie wyrażenia XPath "sm:body()/xg0:Person/xg0:LastName", jak pokazano na rysunku 29.

Następnie musimy określić, że działanie "Zakończ" Odbieranie z skorelowane na tym samym dojściu. Wybierz działanie "Zakończ" Odbieranie i naciśnij przycisk "Koreluj". Następnie określ uchwyt "handle" dla uchwytu "KorelowanieWith", a następnie wybierz pozycję "NameKey" dla pola zapytania (zobacz Rysunek 30).

Rysunek 29. Definiowanie klucza korelacji dla "SayHello"

Rysunek 30. Definiowanie klucza korelacji dla

Oznacza to ostatecznie, że element LastName w wiadomości Person musi być zgodny z elementem NameKey w komunikacie Greeting w dwóch oddzielnych żądaniach. Dzięki temu infrastruktura przepływu pracy będzie mogła automatycznie skorelować komunikaty dla nas i kierować przychodzące komunikaty "Finish" do poprawnego wystąpienia przepływu pracy (na podstawie "LastName/NameKey").

Ostatnie działanie SendReply zwraca następujący sformatowany ciąg do obiektu wywołującego, w tym informacje z oryginalnego "personMsg" i nowego "greetingMsg":

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

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

Przetestuję funkcję korelacji przy użyciu klienta testowego WCF, aby uruchomić kilka wystąpień przepływu pracy, wywołując funkcję SayHello wiele razy z różnymi wartościami FirstName i LastName. Po wykonaniu tej czynności powinniśmy mieć kilka uruchomionych wystąpień usługi przepływu pracy. Teraz możemy wywołać operację Zakończ określając jedną z tych samych wartości LastName używanych w jednym z komunikatów SayHello i powinniśmy zobaczyć odpowiednią wartość FirstName użytą w ostatnim powitaniu zwróconym klientowi (zobacz Rysunek 31).

Ilustruje to korelację opartą na zawartości w działaniu— atrakcyjną funkcję usług przepływu pracy, która jest dostarczana z platformą .NET 4. Należy pamiętać, że można również przeprowadzić korelację na podstawie danych na poziomie kanału i protokołu, takich jak w przypadku platformy .NET 3.5 (np. przy użyciu identyfikatora wystąpienia kanału lub przepływu pracy). Korelacja oparta na zawartości to bardziej elastyczne i wyrafinowane podejście do wykonywania tych samych czynności.

Rysunek 31. Testowanie przykładu korelacji opartej na zawartości

To prowadzi nas do końca naszego pokrycia usług przepływu pracy. Udało nam się tylko zdrapać powierzchnię usług przepływu pracy w tym dokumencie, ale będziesz w stanie znaleźć dodatkowe informacje w przykładach zestawu SDK platformy .NET 4 i w rosnącej dokumentacji MSDN znalezionej w trybie online. Jak widać, połączenie usług WCF i WF 4 otwiera drzwi do całkowicie nowego modelu programowania do tworzenia deklaratywnych, długotrwałych i asynchronicznych usług, które mogą cieszyć się najlepszymi funkcjami, które mają do zaoferowania obie struktury.

Różne funkcje zaawansowane

Oprócz wszystkich innych omówionych w tym dokumencie, WCF 4 zawiera kilka bardziej zaawansowanych funkcji, które mogą okazać się przydatne. Te zaawansowane funkcje obejmują ulepszoną obsługę rozpoznawania typów dzięki usłudze DataContractResolver, możliwości obsługi konkurencyjnych odbiorców kolejek przy użyciu funkcji ReceiveContext, nowego kodera strumienia bajtów i śledzenia opartego na technologii ETW o wysokiej wydajności.

Rozpoznawanie typów za pomocą elementu DataContractResolver

W programie WCF 3.x istnieje funkcja rozpoznawania typów nazywana "znanymi typami". Podczas deserializacji, gdy serializator napotka wystąpienie, które nie jest tego samego typu co zadeklarowany typ, sprawdza listę zadeklarowanych "znanych typów", aby ustalić, jakiego typu użyć. Jako autor usługi można dodawać adnotacje do typów/metod za pomocą atrybutów [KnownType] lub [ServiceKnownType], aby zdefiniować listę możliwych podstawień. Ta funkcja jest często używana do obsługi dziedziczenia i polimorfizmu.

Niestety, program WCF 3.x nie zapewnia łatwego sposobu zastąpienia algorytmu mapowania typów używanego przez moduł DataContractSerializer podczas wykonywania tego typu dynamicznego rozpoznawania typów w czasie wykonywania. Aby rozwiązać ten problem, program WCF 4 udostępnia abstrakcyjną klasę DataContractResolver, z której można korzystać, aby zaimplementować własny niestandardowy algorytm rozpoznawania typów.  Poniżej pokazano, jak rozpocząć pracę:

class MyDataContractResolver: DataContractResolver

{

    Zestaw zestawów;

    public MyDataContractResolver(Zestaw)

    {

        this.assembly = assembly;

    }

    Używane podczas deserializacji

    Umożliwia użytkownikom mapowania nazwy xsi:type na dowolny typ

    public override Type ResolveName(ciąg typeName, ciąg typeNamespace,

        Typ declaredType, DataContractResolver znaneTypeResolver)

    {

        ... // Implementowanie mapowania

    }

    Używane w serializacji

    Mapuje dowolny typ na nową reprezentację xsi:type

    publiczne zastąpienie wartości logicznej TryResolveType(typ typu, typ zadeklarowanytypu,

        DataContractResolver knownTypeResolver, out XmlDictionaryString typeName,

        out XmlDictionaryString typeNamespace)

    {

        ... // Implementowanie mapowania

    }

}

Po zaimplementowaniu niestandardowego elementu DataContractResolver możesz podać go do elementu DataContractSerializer, jak pokazano poniżej:

DataContractSerializer dcs = new DataContractSerializer(

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

    new MyDataContractResolver(assembly));

Teraz, gdy użyjesz tego wystąpienia elementu DataContractSerializer do serializacji/deserializowania obiektów, zostanie wywołana niestandardowa funkcja DataContractResolver w celu wykonania niestandardowej rozdzielczości typu.

Aby wstrzyknąć niestandardowy element DataContractResolver do środowiska uruchomieniowego WCF w tle, musisz napisać zachowanie kontraktu WCF, które podłącza się do elementu DataContractSerializerOperationBehavior i zastępuje domyślny moduł rozpoznawania. Zestaw SDK platformy .NET 4 zawiera kompletny przykład, który ilustruje, jak to osiągnąć za pomocą zachowania kontraktu i atrybutu niestandardowego o nazwie [KnownAssembly].

Rozpoznawanie typów niestandardowych może być przydatne, gdy chcesz zastąpić wartości domyślne elementu DataContractSerializer, kontrolować dokładnie typy używane do serializacji lub dynamicznie zarządzać znanymi typami.

Przetwarzanie komunikatów w kolejce za pomocą funkcji ReceiveContext

W programie WCF 3.x można zagwarantować dokładnie jednokrotne dostarczanie komunikatów przy użyciu narzędzia NetMsmqBinding przy użyciu kolejek transakcyjnych i zarejestrowania operacji usługi WCF w transakcji MSMQ. Gdy wyjątki są zgłaszane podczas przetwarzania komunikatu, program WCF zapewni, że komunikat nie zostanie utracony, zwracając komunikat do kolejki (może zostać zwrócony do kolejki źródłowej, kolejki komunikatów trucizny lub kolejki utraconych komunikatów w zależności od konfiguracji).

Chociaż ta funkcja jest ważna, istnieje kilka problemów, które ludzie często napotykają. Jednym z nich jest to, że transakcje są kosztowne i produkuje dużo odczytu/zapisu w kolejkach, co wprowadza większe obciążenie i złożoność. Innym problemem jest to, że nie ma sposobu, aby upewnić się, że ta sama usługa przetwarza komunikat przy następnym pobraniu go z kolejki (np. nie ma możliwości, aby określona usługa "zablokowała" komunikat), co jest gwarancją, którą możesz wykonać w niektórych scenariuszach.

Aby rozwiązać te problemy, program WCF 4 wprowadza nowy interfejs API o nazwie ReceiveContext do przetwarzania komunikatów w kolejce. Dzięki funkcji ReceiveContext usługa może "zajrzeć" do komunikatu w kolejce, aby rozpocząć jego przetwarzanie, a jeśli coś pójdzie źle i zostanie zgłoszony wyjątek, pozostaje w kolejce. Usługi mogą również "zablokować" komunikaty, aby ponowić próbę przetworzenia w późniejszym momencie. Funkcja ReceiveContext udostępnia mechanizm "kończenia" komunikatu po jego przetworzeniu, dzięki czemu można go usunąć z kolejki.

Takie podejście upraszcza wiele rzeczy na kilku frontach, ponieważ komunikaty nie są już odczytywane i ponownie zapisywane w kolejkach za pośrednictwem sieci, a poszczególne komunikaty nie odbijają się między różnymi wystąpieniami usług podczas przetwarzania. Przyjrzyjmy się prostemu przykładowi, aby zilustrować jego działanie.

W poniższym przykładzie pokazano, jak używać metody ReceiveContext do przetwarzania komunikatów przychodzących do kolejki:

...

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

[ReceiveContextEnabled(ManualControl = true)]

public void CalculateProduct(int firstNumber, int secondNumber)

{

    ReceiveContext receiveContext;

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

         out receiveContext))

    {

        Console.WriteLine("ReceiveContext not installed/found on this machine.");

        wrócić;

    }

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

    {

        receiveContext.Complete(TimeSpan.MaxValue);

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

            firstNumber * secondNumber);

    }

    inaczej

    {

        receiveContext.Abandon(TimeSpan.MaxValue);

        Console.WriteLine("{0} & {1} nie przetworzona", firstNumber, secondNumber);

    }

    receiveCount++;

}

...

Przy założeniu pomyślnego przekazania wywołujemy metodę ReceiveContext.Complete, aby zakończyć przetwarzanie komunikatu powodującego jego usunięcie z kolejki bazowej. W przeciwnym razie wywołujemy metodę Abandon, co powoduje pozostawienie komunikatu w kolejce na potrzeby przyszłych ponownych prób. Zestaw SDK platformy .NET 4 zawiera kompletny przykład, którego można użyć do dokładniejszego eksplorowania tej nowej funkcji.

Usprawnij kodowanie za pomocą elementu ByteStreamMessageEncodingBindingElement

W niektórych scenariuszach obsługi komunikatów po prostu chcesz przesyłać "obiekty blob" danych binarnych bez żadnego zawijania ani dodatkowego przetwarzania. Aby uprościć ten scenariusz, WCF 4 jest dostarczany z nowym elementem ByteStreamMessageEncodingBindingElement, który właśnie to robi. Niestety platforma .NET 4 nie zawiera nowego powiązania dla tego kodera, dlatego konieczne będzie utworzenie niestandardowego powiązania w celu jego użycia.

Zestaw SDK platformy .NET 4 zawiera kompletny przykład, który ilustruje sposób definiowania powiązania niestandardowego używającego elementu ByteStreamMessageEncodingBindingElement za pomocą niestandardowej klasy powiązania. Po utworzeniu nowej klasy powiązania koder strumienia bajtów staje się bardzo łatwy w użyciu z usługami.

Śledzenie oparte na technologii ETW o wysokiej wydajności

Program WCF 4 wprowadza również pewne ulepszenia w zakresie śledzenia i diagnostyki. Program WCF 4 korzysta teraz z funkcji ETW do śledzenia, co znacznie poprawia wydajność śledzenia i zapewnia lepszą integrację z innymi powiązanymi technologiami, takimi jak Windows Workflow Foundation, Windows Server AppFabric i różnymi technologiami zarządzania znajdującymi się w systemie Windows Server, oferując lepszy model dla platformy.

W przypadku etW dostawcy zdarzeń zapisują zdarzenia do sesji i sesji mogą opcjonalnie utrwalać te zdarzenia w dzienniku. Konsumenci mogą nasłuchiwać zdarzeń sesji w czasie rzeczywistym lub odczytywać te zdarzenia z dziennika po fakcie. Kontrolery ETW są odpowiedzialne za włączanie/wyłączanie sesji i kojarzenie dostawców z sesjami.

Zestaw .NET 4 SDK zawiera prosty przykład ilustrujący sposób wykorzystania tej nowej architektury śledzenia o wysokiej wydajności w połączeniu z usługami WCF.

Konkluzja

Program WCF 4 oferuje liczne ulepszenia i kilka zupełnie nowych funkcji, które dotyczą niektórych z dzisiejszych najbardziej typowych scenariuszy komunikacyjnych. Przede wszystkim usługa WCF 4 staje się łatwiejsza w użyciu dzięki uproszczonemu modelowi konfiguracji i lepszej obsłudze typowych ustawień domyślnych.

Ponadto usługa WCF 4 zapewnia najwyższej klasy obsługę odnajdywania i routingu usług, które są typowymi wymaganiami w większości środowisk przedsiębiorstwa i dużych inicjatyw SOA — te funkcje różnią się od wielu konkurencyjnych struktur. WCF 4 upraszcza również opracowywanie usług opartych na protokole REST i udostępnia kilka innych bardziej zaawansowanych funkcji WCF, które obecnie dotyczą niektórych konkretnych punktów bólu.

Oprócz tego wszystkiego program WCF 4 zapewnia zaawansowaną integrację z platformą WF, aby zapewnić nowy model tworzenia deklaratywnych usług przepływu pracy. Usługi przepływu pracy umożliwiają opracowywanie długotrwałych i asynchronicznych usług, które korzystają z modelu programowania WF i bazowego środowiska uruchomieniowego. Dzięki nowym działaniom opartym na programie WCF i obsłudze projektanta znalezionej w programie Visual Studio 2010 ten nowy model programowania staje się pierwszą klasą dla usług tworzenia.

Na platformie .NET 4 światy WCF i WF łączą się ze sobą, aby oferować spójny model programowania, który daje najlepsze, jakie światy mają do zaoferowania. Aby uzyskać więcej informacji na temat nowości w programie WF 4, zapoznaj się z artykułem A Developer's Introduction to Windows Workflow Foundation in .NET 4 (Wprowadzenie dewelopera do programu Windows Workflow Foundation na platformie .NET 4).

Informacje o autorze

Aaron Skonnard jest współzałożycielem Firmy Pluralsight, dostawcą szkoleń firmy Microsoft oferującym kursy dla deweloperów prowadzone przez instruktora i na żądanie .NET. W dzisiejszych czasach Aaron spędza większość czasu na nagrywaniu Pluralsight On-Demand! kursy skoncentrowane na przetwarzaniu w chmurze, platformie Windows Azure, usłudze WCF i rest. Aaron spędził lata pisania, mówienia i nauczania profesjonalnych deweloperów na całym świecie. Możesz skontaktować się z nim w http://pluralsight.com/aaron i http://twitter.com/skonnard.

Dodatkowe zasoby