Wprowadzenie dewelopera do programu Windows Communication Foundation 4

Aaron Skonnard, Pluralsight

Oryginał: listopad 2009 r.

Zaktualizowano do RTM: kwiecień 2010 r.

Omówienie

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 bogatej integracji z programem Windows Workflow Foundation (WF), tworząc "usługi przepływu pracy" obywatela pierwszej klasy.

Dobrą wiadomością jest większość zmian WCF 4 koncentruje się na ułatwianiu dzisiejszych typowych scenariuszy i tworzeniu nowych scenariuszy komunikacyjnych i stylów programowania. W rezultacie 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 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 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, znacznie upraszczając środowisko deweloperskie w najbardziej typowych scenariuszach WCF.

Odnajdywanie

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żyć 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 struktury integracji programu WCF z programem WF w celu zaimplementowania deklaratywnych długotrwałych usług przepływu pracy. Ten nowy model programowania zapewnia najlepsze platformy, które muszą oferować (WCF & WF).

Po zakończeniu obsługi tych głównych obszarów funkcji omówimy krótko niektóre bardziej zaawansowane funkcje usługi WCF niższego poziomu, które są wyposażone w platformę .NET 4, w tym takie rzeczy, jak ulepszone możliwości rozpoznawania typów, obsługa kolejek z konkurencyjnymi konsumentami ("kontekst odbierania"), 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 program 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, ale 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ć, zanim będzie można rozpocząć pracę.

Rzeczywistość jest konfiguracja WCF zwykle staje się najbardziej kosztownym obszarem korzystania z usługi WCF w praktyce dzisiaj i wiele z tych złożoności ląduje na pracownikach 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ść sieci przy użyciu programu WCF 3.x, można rozsądnie stwierdzić, że trudniej jest użyć niż jego poprzednik ASP.NET usług sieci Web (ASMX). Dzięki usłudze ASMX można było zdefiniować operację [WebMethod], a środowisko uruchomieniowe automatycznie dostarczyło konfigurację domyślną dla podstawowej komunikacji. Po przejściu 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 zniechęcająca 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 WCF. Jeśli nie udostępnisz ż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 uruchomić i uruchomić usługę WCF, zwłaszcza dla tych, którzy nie znają różnych opcji konfiguracji programu WCF i chętnie akceptują ustawienia domyślne, przynajmniej do rozpoczęcia pracy.

Domyślne punkty końcowe

W programie WCF 3.x, jeśli spróbujesz hostować usługę bez żadnych 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ę Open w wystąpieniu serviceHost, tworzy wewnętrzny opis usługi z pliku konfiguracji aplikacji wraz z wszystkimi, które aplikacja hosta mogła skonfigurować jawnie i jeśli liczba skonfigurowanych punktów końcowych jest nadal zero, wywołuje funkcję 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 bazowych 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 funkcji AddDefaultEndpoints dodaje jeden domyślny punkt końcowy na adres podstawowy 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 (jeden dla każdego kontraktu usługi). Jeśli jednak usługa implementuje dwa kontrakty usługi, a host jest skonfigurowany z dwoma adresami podstawowymi (jeden dla protokołu HTTP i jeden dla protokołu TCP), punkty AddDefaultEndpoint 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żyć klasy ServiceHost do hostowania usługi GreetingService bez żadnej konfiguracji aplikacji. W przypadku korzystania z klasy 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, a następnie ponownie można założyć, że nie ma app.config pliku skojarzonego z tym programem:

program klasy

