Ten artykuł pochodzi z serii przygotowań do egzaminu 70-503: Windows Communication Foundation.
Istnieje oraz zapewnie będzie istniała nadal potrzeba tworzenia serwisów, które mogą otrzymywać komunikaty w postaci dokumentu Plain old XML (POX). Serwis musi umieć sprawdzić taki komunikat bez dokładniej wiedzy na temat jego struktury. Wiele aplikacji klienckich nie potrafi utworzyć komunikatu sformatowanego jako SOAP. Przykładowo przeglądarki internetowe nie mają wsparcia dla protokołów opartych na SOAP. Potrafią one jedynie wykonać żądanie HTTP. W tych wypadkach treścią żądania jest zwykły ciąg znaków, lub XML. W takim wypadku serwis musi umieć zaakceptować komunikat, bez względu na jego format, po czym należy obsłużyć go ręcznie. Po sprawdzeniu go możemy podjąć decyzję na temat przekazania go w inne miejsce.
Dla WCF obsługa tej technologii to zdolność do akceptacji opcjonalnego komunikatu (ang. arbitrary message) w przeciwieństwie do tych ściśle określonych. Kluczową rolę ogrywa tu klasa Message, która zapewnia dostęp do informacji. W celu obsłużenia komunikatu pozbawionego typu można wykorzystać wartości Action i SoapAction, które mogą zostać załączone w żądaniu. SoapAction wskazuje nazwę metody serwisu, która ma zostać wywołana. Dotyczy komunikatów w formacie SOAP. Action dostarcza URI, który ma wskazać na akcję serwisu. Możemy ręcznie przypisać go do konkretnej akcji:
1: [ServiceContract]
2: public interface IMessageHandler
3: {
4: [OperationContract(Action="uri://service/description")]
5: Message HandleThisMessage(Message request);
6: }
Parametr ten nie jest wymagany i może się okazać, że komunikat, który dotrze do serwisu nie będzie go posiadał. Poprzez ustawienie właściwości Action na gwiazdkę, możemy obsłużyć wszystkie nierozpoznane lub nieistniejące akcje. Przypiszemy je do konkretnej metody:
1: [ServiceContract]
2: public interface IMessageHandler
3: {
4: [OperationContract(Action="*")]
5: Message HandleAllMessages(Message request);
6: }
Zwracany komunikat ma typ Message. Jeżeli nie potrzebujemy odsyłania odpowiedzi do klienta możemy ustawić parametr IsOneWay na true:
1: [ServiceContract]
2: public interface IMessageHandler
3: {
4: [OperationContract(Action="*", IsOneWay=true)]
5: void HandleAllMessages(Message request);
6: }
Ciało (ang. body) obiektu typu Message może zostać przetworzone wyłącznie raz. Po przetworzeniu stan zostanie ustawiony na wartość Read, a następne próby dostępu spowodują wyrzucenie wyjątku. Ciało komunikatu możemy otrzymać korzystając z metody GetReaderAtBodyContents, która zwraca obiekt typu XmlReader. Komunikat ma właściwość State, która wskazuje jego stan. Na początku jest to Created, po przeczytaniu zamieniany jest na Read. Przykład czytania:
1: Message HandleMessage(msg As Message)
2: {
3: XmlReader body = msg.GetReaderAtBodyContents();
4: while (body.Read())
5: {
6: string bodyText = body.ReadString();
7: // Process the body
8: }
9: body.Close();
10: // Rest of processing
11: }
Alternatywnym sposobem jest wykorzystanie metody GetBody, która przyjmuje jako parametr klasę .NET, która została użyta, kiedy komunikat był tworzony po stronie klienta:
1: public void HandleAllMessage(Message request)
2: {
3: Customer c = request.GetBody<Customer>();
4: // Process the incoming customer object
5: }
Ciało komunikatu nie jest jedyną częścią, którą możemy się zainteresować. Przykładowo metod IsEmpty sprawdzi, czy ciało istnieje, IsFault, czy jest to komunikat SOAP typu fault, właściwość Version poda wersję SOAP. Właściwość Header zawiera listę nagłówków powiązanych z komunikatem. Ma ona typu MessageHeaders, a jest to kolekcja obiektów MessageHeaderInfo. Poszczególny nagłówek możemy otrzymać przez indeks, lub iterując po kolekcji. Właściwości klasy MessageHeaderInfo, to:
- Actor – zamierzony cel nagłówka,
- IsReferenceParameter – określa, czy parametr jest powiązany z elementem ReferenceParameters w specyfikacji WS-Addressing,
- MustUnderstand – określa, czy serwis przetwarzający komunikat musi rozumieć nagłówek,
- Name – nazwa nagłówka komunikatu,
- Namespace – przestrzeń nazw dla nagłówka komunikatu,
- Relay – określa, czy nagłówek może zostać przekazany dalej.
Tworzenie komunikatu
Omówiliśmy przetwarzanie komunikatów. Innym zagadnieniem jest ich tworzenie. Poniższy przykład demonstruje przebieg tego procesu:
1: Customer c = new Customer();
2: c.Name = "Contoso";
3: c.City = "Redmond";
4: MessageVersion version = MessageVersion.Soap12;
5: Message m = Message.CreateMessage(version, "HandleAllMessage", c);
Wykorzystana została tu statyczna metoda klasy Message – CreateMessage.