Usługi Web stają się coraz popularniejszymi składnikami rozwiązań informatycznych. Są uniwersalnym mechanizmem komunikacji pomiędzy systemami ułatwiając ich integrację przy znacznie niższych nakładach (zarówno finansowych jak i czasowych). Równocześnie (i to jest główna zaleta całej infrastruktury), podstawą działania usług są standardowe protokoły internetowe. Dzięki temu bez trudu informacje mogą być przesyłane, a równocześnie dostęp do nich może mieć każdy, kto ma dostęp do Internetu.
Z punktu widzenia aplikacji, usługa Web jest jeszcze jednym sposobem, w jaki można wywoływać interfejsy obiektów, czy uruchamiać określoną funkcjonalność modułu. Podstawę usług Web stanowi 5 standardów:
HTTP – służy do przesyłania komunikatów (o ten sam protokół oparta jest komunikacja serwerów WWW)
XML – służy do „zakodowania” informacji przy użyciu odpowiednich znaczników
SOAP – definiuje format dokumentu XML w tym sposób kodowania parametrów wywoływanej usługi. Standard precyzuje, w jaki sposób przekazywana jest nazwa usługi, jak kodowane są typy proste, jak zapisywane tablice itp.
WSDL – jest specjalnym „językiem” – także opartym o XML – który opisuje usługę Web (w tym – jej parametry) w sposób zrozumiały dla człowieka (lub – odpowiedniego narzędzia w pakiecie programistycznym). W praktyce WSDL wystarczy, by wiedzieć, jakie parametry należy przekazać do danej usługi Web. Warto, aby usługa Web potrafiła „zwrócić” WSDL – lub by odpowiedni plik był umieszczony w ustalonym miejscu. Wtedy każdy klient, który chce z tej usługi skorzystać, może poznać odpowiednią specyfikację.
UDDI – to globalny katalog – repozytorium, gdzie umieszczane są informacje o branżowych usługach Web. Klient może odszukać interesującą go usługę przeglądając jeden z istniejących systemów taksonomicznych, opisać usługę przy użyciu dowolnych słów kluczowych itp. Microsoft udostępnia 2 repozytoria UDDI. Jedno – przeznaczone do testów znajduje się pod adresem http://test.uddi.microsoft.com/default.aspx. Drugie - przeznaczone do publikacji „prawdziwych” usług Web znajduje się pod adresem http://uddi.microsoft.com/default.aspx
Tak naprawdę cała komunikacja związana z usługami Web odbywa się przy użyciu formatu tekstowego. Nic nie stoi na przeszkodzie, żeby większość komunikatów generować ręcznie – w podobny sposób jak np. skrypty CGI generują całe strony HTML. Nie jest to jednak zbyt wygodne.
W przypadku programów pisanych w .NET wystarczy przy deklaracji funkcji dodać atrybut WebMethod() – wtedy zostanei wygenerowane odpowiednie „dowiązanie” do protokołu SOAP i dana funkcja stanie się usługą Web.
Utworzenie nowej usługi Web najlepiej jest zacząć od stworzenia nowego projektu – typu ASP.NET Web Service. Może to być projekt w VB.NET, C# albo też w J#. Po określeniu nazwy katalogu wirtualnego na serwerze IIS, VS.NET tworzy szkielet usługi Web. W tym przykładzie zakładam, że utworzony projekt ma nazwę SampleNewsService i jest pisany w VB.NET.
Tworzona usługa Web ma za zadanie zwracać dowolne informacje tekstowe (jako tablicę typu String()) – z takiej usługi korzysta artykuł poświęcony GDI+ i przykład news_ticker. Główna metoda ma przyjmować dwa parametry – typ zwracanych wiadomości, a także maksymalną liczbę wiadomości, jakie klient chce otrzymać. W tym przykładzie funkcja zwraca 2 typy wiadomości. Jeżeli parametr type jest równy 1, zwracana jest tablica zawierająca łańcuchy postaci Client request: Type1, 100_1 ... Client request: Type1, 100_<tu liczba wiadomości>. Jeżeli type=2, to usługa Web ściąga stronę HTML Narodowego Banku Polskiego zawierającą aktualne kursy walut, przetwarza ją i generuje wiadomości o kursach walut.
Poniżej przedstawiona jest definicja szkieletu usługi Web:
<WebService(Namespace:="http://www.vbfaq.pl/SampleNewsServices")> _
Public Class SampleNewsServices
Inherits System.Web.Services.WebService
#Region " Web Services Designer Generated Code "
[...]
#End Region
Private Function SampleItems(ByVal news_count As Integer) As String()
End Function
Private Function GetExchange(ByVal news_count As Integer) As String()
<WebMethod(Description:="Metoda pobiera wiadomości danego typu i zwraca tablicę String()")> Public Function GetNews(ByVal type As Integer, ByVal news_count As Integer) As String()
'Dla zabezpieczenia - aby za dużo danych nie żądać
If news_count > 100 Then news_count = 100
If news_count < 0 Then news_count = 1
Select Case type
Case 2
Return GetExchange(news_count)
Case 1
Case Else
Return SampleItems(news_count)
End Select
Atrybut <WebMethod()> wystarczy, by dana funkcja (tu – GetNews) stała się usługą Web. (Funkcje realizujące właściwe operacje omówione są w dalszej części artykułu). Parametr Description określa opis usługi (wykorzystywany przez .NET Framework np. przy generowaniu stron testowych do uruchomienia danej usługi).
/Ramka – Higiena usług Web/
Należy pamiętać, że usługa Web powoduje wykonanie określonej operacji na serwerze. Jeżeli np. będzie napisana nieoptymalnie to przy większej liczbie żądań może okazać się, ze nawet najpotężniejsze serwery nie będą w stanie obsłużyć w zadowalającym czasie wszystkich klientów. Przecież w momencie, gdy pakiet SOAP przychodzi na serwer WWW – to powoduje to uruchomienie określonego procesu – od programisty zależy czy powstanie dziura w bezpieczeństwie serwera czy wszystko będzie przebiegało bez zakłóceń.
/Koniec Ramki/
W wyniku kompilacji usługi Web, powstaje kilka ważnych ważne plików. Plik z rozszerzeniem DLL zawiera właściwy kod usługi (jak w programach ASP.NET). Plik z rozszerzeniem ASMX jest „punktem startowym” – one jest „wywoływany” przez klientów. Na przykład, chcąc otrzymać specyfikację WSDL opisująca usługę, należy napisać (przy założeniu że usługa została zainstalowana na lokalnym serwerze IIS): http://localhost/SampleNewsServices/NewsService.asmx?WSDL
Plik GLOBAL.ASAX (podobnie jak w przypadku aplikacji ASP.NET) wskazuje nazwę biblioteki, która zawiera „globalne” metody –np wywoływane na początku sesji).
Plik VSDISCO zawiera informacje, które pozwalają VS.NET odczytać dodatkowe informacje o usłudze (plik pełni analogiczną rolę co dokumentacja WSDL)
Przykład pliku WSDL dla usługi GetNews (usługa znajduje się na witrynie www.vbfaq.pl) #WS1.PNG
Po uruchomieniu programu (jako stronę startową należy ustawić plik NewsService.ASMX) na ekranie przeglądarki programista zobaczy specjalną stronę testową – która pozwoli sprawdzić, jak działa uruchomiona usługa).
Uruchomiona usługa #WS2.PNG
Po wybraniu usługi GetNews, wyświetlany jest formularz, w którym można wprowadzić parametry, a także ogólny wygląd pakietu SOAP (warto dodać, że usługi Web mogą być także wywołane za pośrednictwem innych protokołów – nie tylko SOAP) :
POST /SampleNewsService/NewsService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.vbfaq.pl/SampleNewsServices/GetNews"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetNews xmlns="http://www.vbfaq.pl/SampleNewsServices">
<type>int</type>
<news_count>int</news_count>
</GetNews>
</soap:Body>
</soap:Envelope>
Po wywołaniu Invoke, procedura zwraca na przykład następujące kursy walut (w oknie przeglądarki powinien zostać otworzony plik XML:
<?xml version="1.0" encoding="utf-8" ?>
- <ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.vbfaq.pl/SampleNewsServices">
<string>- Australia - 781 - 1 - AUD - 2,2558 - 2,3014 -</string>
<string>- Czechy - 213 - 1 - CZK - 0,1335 - 0,1361 -</string>
<string>- Dania - 792 - 1 - DKK - 0,5410 - 0,5520 -</string>
<string>- Estonia - 233 - 1 - EEK - 0,2569 - 0,2621 -</string>
<string>- Japonia - 784 - 100 - JPY - 3,3805 - 3,4487 -</string>
</ArrayOfString>
Procedura generująca wiadomości wykorzystuje klasę StringBuilder (znajduje się ona w przestrzeni System.Text). W przypadku „zwykłej” klasy String łańcuch znaków po zainicjowaniu obiektu nigdy nie jest zmieniany. Tak więc, jeżeli ktoś pisze:
Dim str1,str2 As String
str1 = “TEKST1”
str2 = “TEKST2”
str2 = str1 + str2
to kod, znajdujący się w ostatniej linii spowoduje, że .NET utworzy zupełnie nowy obiekt str2. StringBuilder jest w wielu przypadkach szybszym sposobem manipulacji łańcuchami – tam, przy tworzeniu obiektu można podać jak duży obszar pamięci ma zostać zarezerwowany na łańcuch znaków (oczywiście w razie potrzeby rozmiar ten będzie zwiększany – jednak to też jest kosztowne)
Poniżej znajduje się kod procedury, która manipulując StringBuilder definiuje postać „komunikatów” zwracanych przez usługę Web:
Dim sb As New StringBuilder(50), sb1 As StringBuilder
Dim retTable(news_count) As String
Dim i As Integer
sb.Append("Client request: Type1")
sb.Append(", ")
sb.Append(news_count)
sb.Append("_")
For i = 1 To news_count
sb1 = New StringBuilder()
sb1.Append(sb) '...
Lauviah666