{

    static void Main(string[] args)

    {

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

        Host ServiceHost = nowy serviceHost(typeof(GreetingService),

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

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

        Hosta. Open();

        foreach (serviceEndpoint se in host. Description.Endpoints)

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

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

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

        Console.ReadLine();

        Hosta. Close();

    }

}

W tym przykładzie skonfigurowano parametr 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 dla podstawowego adresu 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ę, jak 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żę ci, jak wkrótce zmienić te wartości 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ą, aby skonfigurować usługę z co najmniej jednym punktem końcowym, w danych wyjściowych nie będą już widoczne żadne z tych domyślnych punktów końcowych. Aby to zilustrować, po prostu dodaję następujący wiersz kodu, który wywołuje addServiceEndpoint po utworzeniu wystąpienia ServiceHost:

...

Host ServiceHost = nowy serviceHost(typeof(GreetingService),

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

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

Hosta. 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 z pojedynczym punktem końcowym

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. W poniższym przykładzie kodu pokazano, jak to zrobić:

...

Host ServiceHost = nowy serviceHost(typeof(GreetingService),

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

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

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

Hosta. AddDefaultEndpoints();

...

Jeśli ponownie uruchomisz aplikację konsolową z tą zmianą, zobaczysz pięć punktów końcowych wyświetlanych w oknie konsoli — ten, który skonfigurowano 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, jak 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łu 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 .NET 4 machine.config.comments i 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 Twoja organizacja koncentruje się głównie na tworzeniu usług RESTful za pomocą usługi WCF, warto zmienić domyślne powiązanie schematu protokołu "http" na webHttpBinding. W poniższym przykładzie pokazano, jak to zrobić w pliku konfiguracji aplikacji:

<konfiguracja>

  <System.servicemodel>

    <protocolMapping>

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

    </protocolMapping>

  </System.servicemodel>

</Konfiguracji>

Teraz, jeśli uruchomię ponownie aplikację konsolową pokazaną wcześniej z tą app.config, dwa domyślne punkty końcowe oparte na protokole HTTP będą teraz pokazywać, że używają składnika 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ązań, możesz również zastąpić domyślną konfigurację dla określonego powiązania.

Domyślne konfiguracje powiązań

Każde powiązanie programu WCF jest dostarczane z 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ć przez zastosowanie jawnej konfiguracji powiązania.

W programie WCF 3.x należy 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 uciążliwa i podatna na błędy.  Poniższy plik konfiguracji przedstawia typowy przykład:

<Konfiguracji>

  <System.servicemodel>

    <Powiązania>

      <basicHttpBinding>

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

      </basicHttpBinding>

    </Powiązania>

    <services>

      <service name="GreetingService">

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

                  bindingConfiguration="BasicWithMtom"

                  contract="IHello"/>

      </service>

    </Usług>

  </System.servicemodel>

</Konfiguracji>

W powyższym przykładzie konfiguracja powiązania "BasicWithMtom" zastępuje wartości domyślne basicHttpBinding przez zmianę kodowania komunikatu na MTOM. Jednak ta konfiguracja powiązania ma zastosowanie tylko wtedy, gdy zastosujesz ją do określonego punktu końcowego za pomocą atrybutu "bindingConfiguration" — jest to krok, który często wymyka się deweloperom i personelowi operacyjnemu, co powoduje problemy z konfiguracją.

W programie WCF 4 można teraz zdefiniować domyślne konfiguracje powiązań, 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 mają 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>

        <binding messageEncoding="Mtom"/><-- zwróć uwagę, że nie ma atrybutu name ->

      </basicHttpBinding>

    </Powiązania>

  </System.servicemodel>

</Konfiguracji>

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

Ta funkcja zapewnia prosty mechanizm definiowania standardowego zestawu domyślnych powiązań, które 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 działu IT/operacji. Mogą po prostu wybrać odpowiednie powiązanie i zapewnić, ż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, czym powinna być ich domyślna konfiguracja zachowania.

Domyślne konfiguracje zachowań

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><-- zwróć uwagę na brak atrybutu name ->

          <serviceMetadata httpGetEnabled="true"/>

        </Zachowanie>

      </Servicebehaviors>

    </Zachowania>

  </System.servicemodel>

</Konfiguracji>

W tym przykładzie włączono metadane usługi dla każdej usługi, która nie ma jawnej konfiguracji zachowania. Jeśli dodamy tę domyślną konfigurację zachowania do pliku app.config dla aplikacji konsolowej wyświetlanej wcześniej i 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 zachowań obsługują teraz model dziedziczenia. Jeśli aplikacja definiuje konfigurację zachowania przy użyciu tej samej nazwy co ta, która została już zdefiniowana w machine.config, konfiguracja zachowania specyficzna dla aplikacji zostanie scalona z konfiguracją całego komputera, dodając wszelkie dodatkowe zachowania do konfiguracji pochodnego zachowania złożonego.

Standardowe punkty końcowe

Powiązane z domyślnymi punktami końcowymi to kolejna nowa funkcja programu 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ć. Standardowe punkty końcowe definiują "standardową" konfigurację punktu końcowego, której zwykle nie zmieniasz, chociaż możesz to zrobić, jeśli będzie to konieczne wkrótce.

Rysunek 7 opisuje standardowe punkty końcowe dostarczane z programem 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 należy określić element IMetadataExchange dla kontraktu usługi i najprawdopodobniej wybrać protokół HTTP. Dlatego zamiast wymuszać ręczne wykonywanie tych czynności ręcznie, program WCF udostępnia standardową definicję punktu końcowego dla metdata exchange o nazwie "mexEndpoint", która jest łatwa w użyciu.

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

Nazwa standardowego punktu końcowego Opis

mexEndpoint

Definiuje standardowy punkt końcowy dla programu MEX skonfigurowany przy użyciu interfejsu IMetadataExchange dla kontraktu usługi, mexHttpBinding jako domyślnego powiązania (można to zmienić) i pustego adresu.

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 pod adresem multiemisji. Pochodzi z odnajdywaniaEndpoint.

Announcementendpoint

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 przy użyciu biblioteki WebHttpBinding i WebHttpBehavior. Służy do uwidaczniania usług REST.

Webscriptendpoint

Definiuje standardowy punkt końcowy skonfigurowany przy użyciu 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 <punktu końcowego> 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>

    <services>

      <service name="GreetingService">

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

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

      </service>

    </Usług>

  </System.servicemodel>

</Konfiguracji>

Mimo że standardowe punkty końcowe chronią cię przed większością szczegółów konfiguracji (np. z punktem końcowym mexEndpoint, którego nie musiałem określać powiązania lub kontraktu), nadal mogą występować czasy, kiedy chcesz ich używać, ale trzeba skonfigurować standardowe definicje punktów końcowych nieco inaczej. 

Aby to zrobić, 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>

    <services>

      <service name="GreetingService">

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

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

      </service>

    </Usług>

    <standardEndpoints>

      <Udpdiscoveryendpoint>

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

      </Udpdiscoveryendpoint>

    </standardEndpoints>

    <Zachowania>

      <Servicebehaviors>

        <Zachowanie>

          <serviceDiscovery/>

          <serviceMetadata httpGetEnabled="true"/>

        </Zachowanie>

      </Servicebehaviors>

    </Zachowania>

  </System.servicemodel>

</Konfiguracji>

Ten przykład ma na celu zmianę 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żna narysować 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 po przejściu do witryny HelloWorld.svc (zobacz Rysunek 8).

Rysunek 8. Strona pomocy usługi 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"/>

      </Zachowanie>

    </Servicebehaviors>

  </Zachowania>

</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ż jedną umowę 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) za pośrednictwem pliku svc pokazanego tutaj:

<-- GreetingService.svc —>

<%@ServiceHost Service="GreetingService"%>

Biorąc pod uwagę naszą definicję usługi GreetingService, po raz pierwszy przejdziesz do elementu GreetingService.svc, logika aktywacji 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 portu> w elemecie <usługi> .

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

Aktywacja bez plików

Chociaż pliki svc ułatwiają uwidocznienie usług WCF, jeszcze łatwiejsze byłoby zdefiniowanie punktów końcowych aktywacji wirtualnej w Web.config, co eliminuje konieczność całkowitego użycia plików svc.

W programie WCF 4 można zdefiniować punkty końcowe aktywacji usługi wirtualnej mapujące na typy usług w 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>

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

      </serviceActivations>

    </serviceHostingEnvironment>

  </System.servicemodel>

</Konfiguracji>

Dzięki temu można teraz aktywować usługę GreetingService przy użyciu ścieżki względnej "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ą na katalog projektu GreetingService zawierający web.config pokazaną powyżej. Teraz mogę po prostu przejść do https://localhost/GreetingSite/Greeting.svc bez fizycznego pliku svc na dysku. Rysunek 9 pokazuje, jak wygląda to w przeglądarce.

Rysunek 9. Przykład aktywacji bez pliku

Odnajdywanie

Kolejną główną funkcją programu WCF 4, o której omówimy, 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 łączą się 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 do 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. Następnie klient może wybrać określony 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 przez wysyłanie komunikatów multiemisji. Platforma udostępnia 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 do sieci 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.

Odnajdywanie usługi zarządzanej zapewnia serwer proxy odnajdywania w sieci, która "zarządza" punktami końcowymi usługi, które można odnajdywać. Klienci komunikują się bezpośrednio z serwerem proxy odnajdywania, aby zlokalizować usługi na podstawie kryteriów sondowania. Serwer proxy odnajdywania potrzebuje repozytorium usług, które mogą być zgodne z zapytaniem. Sposób wypełniania serwera proxy tą informacjami jest szczegółem implementacji. Serwery proxy odnajdywania można łatwo połączyć z repozytorium usługi eksisytowania, można je wstępnie skonfigurować za pomocą listy 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 anonse mogą być emisją jednoemisji 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 oddzielają szczegóły protokołu odnajdywania, dzięki czemu można po prostu skupić się na logice, którą ma zawierać serwer proxy odnajdywania. Na przykład wystarczy zdefiniować, co będzie robić serwer proxy odnajdywania w odpowiedzi na komunikat sondy, komunikaty o anonsie i rozpoznawać 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ę każdemu z poniższych elementów.

Proste odnajdywanie usług

Najprostszym sposobem włączenia odnajdywania usługi jest tryb ad hoc. Usługa 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ę do odnajdywania, wystarczy dodać standardowy punkt końcowy "udpDiscoveryEndpoint", a następnie włączyć <zachowanie usługi ServiceDiscovery> w usłudze.

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

<Konfiguracji>

    <System.servicemodel>

      <services>

        <service name="CalculatorService">

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

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

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

        </service>

      </Usług>

      <Zachowania>

        <Servicebehaviors>

          <Zachowanie>

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

          </Zachowanie>

        </Servicebehaviors>

      </Zachowania>

    </System.servicemodel>

</Konfiguracji>

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 wykonywanie tych działań za pośrednictwem standardowego punktu końcowego dynamicEndpoint.

Wystarczy użyć istniejącego punktu końcowego klienta do nawiązania połączenia z usługą, usunąć adres i dodać tag kind="dynamicEndpoint".

<Konfiguracji>

    <System.servicemodel>

        <klient>

          <Punktu końcowego

              name="calculatorEndpoint"

              kind="dynamicEndpoint"

              binding="wsHttpBinding"

              contract="ICalculatorService">

          </Punktu końcowego>

        </Klienta>

    </System.servicemodel>

</Konfiguracji>

Po nawiązaniu 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ą precyzyjne dostosowywanie serach, dostosowywanie powiązań odnajdywania i kontrolowanie procesu odnajdywania. Można również wykonać wszystkie te czynności programowo przy użyciu klasy DiscoveryClient.

W poniższym przykładzie pokazano, jak programowo użyć punktu końcowego UdpDiscoveryEndpoint w celu odnalezienia punktu końcowego ICalculatorService, a następnie wywołania go:

Tworzenie elementu DiscoveryClient

DiscoveryClient discoveryClient =

    new DiscoveryClient(nowy UdpDiscoveryEndpoint());

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

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

FindResponse findResponse = discoveryClient.Find(findCriteria);

Po prostu wybierz 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

Klienta. Endpoint.Address = address;

Console.WriteLine("Wywoływanie calculatorService pod adresem {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);

Gdy program kliencki pobierze kolekcję odnalezionych punktów końcowych, może użyć jednej 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 jest dostarczany z zachowaniem <endpointDiscovery> , którego można użyć do zdefiniowania 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>

      <services>

        <service name="CalculatorService"

                 behaviorConfiguration="calculatorServiceBehavior">

          <endpoint binding="wsHttpBinding"

                    contract="ICalculatorService"

                    behaviorConfiguration="ep1Behavior" />

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

        </service>

      </Usług>

      <Zachowania>

        <Servicebehaviors>

          <behavior name="calculatorServiceBehavior">

            <serviceDiscovery/>

          </Zachowanie>

        </Servicebehaviors>

        <endpointBehaviors>

          <behavior name="ep1Behavior">

            <endpointDiscovery>

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

              <Zakresów>

                <dodawanie zakresu="http://www.example.org/calculator"/>

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

              </Zakresów>

            </endpointDiscovery>

          </Zachowanie>

        </endpointBehaviors>

      </Zachowania>

    </System.servicemodel>

</Konfiguracji>

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 klienta 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ą dowiedzieć się więcej o nowych punktach końcowych usługi w miarę dołączania 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 <usługi ServiceDiscovery> umożliwia zdefiniowanie kolekcji punktów końcowych anonsów, które zostaną uwidocznione 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ę:

<konfiguracja>

  <System.servicemodel>

    <services>

      <service name="CalculatorService">

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

        <endpoint kind="udpDiscoveryEndpoint"/>

      </service>

    </Usług>

    <Zachowania>

      <Servicebehaviors>

        <Zachowanie>

          <serviceDiscovery>

            <anonsEndpoints>

              <endpoint kind="udpAnnouncementEndpoint"/>

            </announcementEndpoints>

          </serviceDiscovery>

        </Zachowanie>

      </Servicebehaviors>

    </Zachowania>

  </System.servicemodel>

</Konfiguracji>

Po skonfigurowaniu tej konfiguracji usługa będzie ogłaszać się w trybie online i będzie również ogłaszana w trybie offline. Aby móc korzystać z tych anonsów, należy w szczególności 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ół anonsowania WS-Discovery.

Program WCF 4 jest wyposażony w klasę o nazwie AnnouncementService zaprojektowaną specjalnie do tego celu. Usługa AnnouncementService udostępnia dwa programy obsługi zdarzeń: OnlineAnnouncementReceived i OfflineAnnouncementReceived. Aplikacje klienckie mogą po prostu hostować wystąpienie klasy AnnouncementService 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 komunikat "online", a usługa OnlineAnnouncementReceived zostanie wyzwolona w kliencie. Gdy usługa przejdzie w tryb offline, wyśle do klienta anons "offline", a funkcja OfflineAnnouncementReceived zostanie wyzwolona na kliencie. Poniżej przedstawiono przykładową aplikację kliencką, która hostuje usługę AnnouncementService i implementuje programy obsługi dla dwóch zdarzeń anonsu:

class Client

{

    public static void Main()

    {

        Tworzenie wystąpienia usługi AnonsService

        AnnouncementService announcementService = new AnnouncementService();

        Subskrybowanie zdarzeń anonsu

        announcementService.OnlineAnnouncementReceived += OnOnlineEvent;

        announcementService.OfflineAnnouncementReceived += OnOfflineEvent;

        Tworzenie elementu ServiceHost dla elementu AnnouncementService

        using (ServiceHost announcementServiceHost =

            new ServiceHost(announcementService))

        {

            Posłuchaj ogłoszeń wysłanych za pośrednictwem multiemisji UDP

            announcementServiceHost.AddServiceEndpoint(

                new UdpAnnouncementEndpoint());

            announcementServiceHost.Open();

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

            Console.WriteLine();

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

            Console.ReadLine();

        }

    }

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

    {

        Console.WriteLine();

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

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);

    }

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

    {

        Console.WriteLine();

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

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);

    }

    ...

}

Rysunek 11. Nasłuchiwanie komunikatów o anonsach dotyczących 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 każdym uruchomieniu w oknie konsoli klienta zostanie wyświetlony komunikat "online". Po zamknięciu każdej z 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 anonsowania 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ć z niej dane. Jak więc zaimplementować usługę serwera proxy odnajdywania?

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

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 również użyć bazy danych lub pliku płaskiego.

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

    {

        Tę. AddOnlineService(endpointDiscoveryMetadata);

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

    }

    protected override void OnEndOnlineAnnouncement(IAsyncResult result)

    {

        OnOnlineAnnouncementAsyncResult.End(result);

    }

    OnBeginOfflineAnnouncement jest wywoływany po odebraniu komunikatu Bye przez serwer proxy

    chronione zastąpienie IAsyncResult OnBeginOfflineAnnouncement(

        DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, wywołanie zwrotne AsyncCallback, stan obiektu)

    {

        Tę. RemoveOnlineService(endpointDiscoveryMetadata);

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

    }

    protected override void OnEndOfflineAnnouncement(IAsyncResult result)

    {

        OnOfflineAnnouncementAsyncResult.End(result);

    }

    Funkcja OnBeginFind jest wywoływana po odebraniu komunikatu żądania sondy przez serwer proxy

    chronione zastąpienie IAsyncResult OnBeginFind(

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

    {

        Tę. MatchFromOnlineService(findRequestContext);

        zwraca nowy element OnFindAsyncResult (wywołanie zwrotne, stan);

    }

    protected override void OnEndFind(IAsyncResult result)

    {

        OnFindAsyncResult.End(result);

    }

    ...

W tym przykładzie po prostu hostuję 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 odnajdywania punktu końcowegoEndpoint = nowe odnajdywanieEndpoint(

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

        discoveryEndpoint.IsSystemEndpoint = false;

        AnonsEndpoint ogłoszenieEndpoint = nowy anonsEndpoint(

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

        proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);

        proxyServiceHost.AddServiceEndpoint(announcementEndpoint);

        proxyServiceHost.Open();

        Console.WriteLine("Uruchomiono usługę serwera proxy".");

        Console.WriteLine();

        Console.WriteLine("Naciśnij <klawisz 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 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 końcowego anonsu w aplikacji hosta usługi. W poniższym przykładzie pokazano, jak to zrobić:

...

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

    Guid.NewGuid(). ToString());

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

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

ServiceEndpoint netTcpEndpoint = serviceHost.AddServiceEndpoint(

    typeof(ICalculatorService), nowy ciąg NetTcpBinding(). Pusty);

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

AnonsEndpoint ogłoszenieEndpoint = 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 odnajdywania punktu końcowegoEndpoint = nowe odnajdywanieEndpoint(

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

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

DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint);

Znajdowanie punktów końcowych ICalculatorService

FindResponse findResponse = discoveryClient.Find(

    new FindCriteria(typeof(ICalculatorService)));

...

Teraz przejmijmy kompletny przykład. Najpierw uruchomię aplikację serwera proxy odnajdywania, aby usługa serwera proxy odnajdywania mogła być używana. Następnie uruchomię wystąpienie aplikacji hosta usługi, które zostanie ogłoszone za pomocą serwera proxy odnajdywania. Gdy tak się stanie, zobaczymy komunikat wydrukowany w oknie konsoli aplikacji serwera proxy odnajdywania (zobacz Rysunek 13). Ilustruje to, ż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, sonduje on 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ść wdrażania serwera proxy odnajdywania. Otrzymywanie ogłoszeń jest jednym 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 reagować bezpośrednio na nadawcę. 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 jego obecności i informuje nadawcę o kierowaniu dalszych zapytań na serwerze proxy, co pozwala uniknąć dalszych komunikatów multiemisji.

Aby uzyskać więcej informacji na temat tych zaawansowanych scenariuszy odnajdywania, zobacz WS-Discovery Primer na stronie 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 zaimplementowania scentralizowanej granicy zabezpieczeń, przez którą muszą przechodzić wszystkie komunikaty przychodzące. Niektórzy 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łów, 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 jest też rzadkością używanie 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 struktura 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, program WCF 4 jest teraz dostarczany 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.

Celem usługi RoutingService jest odbieranie komunikatów przychodzących od użytkowników i "kierowanie ich" do odpowiedniej usługi podrzędnej. RouterService określa, która usługa docelowa ma być używana przez ocenę każdego komunikatu przychodzącego 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 tym samym komputerze 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 serviceHost =

        new ServiceHost(typeof(RoutingService)))

    {

        try

        {

            serviceHost.Open();

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

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

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

            Console.ReadLine();

            serviceHost.Close();

        }

        catch (CommunicationException)

        {

            serviceHost.Abort();

        }

    }

}

Skonfigurujesz również usługę RoutingService tak jak dowolną inną usługę, a w tym miejscu definiujesz filtry routingu. Najpierw należy skonfigurować go przy użyciu co najmniej jednego punktu końcowego. Podczas definiowania punktu końcowego routingu wybierasz powiązanie WCF i jedną 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 korzystają z usługi WSHttpBinding (jednokierunkowe i żądanie-odpowiedź). Zwróć uwagę, że tak samo jak w przypadku konfigurowania dowolnej innej usługi WCF:

<Konfiguracji>

  <System.servicemodel>

    <services>

      <--ROUTING SERVICE —>

      <service behaviorConfiguration="routingData"

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

        <Hosta>

          <baseAddresses>

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

          </baseAddresses>

        </Hosta>

        <!--

          Zdefiniuj i skonfiguruj punkt końcowy, na który ma nasłuchiwać router i

          Kontrakt, którego chcemy użyć. Dostarczone kontrakty routera to:

          ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter i

          IDuplexSessionRouter.

         -->

        <endpoint address="oneway-basic"

                  binding="basicHttpBinding"

                  name="onewayEndpointBasic"

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

        <endpoint address="oneway-ws"

                  binding="wsHttpBinding"

                  name="onewayEndpointWS"

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

        <endpoint address="twoway-basic"

                  binding="basicHttpBinding"

                  name="reqReplyEndpointBasic"

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

        <endpoint address="twoway-ws"

                  binding="wsHttpBinding"

                  name="reqReplyEndpointWS"

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

      </service>

    </Usług>

    ...

Interfejsy ISimplexDatagramRouter i IRequestReplyRouter definiują ogólne definicje kontraktów usługi typu "jednokierunkowy" i "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)]

interfejs publiczny ISimplexDatagramRouter

{

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

    IAsyncResult BeginProcessMessage(komunikat komunikatu, wywołanie zwrotne AsyncCallback,

        stan obiektu);

    void EndProcessMessage(Wynik IAsyncResult);

}

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

    SessionMode = SessionMode.Allowed)]

interfejs publiczny IRequestReplyRouter

{

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

        ReplyAction = "*")]

    [GenericTransactionFlow(TransactionFlowOption.Allowed)]

    IAsyncResult BeginProcessRequest(komunikat, wywołanie zwrotne AsyncCallback,

        stan obiektu);

    Message EndProcessRequest(IAsyncResult result);

}

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 rozsyłania w celu określenia miejsca przekazywania komunikatu.

Konfigurowanie usługi RoutingService przy użyciu 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 usługę RoutingBehavior do zarządzania filtrami komunikatów routingu. Najpierw musisz włączyć usługę 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>

        <behavior name="routingData">

          <serviceMetadata httpGetEnabled="True"/>

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

          <routing filterTableName="filterTable1" />

        </Zachowanie>

      </Servicebehaviors>

    </Zachowania>

    ...

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 musimy 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ć trasę. Te docelowe punkty końcowe są definiowane w sekcji konfiguracji klienta> WCF<, ponieważ usługa RoutingService jest zasadniczo "klientem", gdy przekazuje komunikaty do usługi docelowej. W poniższym przykładzie pokazano, jak zdefiniować dwa docelowe punkty końcowe, do których możemy kierować:

<konfiguracja>

    ...

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

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

    <klient>

      <endpoint name="CalculatorService1"

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

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

      <endpoint name="CalculatorService2"

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

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

    </Klienta>

    ...

Teraz możemy zdefiniować rzeczywistą tabelę filtrów, która określi logikę routingu w czasie wykonywania. Pozycje tabeli filtru są definiowane w elemecie <filterTables> . Każdy wpis w <tabeli filterTable> definiuje mapowanie między routingiem "filter" i docelowym punktem końcowym. Definiujesz "filtry", których chcesz użyć w elemecie <filters> — każdy <wpis filtru> określa, jakiego typu filtru chcesz używać wraz z danymi specyficznymi dla filtru (na przykład wartością akcji, wyrażeniem XPath itp.).

W poniższym przykładzie pokazano, jak skonfigurować tabelę filtrów za pomocą pojedynczego filtru, który jest mapowany na punkt końcowy CalculatorService1. W takim przypadku filtr "MatchAll" odpowiada wszystkim przychodzącym komunikatom:

<Konfiguracji>

    ...

    <sekcja --ROUTING —>

    <Routingu>

      <-- Zdefiniuj filtry, których chcemy użyć routera. -->

      <Filtry>

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

      </Filtry>

      <-- Zdefiniuj tabelę filtru zawierającą filtr matchAll —>

      <filterTables>

        <filterTable name="filterTable1">

            <-- Mapuj filtr na punkt końcowy klienta, który został wcześniej zdefiniowany.

                 Komunikaty pasujące do tego filtru będą wysyłane do tego miejsca docelowego. -->

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

        </filterTable>

      </filterTables>

    </Routingu>

  </System.servicemodel>

</Konfiguracji>

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 usługi 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 routingu

Rysunek 15. Klient przeznaczony dla usługi RoutingService pod adresem 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 usługa WCF udostępnia filtr ActionMessageFilter, który umożliwia dopasowanie określonych wartości WS-Addressing "action". WCF udostępnia również element EndpointAddressMessageFilter, EndpointNameMessageFilter i PrefixEndpointAddressMessageFilter, który umożliwia dopasowanie określonych szczegółów 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 usługa WCF 4 umożliwia również definiowanie niestandardowych filtrów komunikatów, co może być jednym z głównych punktów rozszerzalności usługi RoutingService.

Przyjrzyjmy się przykładowi wykonywania routingu opartego na zawartości na podstawie wartości akcji. Załóżmy, że chcemy skierować połowę operacji CalculatorService do aplikacji CalculatorService1 i drugą połowę do aplikacji 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órych chcemy użyć routera. -->

     <Filtry>

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

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

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

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

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

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

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

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

      </Filtry>

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

    </Routingu>

  </System.servicemodel>

</Konfiguracji>

Teraz po uruchomieniu rozwiązania i wykonaniu 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 kalkulatoraService1

Rysunek 18. Dane wyjściowe kalkulatoraService2

Klasa 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ęść przychodzącego komunikatu, 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 zapisywania ostatniego przykładu przy użyciu wyrażeń XPath:

<Konfiguracji>

    ...

    <sekcja --ROUTING —>

    <Routingu>

      <-- Zdefiniuj filtry, których chcemy użyć routera. -->

     <Filtry>

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

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

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

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

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

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

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

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

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

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

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

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

      </Filtry>

      <namespaceTable>

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

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

      </namespaceTable>

      <filterTables>

        <filterTable name="filterTable1">

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

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

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

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

        </filterTable>

      </filterTables>

    </Routingu>

  </System.servicemodel>

</Konfiguracji>

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ń prefiksów przestrzeni nazw przy użyciu <elementu namespaceTable> . Jest to konieczne, jeśli chcesz użyć prefiksów przestrzeni nazw w wyrażeniach XPath, takich jak powyżej. Ponowne uruchomienie rozwiązania za pomocą tej konfiguracji daje takie same wyniki jak poprzednio (zobacz Rysunek 17 i Rysunek 18).

Tę technikę filtru XPath należy użyć w dowolnym momencie, aby 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 w 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 netTcpBinding lub NetNamedPipeBinding.

Zobaczmy, jak skonfigurować usługę RoutingService do obsługi tego scenariusza. Pozostawimy konfigurację punktu końcowego routingu tak samo jak powyżej, co umożliwia konsumentom komunikowanie się z usługą RoutingService za pośrednictwem metody 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:

<konfiguracja>

    ...

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

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

    <klient>

      <endpoint name="CalculatorService1"

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

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

      <endpoint name="CalculatorService2"

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

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

    </Klienta>

    ...

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 posiadanie list punktów końcowych "kopii zapasowej".

W poniższym przykładzie pokazano, jak zdefiniować listę punktów końcowych kopii zapasowej w ramach <elementu backupLists> , który możemy skojarzyć z naszymi wpisami tabeli filtrów:

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

    </Routingu>

  </System.servicemodel>

</Konfiguracji>

Zwróć uwagę, że w tym przykładzie skonfigurowaliśmy wszystkie wpisy tabeli filtrów do przekazywania do elementu CalculatorService1, ponieważ usługa CalculatorService2 jest teraz punktem końcowym "kopii zapasowej", który będzie używany tylko wtedy, gdy funkcja CalculatorService1 powoduje wyjątek TimeoutException, 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 pokazano 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" />

      </Filtry>

      <filterTables>

        <filterTable name="filterTable1">

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

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

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

        </filterTable>

      </filterTables>

    </Routingu>

  </System.servicemodel>

</Konfiguracji>

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 znajduje się w komunikatach.

To zachowanie multiemisji składa się z mostkowania protokołu i obsługi błędów omówionych w poprzednich sekcjach. Jedynym problemem jest to, że multiemisji działa tylko w przypadku komunikacji jednokierunkowej lub dwukierunkowej, ale nie komunikacji typu żądanie-odpowiedź, 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 oferuje 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 nie tylko. Nie będziemy mieli 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 wprowadza go do oficjalnej struktury. 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 generowanie kodu po stronie klienta — znacznie ułatwia użytkownikom ustalenie, jak rozpocząć pracę z usługą — dlatego zazwyczaj dobrym pomysłem jest włączenie tej nowej funkcji.

Jeśli 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 przy użyciu 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>

        <behavior name="HelpBehavior">

          <webHttp helpEnabled="true" />

        </Zachowanie>

      </endpointBehaviors>

    </Zachowania>

    <services>

      <service name="CounterResource">

        <endpoint behaviorConfiguration="HelpBehavior"

                  binding="webHttpBinding"

                  contract="CounterResource" />

      </service>

    </Usług>

  </System.servicemodel>

</Konfiguracji>

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

Rysunek 19. Strona automatycznej pomocy dla 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żesz 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 odpowiednie przykładowe wystąpienie XML, którego użytkownicy mogą używać do integracji z usługą. Konsumenci mogą używać schematu do generowania odpowiednich typów z możliwością 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 zwiększa możliwości odnajdywania 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 żądania/odpowiedzi, a opis zawsze będzie 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. Jednak aby zdać sobie sprawę z tej korzyści, należy wykorzystać różne nagłówki buforowania HTTP w żądaniach i komunikatach odpowiedzi. Można to zrobić w ramach operacji usługi WCF, ręcznie korzystając z nagłówków żądań/odpowiedzi za pośrednictwem wystąpienia WebOperationContext, ale nie jest to proste, aby zrobić to poprawnie.

W związku z tym program WCF 4 jest wyposażony w prostszy model do kontrolowania buforowania za pomocą atrybutu [AspNetCacheProfile], który można deklaratywne stosować 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ższej 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>

</Konfiguracji>

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, której dotyczy ta usługa, 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 WCF zajmuje się wstrzyknięciem kontrolki pamięci podręcznej HTTP, daty, wygasania i różnicy nagłówków HTTP w odpowiedzi, które klienci mogą również wykorzystać do określenia odpowiednich semantyki buforowania wokół przyszłych rund.

Wybór formatu komunikatu

Jeśli spojrzysz wstecz na rysunek 19, zauważysz, że usługa CounterResource obsługuje zarówno formaty XML, jak i JSON dla operacji GET, POST i PUT. Jest to możliwe od czasu, gdy program WCF 3.5 za pośrednictwem właściwości RequestFormat i ResponseFormat można znaleźć w atrybutach [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 i drugą dla wersji JSON — jak pokazano tutaj:

...

[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ć zarówno formaty XML, jak 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 HTTP "Accept", co jest lepszym sposobem jego wykonania. Wyjaśnij mi, 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 w warstwie WebHttpEndpoint w warstwie Standardowa jest zaznaczony format automatyczny, jak pokazano tutaj:

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

</Konfiguracji>

Dzięki temu usługa jest teraz w stanie obsługiwać i zwracać komunikaty XML lub JSON. Określa format, który ma być używany przez pierwsze sprawdzenie nagłówka HTTP Accept znalezionego 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 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 pomocą nagłówków HTTP Content-Type i Accept. Nagłówek Content-Type określa format w komunikacie żądania, podczas gdy 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:

Zaakceptuj: 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 wrócić do kodu JSON z naszej nowej i ulepszonej usługi.

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

Program WCF 4 udostępnia również nowe interfejsy API, które ułatwiają jawne określanie formatu komunikatów 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. Jeśli nie znajdzie parametru "format", po prostu będzie 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 jest

    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;

        }

        else

        {

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

               formatQueryStringValue), HttpStatusCode.BadRequest);

        }

    }

    return HandleGet();

}

W końcu te nowe funkcje sprawiają, że nie trzeba już kodować typu formatu komunikatów do kontraktów operacji [WebGet] i [WebInvoke], tak 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, dzięki czemu można automatycznie mapować 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 wysył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 FaultException<T> w programie WCF, ale można określić kod stanu HTTP i typ szczegółów, aby podać 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;

    }

    else

    {

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

           format), HttpStatusCode.BadRequest);

    }

}

Ta nowa funkcja sprawia, że jest znacznie 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 możliwościami 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 opracowywania. W miarę rozwoju i rozwoju 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 na klasę 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łujem funkcję RouteTable.Routes.Add dwa razy, aby dodać nowe trasy 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 w środowisku programu Visual Studio 2010 za pomocą prostego kliknięcia przycisku. W przypadku zespołów produktów firmy Microsoft jest to wspaniałe, 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 — jeden 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, która generuje, używa większości nowych funkcji WCF 4 wyróżnionych w tej sekcji.

Więcej informacji

Oprócz omówionych tutaj funkcji WCF 4 jest dostępnych kilka bardziej zaawansowanych funkcji REST i nowych rozszerzeń interfejsu API WCF, które upraszczają obsługę niestandardowych formatów komunikatów (nie XML lub JSON), zwracanie "widoków" opartych na szablonach przy użyciu nowej funkcji T4, implementowanie warunkowej obsługi get i ETag, implementowanie optymistycznej współbieżności i generowanie linków wychodzących.

Aby uzyskać więcej informacji na temat wszystkich tych nowych funkcji programu WCF 4, w tym tych, których nie mieliśmy 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ół dostarczył dokładnie 12-częściowej serii blogów, która prowadzi przez każdą nową funkcję jeden wpis w blogu naraz, wraz z dużą ilością przykładowego kodu i instrukcji 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 mocno 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 osób piszących logikę. To, co WF ostatecznie daje ci platformę do pisania własnych języków, definiując własną bibliotekę działań domeny biznesowej. Następnie zapewnia projektantowi wizualnemu tworzenie tych działań w programach oraz środowisko uruchomieniowe, które wie, jak zarządzać wykonywaniem tych programów.

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 przez utrzymywanie programu 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, co zwalnia zasoby systemowe, z których korzysta.

Rysunek 23. Usługi przepływu pracy

To, co sprawia, że WF różni się od innych platform programistycznych jest to, że zapewnia te funkcje, jednocześnie umożliwiając programowanie przy użyciu sekwencyjnej logiki programowania sterowania przepływem, co jest zwykle znacznie łatwiejsze dla deweloperów czytania i pisania kodu do zrozumienia.

Jeśli tworzysz usługi WCF, które mają charakter długotrwały lub możesz skorzystać z niektórych innych korzyści opisanych właśnie przeze mnie, możesz zaimplementować usługi WCF przy użyciu przepływu pracy WF. Za pomocą usługi WF można koordynować logikę korzystania z innych usług zewnętrznych.

Rysunek 23 ilustruje te pojęcia.

Chociaż było to możliwe od wersji .NET 3.5, platforma .NET 4 poczyniła znaczne postępy w ulepszaniu środowiska dewelopera i udostępnia niektóre z potrzebnych funkcji, których brakowało na platformie .NET 3.5.

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

Tworzenie pierwszej usługi przepływu pracy

Aby dać ci wrażenie na nowe środowisko deweloperskie usług przepływu pracy, przedstawię kompletny przykład kompilowania go przy użyciu platformy .NET 4 i nowego projektanta programu Visual Studio 2010.

Jeśli otworzysz program Visual Studio 2010 i wybierzesz 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ń WCF "Messaging" (zobacz Przybornik na rysunku 25).

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

Szkieletowa usługa przepływu pracy dostarczona z tym szablonem projektu zawiera działanie Odbierz, a następnie działanie Wyślij. Zwróć uwagę, że działanie Odbierz zawiera właściwość OperationName i jest obecnie ustawiona na "GetData". Ma również właściwość Content do powiązania komunikatu przychodzącego z zmienną lokalną zdefiniowaną w działaniu Sekwencja — w tym przypadku zmienna jest nazywana "danymi" i jest typu Int32 (zobacz okno Zmienne poniżej usługi 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 okno Właściwości po prawej stronie na rysunku 25).

Dostosujmy tę usługę przepływu pracy trochę. 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 Odbierz na "SayHello". Na koniec zdefiniuję nową zmienną o nazwie "personName" typu String w ramach sekwencji.

Następnie powiążę właściwość Content działania Odbierz do zmiennej "personName", jak pokazano na rysunku 26. Następnie powiążę właściwość Content działania Wyślij do ciągu w formacie "hello {0}!" Wstaw 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 Eksplorator rozwiązań i wybierając pozycję "Otwórz za pomocą..." a następnie "Edytor XML". Dzięki temu można przyjrzeć się pierwotnej 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, dzięki czemu 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 klawisza F5 w programie Visual Studio 2010. Naciśnięcie klawisza 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 może dynamicznie tworzyć definicję WSDL dla usługi, sprawdzając działania Wysyłanie i odbieranie używane w definicji przepływu pracy oraz typy komunikatów, które wysyłają i odbierają.

Jest to prosty przewodnik po tworzeniu 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ń Wysyłania/odbierania 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 eliminuje potrzebę dodatkowych plików svc. Będziemy nadal 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 w przypadku wielu wystąpień usług działających 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, który omówiliśmy w poprzedniej sekcji, pokazano, jak hostować usługi 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żyto podejścia "zero config", można skonfigurować usługi przepływu pracy w Web.config tak 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>

    <services>

      <service name="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ń WCF. W poniższym przykładzie pokazano, jak skonfigurować tę usługę przepływu pracy z kilkoma standardowymi zachowaniami WCF:

<Konfiguracji>

  <System.servicemodel>

    <services>

      <service name="HelloWorldWorkflowService"

        behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

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

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

                  contract="IHelloWorld"/>

      </service>

     </Usług>

    <Zachowania>

      <Servicebehaviors>

        <behavior name="HelloWorldWorkflowService.Service1Behavior">

          <serviceDebug includeExceptionDetailInFaults="False" />

          <serviceMetadata httpGetEnabled="True"/>

        </Zachowanie>

      </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ływów 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.

Samoobsługowe hostowanie za pomocą elementu WorkflowServiceHost

Mimo że platforma .NET 3.5 została wyposażona w klasę WorkflowServiceHost do hostowania usług przepływu pracy, konieczne było przeprojektowanie wszystkich zmian 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"));

Hosta. AddDefaultEndpoints();

Hosta. Description.Behaviors.Add(

    new ServiceMetadataBehavior { HttpGetEnabled = true });

Hosta. 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 tak proste, jak w przypadku dowolnej usługi WCF.

Workflowcontrolendpoint

Hostowanie usługi przepływu pracy zajmuje się inicjowaniem środowiska uruchomieniowego programu WF i aktywowaniem nowych wystąpień przepływu pracy podczas aktywowania komunikatów przybywających przez jeden z uwidocznionych punktów końcowych. Oprócz tej podstawowej funkcjonalności 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 element WorkflowControlEndpoint, który można uwidocznić w usługach przepływu pracy.

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

...

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

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

Hosta. AddDefaultEndpoints();

WorkflowControlEndpoint wce = new WorkflowControlEndpoint(

    nowy NetNamedPipeBinding(),

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

Hosta. AddServiceEndpoint(wce);

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

    <services>

      <service name="HelloWorldWorkflowService"

          behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

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

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

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

      </service>

      ...

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 zawiera dwie działania obsługi komunikatów — Wysyłanie i odbieranie — do wysyłania i odbierania komunikatów przy użyciu usługi 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ń wysyłania/odbierania 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 Odbieranie należy nadać jej nazwę operacji i zamapować 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="")]

public, klasa Person

{

    [DataMember]

    identyfikator ciągu publicznego;

    [DataMember]

    public string FirstName;

    [DataMember]

    ciąg publiczny 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 zamapować działania ReceiveRequest i SendResponse na zmienną personMsg za pomocą właściwości "Content". Aby to zrobić, po prostu zaznacz każde działanie i naciśnij przycisk "Zawartość", aby wyświetlić okno "Definicja zawartości". Następnie wprowadź ciąg "personMsg" w polu tekstowym "Dane wiadomości" i "Osoba" w polu tekstowym "Typ wiadomości". Należy to zrobić w przypadku 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 okno Właściwości po wybraniu działania 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 o typie 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 Odbieranie w celu zaimplementowania operacji request-reply 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 ramach przepływu 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 redagują 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ę do sekwencji zawierającej działanie Wyślij lub Odbierz, a następnie odpowiednie działanie "odpowiedz".

Dodawanie odwołania do usługi

Aby jeszcze 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, jak można się tego spodziewać, 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 pobierze plik WSDL i wygeneruje 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, aby dodać odwołanie 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 ramach przepływów pracy w celu wywołania usługi zewnętrznej.

Korelacja

W przypadku tworzenia systemów składających się z długotrwałych usług przepływu pracy często występuje wiele wystąpień pojedynczej usługi przepływu pracy, które jednocześnie oczekują na wystąpienie tego samego zdarzenia (np. oczekiwanie na nadejście określonego komunikatu przed kontynuowaniem). Wyzwaniem w tym scenariuszu jest to, że potrzebujesz sposobu skorelowania komunikatu przychodzącego z odpowiednim wystąpieniem przepływu pracy. Zazwyczaj sposobem określania prawidłowego wystąpienia przepływu pracy jest sprawdzenie zawartości komunikatu przychodzącego.

Platforma .NET 4 zawiera zaawansowaną funkcję korelacji komunikatów opartą na zawartości, której można używać w połączeniu z właśnie omówionymi działaniami Wyślij i Odbierz. Implementacja tej funkcji koncentruje się na tym, co jest znane jako "uchwyty korelacji", kolejna nowa koncepcja 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ść CorrelatesWith 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 będzie mapowany na komunikat przetwarzany przez to konkretne działanie (np. element SSN w jednym komunikacie może skorelować 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, odbiera komunikat Osoba 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 kolejne odbieranie, po którym następuje inna funkcja SendReply. Dam działanie Odbierz nazwę operacji "Zakończ", a my 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 podać pozdrawianie (i może to potrwać kilka minut, godzin lub dni, w którym może utrwałyć się przepływ pracy). Gdy klient wywołuje metodę Zakończ dostarczanie pozdrowień, przepływ pracy tworzy powitanie przy użyciu salutacji 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ńczenia, więc na pewno musimy skorelować komunikat Zakończ z poprzednim komunikatem SayHello. Ponieważ tak jest, muszę skojarzyć działanie Odbierz dla "Finish" z tym samym uchwytem korelacji, który określono w działaniu "SayHello" (nameHandle).

Teraz przyjrzyjmy się zawartości wiadomości, 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="")]

public, klasa Person

{

    [DataMember]

    ciąg publiczny FirstName { get; set; }

    [DataMember]

    ciąg publiczny LastName { get; set; }

}

[DataContract(Przestrzeń nazw = "")]

powitanie klasy publicznej

{

    [DataMember]

    publiczny ciąg salutacji { get; set; }

    [DataMember]

    ciąg publiczny NameKey { get; set; }

}

Działanie Odbierz dla elementu "SayHello" jest skonfigurowane do używania komunikatu Osoba, a działanie Odbieranie dla komunikatu "Finish" jest skonfigurowane do korzystania z komunikatu Greeting. Założymy, że wartość LastName jest zawsze unikatowa, więc możemy użyć jej jako unikatowej wartości dla korelacji. W związku z tym, gdy klient wyśle komunikat "Finish", musi podać tę samą wartość LastName użytą 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" Odbierz. Wybierz więc działanie "SayHello" Odbierz i naciśnij przycisk obok pola tekstowego "CorrelationInitializers".

W tym miejscu musisz wybrać opcję "Inicjator korelacji zapytania" z pola listy rozwijanej, a następnie należy 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 Odbieranie "Zakończ" skorelowane z tym samym uchwytem. Wybierz działanie "Zakończ" Odbierz i naciśnij przycisk "Koreluj". Następnie określ uchwyt "handle" dla uchwytu "CorrelatesWith", 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 elementu "Finish"

Oznacza to ostatecznie, że element LastName w komunikacie Person musi być zgodny z elementem NameKey w komunikacie Powitanie 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 elementu "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żywaną 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 programie .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 zaawansowane podejście do wykonywania tych samych czynności.

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

To przybliża nas do końca naszego zakresu usług przepływu pracy. Udało nam się tylko zdrapać powierzchnię usług przepływu pracy w tym dokumencie, ale będzie można 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, o których mówiliśmy 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 za pośrednictwem usługi DataContractResolver, możliwość obsługi konkurencyjnych użytkownikó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 podstaw. 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, WCF 4 udostępnia abstrakcyjną klasę DataContractResolver, z której można korzystać, aby zaimplementować własny algorytm rozpoznawania typów niestandardowych.  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,

        Type declaredType, DataContractResolver knownTypeResolver)

    {

        ... // implementowanie mapowania

    }

    Używane w serializacji

    Mapuje dowolny typ na nową reprezentację xsi:type

    public override bool TryResolveType (typ typu, typ zadeklarowany typ, typ, typ zadeklarowany,

        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 klasy DataContractSerializer do serializacji/deserializacji obiektów, zostanie wywołana niestandardowa funkcja DataContractResolver w celu przeprowadzenia niestandardowej rozpoznawania typów.

Aby wstrzyknąć niestandardowe daneContractResolver do środowiska uruchomieniowego WCF w tle, musisz napisać zachowanie kontraktu WCF, które podłącza się do elementu DataContractSerializerOperationBehavior i zastępuje domyślny program rozpoznawania. Zestaw SDK platformy .NET 4 zawiera kompletny przykład pokazujący, 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 modułu DataContractSerializer, kontrolować dokładnie, które typy są 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 polecenia NetMsmqBinding przy użyciu kolejek transakcyjnych i zarejestrowania operacji usługi WCF w transakcji MSMQ. Gdy wyjątki są zgłaszane podczas przetwarzania komunikatu, usługa 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 otrutych lub kolejki utraconych wiadomości 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 generuje dużo odczytu/zapisu w kolejkach, co wprowadza większe obciążenie i złożoność. Innym problemem jest to, że nie ma możliwości zapewnienia, że ta sama usługa przetwarza komunikat przy następnym pobraniu go z kolejki (np. nie ma możliwości zablokowania komunikatu o określonej usłudze), co jest gwarancją, którą można wykonać w niektórych scenariuszach.

Aby rozwiązać te problemy, 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 nie tak, a wyjątek zostanie zgłoszony, pozostaje w kolejce. Usługi mogą również "zablokować" komunikaty, aby ponowić próbę przetworzenia w późniejszym momencie. Funkcja ReceiveContext udostępnia mechanizm "ukończenia" komunikatu po przetworzeniu go, aby można go było usunąć z kolejki.

Takie podejście upraszcza kilka frontów, ponieważ komunikaty nie są już odczytywane i ponownie zapisywane w kolejkach za pośrednictwem sieci, a poszczególne komunikaty nie odbijają się w różnych wystąpieniach usługi podczas przetwarzania. Przyjrzyjmy się prostemu przykładowi, aby zilustrować, jak to działa.

W poniższym przykładzie pokazano, jak używać funkcji 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("Nie zainstalowano/znaleziono elementu ReceiveContext na tym komputerze".");

        Zwraca;

    }

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

    {

        receiveContext.Complete(TimeSpan.MaxValue);

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

            firstNumber * secondNumber);

    }

    else

    {

        receiveContext.Abandon(TimeSpan.MaxValue);

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

    }

    receiveCount++;

}

...

Przy założeniu pomyślnego przekazania wywołamy metodę ReceiveContext.Complete, aby zakończyć przetwarzanie komunikatu powodującego jego usunięcie z kolejki bazowej. W przeciwnym razie wywołamy metodę Abandon, która pozostawia komunikat 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 bardziej szczegółowego 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 opakowującego lub 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 musisz utworzyć powiązanie niestandardowe, aby można było z niego korzystać.

Zestaw SDK platformy .NET 4 zawiera kompletny przykład ilustrujący sposób definiowania powiązania niestandardowego korzystającego z klasy powiązania 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óżne technologie zarządzania znalezione w systemie Windows Server, oferując lepszy model dla platformy.

W przypadku funkcji ETW dostawcy zdarzeń zapisują zdarzenia do sesji i sesji mogą opcjonalnie utrwalać te zdarzenia w dzienniku. Użytkownicy 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, który ilustruje sposób wykorzystania tej nowej architektury śledzenia o wysokiej wydajności w połączeniu z usługami WCF.

Podsumowanie

Program WCF 4 oferuje wiele ulepszeń i kilka zupełnie nowych funkcji, które dotyczą niektórych z dzisiejszych najbardziej typowych scenariuszy komunikacji. Przede wszystkim program WCF 4 staje się łatwiejszy 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 same stanowią platformę WCF oprócz 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, program WCF 4 zapewnia zaawansowaną integrację z platformą WF w celu zapewnienia nowego modelu 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 platformie WCF i obsłudze projektanta znalezionego 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 zaoferować spójny model programowania, który zapewnia najlepsze światy, które 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 ukierunkowane na przetwarzanie w chmurze, platformę Windows Azure, platformę WCF i architekturę REST. Aaron spędził lata na pisaniu, mówieniu i nauczaniu profesjonalnych deweloperów na całym świecie. Możesz dotrzeć do niego pod adresem http://pluralsight.com/aaron i http://twitter.com/skonnard.

Dodatkowe zasoby