background image

Wydawnictwo Helion 
ul. Koœciuszki 1c 
44-100 Gliwice 
tel. 032 230 98 63 

e-mail: helion@helion.pl 

ASP.NET AJAX. 
Programowanie 
w nurcie Web 2.0

Autor: Christian Wenz
T³umaczenie: Marek Pa³czyñski
ISBN: 978-83-246-1494-3
Tytu³ orygina³u: 

Programming ASP.NET AJAX: 

Build rich, Web 2.0-style UI with ASP.NET AJAX

Format: 168x237, stron: 432

Wykorzystaj najlepsze rozwi¹zania technologii AJAX 

i stwórz interaktywn¹ stronê internetow¹

• 

Jak wykorzystywaæ dane serwerowe?

• 

Jak tworzyæ i udostêpniaæ w³asne kontrolki?

• 

Jak aktualizowaæ czêœæ strony w regularnych odstêpach czasu?

Zastanawia³eœ siê, dlaczego interaktywne witryny ciesz¹ siê dziœ tak¹ popularnoœci¹? Dzieje siê 
tak g³ównie dlatego, ¿e wymagaj¹ one od u¿ytkowników wspó³uczestnictwa w tworzeniu 
i rozwoju serwisu, a tym samym powoduj¹, ¿e abonenci maj¹ du¿y wp³yw na jego ostateczny 
kszta³t. Dziêki temu ka¿dy odbiorca korzysta z atrakcyjnej witryny idealnie dopasowanej 
do swoich potrzeb. To w³aœnie ASP.NET AJAX umo¿liwia projektowanie profesjonalnych, 
interaktywnych stron WWW w duchu Web 2.0. Znawcy tematu zapewniaj¹, ¿e AJAX 
jest rozwi¹zaniem przysz³oœciowym w dziedzinie projektowania serwisów internetowych. 
O tym, jak za pomoc¹ tej technologii wdro¿yæ w swoim serwisie rozwi¹zania zgodne z filozofi¹ 
Web 2.0, dowiesz siê w³aœnie z tego podrêcznika.

W ksi¹¿ce „ASP.NET AJAX. Programowanie w nurcie Web 2.0” zamieszczono, oprócz 
teoretycznych wiadomoœci, mnóstwo przyk³adów demonstruj¹cych dzia³anie najwa¿niejszych 
mechanizmów œrodowiska ASP.NET AJAX. Przedstawione rozwi¹zania maj¹ bardzo ogólny 
charakter, a zatem mo¿esz szybko dostosowaæ je do potrzeb w³asnej aplikacji. Korzystaj¹c 
z tego podrêcznika, nauczysz siê m.in. projektowaæ w³asne kontrolki i udostêpniaæ je 
w serwisie Toolkit, poznasz zasady korzystania ze standardowych bibliotek AJAX-a w innych 
œrodowiskach (np. PHP). Bêdziesz umia³ zbudowaæ profesjonaln¹, dynamiczn¹ stronê 
internetow¹, bazuj¹c¹ na platformie ASP.NET AJAX.

• 

Struktura i architektura œrodowiska ASP.NET AJAX

• 

JavaScript

• 

Rozszerzenia ASP.NET AJAX

• 

Us³ugi sieciowe

• 

Odœwie¿anie czêœci strony — obiekt UpdatePanel

• 

Lokalizacja i globalizacja aplikacji

• 

ASP.NET Control Toolkit

• 

Animacja na stronie WWW

• 

Wi¹zanie i walidacja danych

• 

Zachowania i komponenty

• 

Dokumentacja klasy XMLHttpRequest i modelu DOM

P³yñ z nurtem nowoczesnoœci — twórz elektryzuj¹ce, interaktywne strony WWW!

background image

 

 

 

 

 

3

Spis tre

ļci

Przedmowa ...............................................................................................................................9

  I  Podstawy  ................................................................................................ 17

 

1.  ASP.NET AJAX, Ajax i ASP.NET .................................................................................... 19

ASP.NET AJAX i Ajax 

19

ASP.NET AJAX i ASP.NET 

21

Wymagania wstöpne i instalacja ASP.NET AJAX 

23

Struktura i architektura Ĉrodowiska ASP.NET AJAX 

29

Pierwszy przykäad strony ASP.NET AJAX — Witaj uĔytkowniku 

31

Kontrolka ScriptManager 

35

Podsumowanie 

37

Do dalszego czytania 

37

  2.  JavaScript .....................................................................................................................39

Jözyk JavaScript 

41

Programowanie obiektowe 

51

Dostöp do elementów strony 

54

Metody modelu DOM 

58

Podsumowanie 

59

Do dalszego czytania 

59

  3.  Ajax  .............................................................................................................................. 61

Obiekt XMLHttpRequest 

61

Obiekt XMLDocument 

71

JSON 

76

Podsumowanie 

79

Do dalszego czytania 

79

background image

_  Spis treļci

  II  Rozszerzenia ASP.NET AJAX ..................................................................81

  4.  Wykorzystanie rozszerze

ħ JavaScript ļrodowiska ASP.NET AJAX ...........................83

Skróty ASP.NET AJAX i funkcje pomocnicze 

83

Rozszerzenia istniejñcych obiektów JavaScript 

86

Techniki programowania obiektowego dla jözyka JavaScript w ASP.NET AJAX 

87

Klienckie wersje klas .NET 

98

Podsumowanie 

102

Do dalszego czytania 

102

  5.  Us

ĥugi sieciowe .......................................................................................................... 103

Obsäuga bäödów 

103

Metody strony 

107

Przechowywanie informacji o stanie sesji 

110

Wymiana zäoĔonych struktur danych miödzy klientem i serwerem 

115

Wykorzystanie usäug sieciowych z poziomu skryptu JavaScript 

119

Podsumowanie 

129

Do dalszego czytania 

129

  6.  Od

ļwieŜanie czýļci strony — obiekt UpdatePanel  ..................................................131

Przeksztaäcenie fragmentu strony w aktualizowany obszar 

132

Podsumowanie 

145

Do dalszego czytania 

146

  7.  Wykorzystanie us

ĥugi profili ASP.NET AJAX ............................................................ 147

Przygotowanie witryny 

148

Dostöp do danych profilu 

149

Dostöp do danych profilu zdefiniowanych w grupie 

154

Podsumowanie 

158

Do dalszego czytania 

158

  8.  Wykorzystanie us

ĥugi uwierzytelniania ASP.NET AJAX .......................................... 159

Przygotowanie aplikacji 

159

Logowanie i wylogowanie 

162

Podsumowanie 

168

Do dalszego czytania 

168

  9.  Lokalizacja i globalizacja aplikacji  ............................................................................ 169

Lokalizacja 

170

Globalizacja i internacjonalizacja 

182

Podsumowanie 

186

Do dalszego czytania 

186

background image

 

 

 

Spis tre

ļci 

_ 

5

  III  ASP.NET AJAX Control Toolkit  ............................................................. 187

  10.  Korzystanie z pakietu Control Toolkit  ...................................................................... 189

Instalacja pakietu Control Toolkit 

189

Korzystanie z pakietu kontrolek 

192

Podsumowanie 

195

Do dalszego czytania 

195

  11.  Animacja na stronie WWW  ....................................................................................... 197

Platforma animacji 

197

Mechanizm „przeciñgnij i upuĈè” 

204

Podsumowanie 

207

Do dalszego czytania 

207

  12.  Automatyczne uzupe

ĥnianie wprowadzanych danych,

zwalczanie spamu i inne operacje  ............................................................................209

Tworzenie harmonijkowych obszarów 

209

Zachowanie wzglödnego poäoĔenia elementu 

211

WyposaĔenie kontrolki TextBox w funkcjö automatycznego uzupeäniania danych  213
Doäñczenie kalendarza do pola tekstowego 

220

Dynamiczne zwijanie pojedynczego panelu 

221

WyĈwietlanie okna komunikatu 

223

Zwalczanie spamu w blogach i na innych forach internetowych 

226

Tworzenie zakäadek 

228

Podsumowanie 

230

Do dalszego czytania 

230

  13.  Tworzenie i udost

ýpnianie wĥasnych kontrolek ...................................................... 231

Tworzenie wäasnych kontrolek ASP.NET AJAX 

231

Doäñczenie komponentu do pakietu Control Toolkit 

239

Podsumowanie 

247

Do dalszego czytania 

248

  IV  ASP.NET AJAX Futures ......................................................................... 249

  14.  Kontrolki klienckie ..................................................................................................... 251

Podstawy korzystania z kontrolek klienckich ASP.NET AJAX 

251

Korzystanie z kontrolek ASP.NET AJAX 

252

Obsäuga zdarzeþ kontrolek 

267

Podsumowanie 

271

Do dalszego czytania 

271

background image

_  Spis treļci

  15.  Wi

ézanie i walidacja danych  ....................................................................................273

Wiñzanie danych 

273

Walidacja danych 

289

Podsumowanie 

303

Do dalszego czytania 

303

  16.  Zachowania i komponenty ........................................................................................305

Wykorzystanie zachowaþ 

305

Wykorzystanie komponentów 

317

Podsumowanie 

319

Do dalszego czytania 

319

  17.  Wykorzystanie danych serwerowych  ...................................................................... 321

Kontrolka ListView 

321

Utworzenie wäasnego Ēródäa danych 

336

Podsumowanie 

341

Do dalszego czytania 

341

  18.  Animacje  ....................................................................................................................343

Zastosowanie animacji 

343

Wykorzystanie animacji do uzyskania efektu zanikania 

344

Podsumowanie 

354

Do dalszego czytania 

354

  19.  Usprawnianie dzia

ĥania zakĥadek oraz przycisków „w przód” i „w tyĥ” ...............355

Poprawianie kodu 

356

Usprawnianie zakäadek oraz przycisków „w przód” i „w tyä”
za pomocñ kontrolki UpdateHistory 

358

Usprawnianie zakäadek oraz przycisków „w przód” i „w tyä”
za pomocñ kontrolek ASP.NET AJAX Futures 

362

Podsumowanie 

368

Do dalszego czytania 

368

  20.  Rozszerzenie Web Parts ............................................................................................369

Wykorzystanie Ĉrodowiska ASP.NET AJAX z rozszerzeniem ASP.NET Web Parts  369
Podsumowanie 

374

Do dalszego czytania 

374

background image

 

 

 

Spis tre

ļci 

_ 

7

  V  Biblioteka Microsoft AJAX  ...................................................................375

  21.  Wykorzystanie ASP.NET AJAX w po

ĥéczeniu z innymi technologiami sieciowymi ......377

Wykorzystanie rozwiñzaþ ASP.NET AJAX w aplikacji PHP 

378

Podsumowanie 

382

Do dalszego czytania 

382

 

  Dodatki ................................................................................................. 383

 

A  Uruchamianie aplikacji ASP.NET AJAX  .....................................................................385

B  Dokumentacja klasy XMLHttpRequest ..................................................................... 397

C  Dokumentacja modelu DOM  .....................................................................................399

D  Dokumentacja 

ļrodowiska ASP.NET AJAX ...............................................................403

E  Dokumentacja kontrolek ScriptManager, UpdatePanel, UpdateProgress i Timer  ....407

Skorowidz ..............................................................................................................................411

background image

103

ROZDZIA

Ĥ 5.

Us

ĥugi sieciowe

Usäuga  sieciowa  zostaäa  wykorzystana  juĔ  w  pierwszym  rozdziale  ksiñĔki  w  przykäadzie
aplikacji  „Witaj  Ĉwiecie”.  Jej  zadanie  polegaäo  wówczas  na  przekazywaniu  danych  miödzy
klientem i serwerem. Chcñc jednak skorzystaè ze wszystkich moĔliwoĈci, jakie daje poäñcze-
nie  usäug  sieciowych  ze  skryptami  JavaScript,  trzeba  siö  zapoznaè  z  kilkoma  bardziej  za-
awansowanymi  sposobami  wykorzystywania  tego  typu  rozwiñzaþ.  Zaliczajñ  siö  do  nich
miödzy innymi: obsäuga bäödów, stosowanie osadzanych usäug sieciowych (metod usäug sie-
ciowych zawartych w kodzie strony .aspx, zwanych teĔ czasami metodami strony) oraz wy-
korzystanie usäug sieciowych i skryptów JavaScript bez wsparcia ze strony platformy .NET.

W tym rozdziale zostanñ przedstawione pewne szczególne rozwiñzania Ĉrodowiska ASP.NET
AJAX  zwiñzane  z  obsäugñ  usäug  sieciowych,  w  tym  procedury  obsäugi  bäödów  oraz  prze-
chowywanie informacji o stanie sesji. Tematyka rozdziaäu obejmuje równieĔ zasady odwoäy-
wania  siö  z  poziomu  skryptów  JavaScript  do  usäug  sieciowych,  które  nie  zostaäy  przygoto-
wane w 

Ĉrodowisku ASP.NET.

Obs

ĥuga bĥýdów

W analizowanych wczeĈniej przykäadach zakäadaliĈmy, Ĕe wywoäania zdalnych metod zawsze
koþczñ siö poprawnie. Nie uwzglödnialiĈmy moĔliwoĈci wygenerowania wyjñtku.

Projektanci serwisów internetowych czösto pomijajñ procedury obsäugi bäödów w przypadku
odwoäaþ do usäug sieciowych udostöpnianych przez zdalne serwery (czyli serwery pracujñce
w innej domenie). Jednñ z przyczyn jest to, Ĕe usäugi sieciowe moĔna implementowaè na
podstawie róĔnych technologii, a kaĔda z technologii dysponuje wäasnym mechanizmem
zgäaszania wyjñtków, a niektóre z nich w ogóle nie generujñ wyjñtków.

W przypadku platformy ASP.NET AJAX i rozwiñzaþ Ajax praca z usäugami sieciowymi od-
biega nieco od standardowego modelu. Nie moĔna wywoäywaè bezpoĈrednio usäugi sieciowej,
poniewaĔ  zabrania  tego  system  bezpieczeþstwa.  DomyĈlnie  interpreter  JavaScript  i  obiekt

XMLHttpRequest

 pozwalajñ jedynie na odwoäania z uĔyciem adresów URI z tej samej dome-

ny, z której pochodzi strona. Zatem podczas pracy w Ĉrodowisku ASP.NET AJAX wywoäania
usäug sieciowych sñ kierowane do serwera w tej samej domenie. To z kolei oznacza, Ĕe sama
usäuga  sieciowa  opiera  siö  na  technologii  .NET  (lub  WCF  —  nowym  modelu  Windows
Communication Foundation). Zasady generowania wyjñtków sñ wiöc znane.

background image

104

_

Rozdzia

ĥ 5. Usĥugi sieciowe

Zapewnienie  dostöpu  do  wyjñtków  generowanych  przez  usäugi  sieciowe  w  skryptach  Java-
Script  naleĔy  do  zadaþ  platformy  ASP.NET  AJAX.  Aby  sprawdziè  dziaäanie  opisywanego
mechanizmu,  moĔemy  utworzyè  usäugö  matematycznñ,  która  bödzie  dzieliäa  dwie  liczby.
Doprowadzenie do wygenerowania wyjñtku nie bödzie trudne — wystarczy wymusiè dzielenie
przez zero, co powinno spowodowaè wywoäanie przez usäugö wyjñtku 

DivideByZeroException

.

Kod  usäug  sieciowej  (MathService.asmx)  zostaä  przedstawiony  w  przykäadzie  5.1.  Analizujñc
treĈè przykäadu, warto zwróciè uwagö na atrybuty 

[ScriptService]

 i 

[WebMethod]

, które

muszñ byè uwzglödnione w kaĔdej usäudze sieciowej ASP.NET AJAX.

Przykäad 5.1. Usäuga sieciowa generujñca wyjñtek

MathService.asmx

<%@ WebService Language="C#" Class="MathService" %>

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = "http://hauser-wenz.de/AspNetAJAX/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class MathService : System.Web.Services.WebService {
    [WebMethod]
    public float DivideNumbers(int a, int b) {
      if (b == 0) {
        throw new DivideByZeroException( );
      } else {
        return (float)a / b;
      }
    }
}

Przygotujmy  stronö,  która  wywoäa  usäugö  sieciowñ.  Potrzebne  bödñ  dwa  pola  edycyjne,
w  których  uĔytkownik  bödzie  wpisywaä  liczby  do  podzielenia  oraz  dwa  obszary  na  dane
wyjĈciowe — jeden na wynik dziaäania matematycznego, a drugi na ewentualne komunikaty
o bäödach. Kod musi równieĔ obejmowaè przycisk wywoäujñcy funkcjö JavaScript, która na-
stöpnie wywoäa usäugö sieciowñ.

<nobr>
  <input type="text" id="a" name="a" size="2" />
  /
  <input type="text" id="b" name="b" size="2" />
  =
  <span id="c" style="width: 50px;" />
</nobr>
<br />
<input type="button" value="Podziel liczby" onclick="callService(this.form);" />
<br />
<div id="output" style="width: 600px; height: 300px;">
</div>

SpoĈród kontrolek serwerowych na stronie trzeba umieĈciè komponent 

ScriptManager

 wraz

z osadzonym w jego treĈci odniesieniem do wykorzystywanej usäugi sieciowej.

<asp:ScriptManager ID="ScriptManager1" runat="server">
  <Services>
    <asp:ServiceReference Path="MathService.asmx" />
  </Services>
</asp:ScriptManager>

background image

Obs

ĥuga bĥýdów

105

Dziöki  takiemu  rozwiñzaniu  wywoäania  usäugi  sieciowej  mogñ  byè  realizowane  za  pomocñ
obiektu poĈredniczñcego o nazwie 

MathService

, który zostanie wygenerowany automatycznie.

Podczas wywoäywania metody sieciowej konieczne jest zachowanie odpowiedniej kolejnoĈci
parametrów.  Najpierw  definiowane  sñ  parametry  (lub  parametr)  przekazywane  do  metody
sieciowej, a nastöpnie funkcja zwrotna wykonywana po zakoþczeniu wywoäania metody.

Jednak tym razem do metody 

DivideNumbers()

 zostanie przekazany jeszcze jeden dodatko-

wy parametr. Za funkcjñ zwrotnñ, wykonywanñ po zakoþczeniu wywoäania, zostanie zdefi-
niowana jeszcze jedna funkcja zwrotna. Druga z  funkcji  zwrotnych  bödzie  wywoäywana
w przypadku wystñpienia bäödów (w tym równieĔ w przypadku upäyniöcia dopuszczalnego
czasu realizacji zadania).

function callService(f) {
  document.getElementById("c").innerHTML = "";
  MathService.DivideNumbers(
    parseInt(f.elements["a"].value),
    parseInt(f.elements["b"].value),
    callComplete,
    callError
  );
}

Funkcja obsäugi bäödów otrzymuje obiekt bäödu zawierajñcy piöè metod:

get_exceptionType( )

Metoda ta udostöpnia informacje o typie wyjñtku.

get_message( )

Metoda ta zwraca komunikat o bäödzie zwiñzany z wyjñtkiem.

get_stackTrace( )

Metoda te zwraca informacje o stosie wywoäaþ funkcji.

get_statusCode( )

Metoda ta udostöpnia kod statusowy przekazany przez serwer.

get_timeOut( )

Metoda ta pozwala na ustalenie, czy zostaä przekroczony maksymalny czas realizacji za-
dania.

Informacje na temat bäödu sñ wyĈwietlane w obszarze elementu 

<div>

, który zostaä utworzony

specjalnie w tym celu.

function callError(result) {
  document.getElementById("output").innerHTML =
    "<b>" +
    result.get_exceptionType( ) +
    "</b>: " +
    result.get_message( ) +
    "<br />" +
    result.get_stackTrace( );
}

Przygotowanie  pozostaäej  czöĈci  kodu  nie  powinno  naströczaè  wiökszych  trudnoĈci.  Gdy
wywoäanie  usäugi  sieciowej  zakoþczy  siö  pomyĈlnie,  wynik  powinien  zostaè  wyĈwietlony
w obszarze elementu 

<span>

. Peäna treĈè strony zostaäa przedstawiona w przykäadzie 5.2.

background image

106

_

Rozdzia

ĥ 5. Usĥugi sieciowe

Przykäad 5.2. Strona wyĈwietlajñca wyjñtek wygenerowany przez usäugö MathService.asmx

Error.aspx

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>ASP.NET AJAX</title>

  <script language="Javascript" type="text/javascript">
  function callService(f) {
    document.getElementById("c").innerHTML = "";
    document.getElementById("output").innerHTML = "";
    MathService.DivideNumbers(
      parseInt(f.elements["a"].value),
      parseInt(f.elements["b"].value),
      callComplete,
      callError);
  }

  function callComplete(result) {
    document.getElementById("c").innerHTML = result;
  }

  function callError(result) {
    document.getElementById("output").innerHTML =
      "<b>" +
      result.get_exceptionType() +
      "</b>: " +
      result.get_message() +
      "<br />" +
      result.get_stackTrace();
  }
  </script>

</head>
<body>
  <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
      <Services>
        <asp:ServiceReference Path="MathService.asmx" />
      </Services>
    </asp:ScriptManager>
    <div>
      <nobr>
        <input type="text" id="a" name="a" size="2" />
        :
        <input type="text" id="b" name="b" size="2" />
        =
        <span id="c" style="width: 50px;"></span>
      </nobr>
      <br />
      <input type="button" value="Podziel liczby" onclick="callService(this.form);" />
      <br />
      <div id="output" style="width: 600px; height: 300px;">
      </div>
    </div>
  </form>
</body>
</html>

background image

Metody strony

107

Podzielenie  liczby  5  przez  6  daje  spodziewany  wynik  0.8333333.  Jednak  próba  podzielenia
liczby 5 przez 0 powoduje wygenerowanie przez usäugö sieciowñ wyjñtku, a w konsekwencji
wyĈwietlenie komunikatu o bäödzie  wraz  ze  stosem  wywoäaþ  funkcji  (wyglñd  strony  zostaä
pokazany na rysunku 5.1).

Rysunek 5.1. WyĈwietlenie informacji na temat wyjñtku

Informacja na temat

(nie)wy

ļwietlania komunikatów o bĥýdach

WyĈwietlanie komunikatów o bäödach w aplikacji klienckiej jest doskonaäym rozwiñzaniem
na czas uruchamiania aplikacji. Stanowi jednak bardzo duĔe zagroĔenie w Ĉrodowisku uĔyt-
kowym. Komunikaty o bäödach mogñ bowiem zawieraè tajne dane, takie jak parametry ciñ-
gów  poäñczenia.  Nawet  jeĈli  nie  sñ  bezpoĈrednio  wyĈwietlane  w  oknie  przeglñdarki  Ĉrodo-
wisko  ASP.NET  AJAX  moĔe  je  przekazywaè  do  aplikacji  klienckiej.  Aby  temu  zapobiec,
naleĔy wykonaè dwie czynnoĈci. Po pierwsze trzeba sprawdziè, czy do przeglñdarki nie sñ
dostarczane szczegóäowe opisy bäödu (obejmujñce dane na temat stosu  wywoäaþ funkcji).
Po drugie generujñc wyjñtek po stronie serwera naleĔy uwzglödniè w komunikacie moĔliwie
najmniejszñ iloĈè szczegóäowych informacji.

Metody strony

Prawdopodobnie  wiökszoĈè  programistów  zgodzi  siö  z  twierdzeniem,  Ĕe  umieszczanie
wszystkich metod sieciowych aplikacji w oddzielnym pliku jest doĈè uciñĔliwe. Pod wzglödem
struktury aplikacji taki sposób zarzñdzania plikami wydaje siö wäaĈciwy. Jednak w przypad-
ku nieskomplikowanych skryptów i aplikacji (takich jak wiökszoĈè opisywanych w ksiñĔce)
dodatkowy plik .asmx niepotrzebnie rozbudowuje projekt.

background image

108

_

Rozdzia

ĥ 5. Usĥugi sieciowe

Przy niewiele wiökszym narzucie kodowym (lub nawet zmniejszeniu iloĈci kodu w pewnych
okolicznoĈciach) istnieje moĔliwoĈè zamieszczenia caäego skryptu w jednym miejscu — w gäów-
nym pliku .aspx (lub w zwiñzanym z nim pliku klasy). Procedura przygotowania opisywanego
rozwiñzania skäada siö z dwóch etapów. Pierwszy sprowadza siö do zaimportowania do pliku
strony przestrzeni nazw usäug sieciowych:

<%@ Import Namespace="System.Web.Services" %>

Drugi etap polega na doäñczeniu treĈci metody sieciowej do kodu strony. Metoda usäugi sie-
ciowej (a dokäadnie metoda dziaäajñca jak metoda sieciowa) musi zostaè oznaczona za pomocñ
atrybutu 

[WebMethod]

 — podobnie jak w pliku .asmx. Obsäuga osadzanych metod usäug sie-

ciowych w Ĉrodowisku ASP.NET AJAX ma równieĔ pewne ograniczenia. Oto one:

Metoda musi byè oznaczona za pomocñ atrybutu 

ScriptMethod

, opisanego w przestrzeni

nazw 

System.Web.Script.Services

.

Metoda musi byè zadeklarowana jako publiczna (

public

).

Metoda musi byè zadeklarowana jako statyczna (

static

).

Przykäad metody speäniajñcej wszystkie wymienione wymagania zostaä przedstawiony poniĔej:

<script runat="server">
  [WebMethod]
  [System.Web.Script.Services.ScriptMethod]
  public static
 float DivideNumbers(int a, int b)
  {
    if (b == 0)
    {
      throw new DivideByZeroException( );
    }
    else
    {
      return (float)a / b;
    }
  }
</script>

ćrodowisko ASP.NET AJAX automatycznie wyszukuje wszystkie opisane w ten sposób metody
i doäñcza je do klasy klienckiej 

PageMethods

. Zatem aby wywoäaè metodö strony, wystarczy

posäuĔyè siö zapisem 

PageMethods.DivideNumbers()

 zgodnie z poniĔszym przykäadem.

function callService(f) {
  document.getElementById("c").innerHTML = "";
  PageMethods.DivideNumbers(
  parseInt(f.elements["a"].value),
  parseInt(f.elements["b"].value),
  callComplete,
  callError);
}

Ostatnia czynnoĈè projektowa pola na wäñczeniu wywoäaþ do osadzonych metod usäug sie-
ciowych. W terminologii ASP.NET AJAX metody te sñ nazywane „metodami strony” (ang.
page methods). Ich wäñczenie wymaga przypisania wartoĈci 

true

 do wäaĈciwoĈci 

EnablePage-

Methods

 kontrolki 

ScriptManager

:

<asp:ScriptManager ID="a1" runat="server" EnablePageMethods="true" />

background image

Metody strony

109

W przykäadzie 5.3 zostaä zamieszczony peäen kod strony ASP.NET, w której znajduje siö za-
równo treĈè samej strony, jak i metoda usäugi sieciowej.

Przykäad 5.3. Kod usäugi sieciowej i strony ASP.NET AJAX zapisane w jednym pliku

Inline.aspx

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Web.Services" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  [WebMethod]
  [System.Web.Script.Services.ScriptMethod]
  public static float DivideNumbers(int a, int b)
  {
    if (b == 0)
    {
      throw new DivideByZeroException();
    }
    else
    {
      return (float)a / b;
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>ASP.NET AJAX</title>

  <script language="Javascript" type="text/javascript">
  function callService(f) {
    document.getElementById("c").innerHTML = "";
    PageMethods.DivideNumbers(
      parseInt(f.elements["a"].value),
      parseInt(f.elements["b"].value),
      callComplete,
      callError);
  }

  function callComplete(result) {
    document.getElementById("c").innerHTML = result;
  }

  function callError(result) {
    document.getElementById("output").innerHTML =
      "<b>" +
      result.get_exceptionType() +
      "</b>: " +
      result.get_message() +
      "<br />" +
      result.get_stackTrace();
  }
  </script>

</head>
<body>
  <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server"

background image

110

_

Rozdzia

ĥ 5. Usĥugi sieciowe

EnablePageMethods="true">
    </asp:ScriptManager>
    <div>
      <nobr>
        <input type="text" id="a" name="a" size="2" />
        :
        <input type="text" id="b" name="b" size="2" />
        = <span id="c" style="width: 50px;"></span>
      </nobr>
      <br />
      <input type="button" value="Podziel liczby" onclick="callService(this.form);" />
      <br />
      <div id="output" style="width: 600px; height: 300px;">
      </div>
    </div>
  </form>
</body>
</html>

Wynik wyĈwietlany  po zaäadowaniu strony, wprowadzeniu  dwóch  wartoĈci  i  klikniöciu
przycisku Podziel liczby zostaä pokazany na rysunku 5.2.

Rysunek 5.2. Jeden plik, jedna usäuga sieciowa, jedna operacja dzielenia

Przechowywanie informacji o stanie sesji

Usäugi sieciowe zyskaäy sobie miano doskonaäej technologii, która nie ma nic wspólnego
z aplikacjami sieciowymi. Jednak od kiedy zostaäy zintegrowane z platformñ .NET i witrynami
ASP.NET, programiĈci zyskali moĔliwoĈè projektowania rozwiñzaþ, które znacznie wykraczajñ
poza funkcje samych usäug sieciowych.

Usäugi  sieciowe  platformy  .NET  pozwalajñ  miödzy  innymi  na  przetwarzanie  informacji
o stanie  sesji.  Dane  zapisane  w  sesji  sñ  (dziöki  Ĉrodowisku  ASP.NET  AJAX)  udostöpniane
nawet aplikacjom bazujñcym na technologii Ajax. Na przykäad Ĉrodowisko ASP.NET AJAX
gwarantuje róĔnym aplikacjom Ajax (uruchomionym na jednym serwerze) dostöp do danych
tego samego uĔytkownika.

background image

Przechowywanie informacji o stanie sesji

111

Zaimplementowanie opisywanego mechanizmu jest äatwiejsze niĔ jego omówienie. Za dostöp
do  danych  sesji  odpowiada  wäaĈciwoĈè 

EnableSession

  atrybutu 

[WebMethod]

.  Jej  przezna-

czenie jest takie samo, jak w przypadku metody sieciowej aplikacji .NET.

 [WebMethod(EnableSession=true)]

Po  uwzglödnieniu  wäaĈciwoĈci 

EnableSession

  moĔna  bezpoĈrednio  odwoäywaè  siö  do

obiektu 

Session

 platformy ASP.NET i zapisaè lub  odczytywaè dane. PoniewaĔ metody sie-

ciowe  muszñ  mieè  charakter  metod  statycznych,  konieczne  jest  zastosowanie  odwoäania

HttpContext.Current.Session

, a nie po prostu 

Session

. Pierwsze z odwoäaþ odnosi siö jedynie

do obiektów bieĔñcej instancji klasy 

Page

.

W nastöpnym fragmencie skryptu zostaäy zaprezentowane dwie funkcje. Pierwsza z nich za-
pisuje bieĔñcñ wartoĈè czasu w sesji. Natomiast druga oblicza róĔnicö miödzy czasem bieĔñ-
cym a znacznikiem czasu zapisanym w sesji. JeĈli w sesji nie zostaäa zapisana Ĕadna wartoĈè,
funkcja zwraca wartoĈè 

-1

.

[WebMethod(EnableSession = true)]
[System.Web.Script.Services.ScriptMethod]
public static bool SaveTime( )
{
  HttpContext.Current.Session["PageLoaded"] = DateTime.Now;
  return true;
}

[WebMethod(EnableSession = true)]
[System.Web.Script.Services.ScriptMethod]
public static double CalculateDifference( )
{
  if (HttpContext.Current.Session["PageLoaded"] == null) {
    return -1;
  } else {
    DateTime then = (DateTime)HttpContext.Current.Session["PageLoaded"];
    TimeSpan diff = DateTime.Now.Subtract(then);
    return diff.TotalSeconds;
  }
}

Powróèmy na chwilö do aplikacji dzielenia dwóch liczb. Do strony zwierajñcej kod aplikacji
zostanie  dodana  metoda 

SaveTime()

,  która  zapisze  wartoĈè  czasu,  wäaĈciwñ  dla  chwili  äa-

dowania skryptu. Z kolei w momencie obliczania wyniku dzielenia wyznaczona zostanie
róĔnica miödzy czasem bieĔñcym a zarejestrowanym wczeĈniej. W ten sposób bödzie moĔna
ustaliè, ile czasu minöäo od pobrania strony do obliczenia wyniku dziaäania (które oczywiĈcie
moĔna równieĔ wykonaè w samym jözyku JavaScript; celem przykäadu jest jednak zademon-
strowanie innego rozwiñzania).

Kolejny fragment kodu JavaScript odpowiada za wywoäanie metody sieciowej (

SaveTime()

),

która zarejestruje czas w chwili pobrania strony. PoniewaĔ w operacji tej nie jest zwracana
Ĕadna wartoĈè wynikowa, funkcja zwrotna moĔe byè funkcjñ pustñ

function pageLoad( ){
  PageMethods.SaveTime(doNothing, doNothing);
}

function doNothing(result) {
  //nic :-)
}

background image

112

_

Rozdzia

ĥ 5. Usĥugi sieciowe

Zgodnie z wczeĈniejszymi zaäoĔeniami konieczne jest równieĔ zdefiniowanie metody (

call-

Service()

),  która  wywoäa  metodö 

CalculateDifference()

  usäugi  sieciowej.  Zamieszczony

poniĔej kod uwzglödnia dwa wywoäania metod sieciowych. Pierwsze odpowiada za oblicze-
nie  róĔnicy  czasu  miödzy  pobraniem  strony  a  klikniöciem  przycisku.  Drugie  natomiast  po-
woduje wykonanie samego dziaäania matematycznego.

function callService(f) {
  document.getElementById("c").innerHTML = "";
  PageMethods.CalculateDifference(
    showDifference,
    callError);
  PageMethods.DivideNumbers(
    parseInt(f.elements["a"].value),
    parseInt(f.elements["b"].value),
    callComplete,
    callError);
}

Potrzebny  bödzie  jeszcze  pewien  kod  HTML,  który  pozwoli  na  wyĈwietlenie  informacji
o czasie. Wykorzystamy do tego celu kontener 

<div>

. NaleĔy pamiötaè, Ĕe wynik o wartoĈci

-1

 oznacza, Ĕe w sesji nie zostaä zarejestrowany znacznik czasu i w zwiñzku z tym nie moĔna

obliczyè róĔnicy czasowej.

function showDifference(result) {
  if (result != -1) {
    document.getElementById("output").innerHTML =
    "Formularz by

Ī wyŁwietlany przez " + result + " sekund";

  }
}

Kompletny  kod  strony  (treĈè  HTML  i  skrypt  niezbödny  do  zaimplementowania  algorytmu)
zostaä  przedstawiony  w  przykäadzie  5.4.  Wszystkie  zmiany  w  treĈci  zostaäy  odpowiednio
wyróĔnione. Aby aplikacja dziaäaäa poprawnie, trzeba pamiötaè o dodaniu atrybutu 

Enable-

PageMethods="true"

 do  kodu  kontrolki 

ScriptManager

.  Brak  atrybutu  uniemoĔliwia  wy-

woäanie metody strony.

Przykäad 5.4. Wykorzystanie sesji w aplikacji ASP.NET AJAX i ASP.NET

WebServiceSession.aspx

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Web.Services" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  [WebMethod(EnableSession = true)]
  [System.Web.Script.Services.ScriptMethod]
  public static bool SaveTime()
  {
    HttpContext.Current.Session[
"PageLoaded"] = DateTime.Now;
    return true;
  }

  [WebMethod(EnableSession = true)]
  [System.Web.Script.Services.ScriptMethod]
  public static double CalculateDifference()
  {

background image

Przechowywanie informacji o stanie sesji

113

      if (HttpContext.Current.Session["PageLoaded"] == null)
      {
      return -1;
    } else {
        DateTime then = (DateTime)HttpContext.Current.Session[
"PageLoaded"];
      TimeSpan diff = DateTime.Now.Subtract(then);
      return diff.TotalSeconds;
    }
  }

  [WebMethod]
  [System.Web.Script.Services.ScriptMethod] public float DivideNumbers(int a, int b)
  {
    if (b == 0)
    {
      throw new DivideByZeroException();
    }
    else
    {
      return (float)a / b;
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>ASP.NET AJAX</title>

  <script language="Javascript" type="text/javascript">
  function pageLoad() {
    PageMethods.SaveTime(doNothing, doNothing, doNothing);
  }
  function doNothing(result) {
    //nic :-)
  }

  function callService(f) {
    document.getElementById("c").innerHTML = "";
    PageMethods.CalculateDifference(
      showDifference,
      callError);
    PageMethods.DivideNumbers(
      parseInt(f.elements["a"].value),
      parseInt(f.elements["b"].value),
      callComplete,
      callError);
  }
function showDifference(result) {
    if (result != -1) {
      document.getElementById(
"output").innerHTML =
        
"Formularz by

Ĩ wyĿwietlany przez " + result + " sekund";

    }
  }

  function callComplete(result) {
    document.getElementById("c").innerHTML = result;
  }

  function callError(result) {
    if (result == null) {
      window.alert("B

Īîd!");

    } else {

background image

114

_

Rozdzia

ĥ 5. Usĥugi sieciowe

      document.getElementById("output").innerHTML =
        "<b>" +
        result.get_exceptionType() +
        "</b>: " +
        result.get_message() +
        "<br />" +
        result.get_stackTrace();
    }
  }
  </script>

</head>
<body>
  <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server"
      EnablePageMethods="true">
    </asp:ScriptManager>
    <div>
      <nobr>
        <input type="text" id="a" name="a" size="2" />
        :
        <input type="text" id="b" name="b" size="2" />
        = <span id="c" style="width: 50px;"></span>
      </nobr>
      <br />
      <input type="button" value="Podziel liczby" onclick="callService(this.form);" />
      <br />
      <div id="output" style="width: 600px; height: 300px;">
      </div>
    </div>
  </form>
</body>
</html>

Podczas  wykonywania  metody 

DivideNumbers()

  moĔna  zauwaĔyè  nieco  inne  dziaäanie

przeglñdarki niĔ w poprzednich zadaniach. Po pierwsze, serwer dostarcza plik cookie zwiñ-
zany z sesjñ (o ile w pliku Web.config nie zostaäa wäñczona opcja zarzñdzania sesjñ bez uĔycia
plików cookie). JeĔeli w przeglñdarce zostaäa wäñczona opcja pytania o zezwolenie na przyjö-
cie  pliku  cookie,  na  ekranie  powinno  siö  wyĈwietliè  okno,  zbliĔone  do  przedstawionego  na
rysunku 5.3. Druga róĔnica wiñĔe siö z zachowaniem danych sesji pomiödzy odwoäaniami do
usäugi sieciowej (rysunek 5.4).

Rysunek 5.3. ćrodowisko ASP.NET przesyäa plik cookie zwiñzany z sesjñ dla danej strony

background image

Wymiana z

ĥoŜonych struktur danych miýdzy klientem i serwerem

115

Rysunek 5.4. Wykorzystanie sesji do przechowywania wartoĈci czasu (niezbödnej do obliczenia przerwy
miödzy pobraniem strony i wykonaniem dziaäania)

Wymiana z

ĥoŜonych struktur danych

mi

ýdzy klientem i serwerem

We wczeĈniejszych przykäadach analizowaliĈmy jedynie wymianö miödzy serwerem i klientem
ciñgów tekstowych i wartoĈci typów prostych (liczb, wartoĈci logicznych). Nic jednak nie stoi
na przeszkodzie, aby objñè tym mechanizmem równieĔ operacjö dostarczania bardziej zäoĔo-
nych struktur danych. Co prawda jözyk JavaScript nie moĔe konkurowaè z bogatszymi pod
wzglödem liczby typów jözykami platformy .NET, ale format JSON (opisany w rozdziale 3.)
zapewnia podstawowñ obsäugö tablic i obiektów.

ćrodowisko ASP.NET AJAX jest standardowo wyposaĔone w mechanizmy serializacji i dese-
rializacji danych JSON. JeĈli wiöc uwzglödnimy je w kodzie usäugi sieciowej zaprezentowanej
w przykäadach 5.1 i 5.2, bödziemy mogli udostöpniè nowñ metodö, która za jednym razem
zwróci dwie informacje — wynik dzielenia liczb oraz wartoĈè znacznika czasu serwerowego.
Aby wdroĔyè opisane rozwiñzanie, utworzymy w pliku MathService.asmx nowñ klasö, która
bödzie opisywaäa zwracany obiekt.

public class DivisionData
{
  public float result;
  public string calculationTime;
}

Powoäanie i zwrócenie obiektu bödzie naleĔaäo do metody przedstawionej poniĔej.

[WebMethod]
public DivisionData ExtendedDivideNumbers(int a, int b) {
  if (b == 0) {
    throw new DivideByZeroException( );
  } else {
    float res = (float)a / b;
    string stamp = DateTime.Now.ToLongTimeString( );
    DivisionData d = new DivisionData( );
    d.result = res;

background image

116

_

Rozdzia

ĥ 5. Usĥugi sieciowe

    d.calculationTime = stamp;
    return d;
  }
}

Aby  zwracany  obiekt  byä  dostöpny  dla  kodu  JavaScript,  aplikacja  ASP.NET  AJAX  musi
go  przeksztaäciè  (w  procesie  serializacji)  w  odpowiedni  ciñg  JSON.  Za  uĔycie  wäaĈciwej
definicji  obiektu  odpowiada  atrybut 

GenerateScriptType

  (zdefiniowany  w  przestrzeni

nazw 

System.Web.Script.Services

  [w  której  zostaäy  zapisane  równieĔ  atrybuty 

Script-

Service

 i 

ScriptMethod

]):

[System.Web.Script.Services.GenerateScriptType(typeof(DivisionData))]

Po stronie serwera nie trzeba wprowadzaè wiöcej zmian. Zaktualizowana treĈè pliku Math-
Service.asmx
 zostaäa zamieszczona w przykäadzie 5.5.

Przykäad 5.5. Zaktualizowany plik usäugi MathService

MathService.asmx

<%@ WebService Language="C#" Class="MathService" %>

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

public class DivisionData
{
    public float result;
    public string calculationTime;
}

[WebService(Namespace = "http://hauser-wenz.de/AspNetAJAX/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
[System.Web.Script.Services.GenerateScriptType(typeof(DivisionData))]
public class MathService : System.Web.Services.WebService
{

    [WebMethod]
    public float DivideNumbers(int a, int b)
    {
        if (b == 0)
        {
            throw new DivideByZeroException();
        }
        else
        {
            return (float)a / b;
        }
    }

    [WebMethod]
    public DivisionData ExtendedDivideNumbers(int a, int b)
    {
        if (b == 0)
        {
            throw new DivideByZeroException();
        }
        else

background image

Wymiana z

ĥoŜonych struktur danych miýdzy klientem i serwerem

117

        {
            float res = (float)a / b;
            string stamp = DateTime.Now.ToLongTimeString();
            DivisionData d = new DivisionData();
            d.result = res;
            d.calculationTime = stamp;
            return d;
        }
    }

}

Po  stronie  klienta  deserializacja  obiektu 

DivisionData

  jest  realizowana  w  sposób  automa-

tyczny. Obiekt bödñcy wynikiem wywoäania usäugi sieciowej ma te same wäaĈciwoĈci (

result

calculationTime

),  jakie  zostaäy  zdefiniowane  w  obiekcie 

DivisionData

.  Instrukcje  Java-

Script  potrzebne  do  wywoäania  zmodyfikowanej  usäugi  sieciowej  zostaäy  przedstawione
w przykäadzie 5.6.

Przykäad 5.6. Kod strony pobierajñcej z metody sieciowej bardziej rozbudowane obiekty

Complex.aspx

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>ASP.NET AJAX</title>

  <script language="Javascript" type="text/javascript">
  function callService(f) {
    document.getElementById("c").innerHTML = "";
    document.getElementById("output").innerHTML = "";
    MathService.ExtendedDivideNumbers(
      parseInt(f.elements["a"].value),
      parseInt(f.elements["b"].value),
      callComplete,
      callError);
  }

  function callComplete(result) {
    document.getElementById("c").innerHTML =
      result.result +
      
" (obliczono o godzinie " +
      result.calculationTime +
      
")";
  }

  function callError(result) {
    document.getElementById("output").innerHTML =
      "<b>" +
      result.get_exceptionType() +
      "</b>: " +
      result.get_message() +
      "<br />" +
      result.get_stackTrace();
  }
  </script>

</head>

background image

118

_

Rozdzia

ĥ 5. Usĥugi sieciowe

<body>
  <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
      <Services>
        <asp:ServiceReference Path="MathService.asmx" />
      </Services>
    </asp:ScriptManager>
    <div>
      <nobr>
        <input type="text" id="a" name="a" size="2" />
        :
        <input type="text" id="b" name="b" size="2" />
        =
        <span id="c" style="width: 50px;"></span>
      </nobr>
      <br />
      <input type="button" value="Podziel liczby" onclick="callService(this.form);" />
      <br />
      <div id="output" style="width: 600px; height: 300px;">
      </div>
    </div>
  </form>
</body>
</html>

Sposób prezentacji wyniku dzielenia i czasu wygenerowania odpowiedzi zostaä pokazany na
rysunku 5.5.

Rysunek 5.5. WyĈwietlenie informacji dostarczonych przez serwer

Przechwytujñc ruch HTTP generowany przez skrypt, moĔemy sprawdziè, w jaki sposób zäo-
Ĕona struktura danych zostaäa przeksztaäcona w blok danych JSON (rysunek 5.6).

Opisane  do  tej  pory  funkcje  Ĉrodowiska  ASP.NET  AJAX  zwiñzane  z  usäugami  sieciowymi
byäby  niezwykle  trudne  do  zaimplementowania  za  pomocñ  samego  jözyka  JavaScript.  Plat-
forma ASP.NET AJAX doskonale integruje siö z usäugami sieciowymi .NET i stanowi bardzo
uĔyteczny pomost miödzy technologiñ JavaScript (po stronie klienckiej) i technologiñ ASP.NET
(po stronie serwera).

background image

Wykorzystanie us

ĥug sieciowych z poziomu skryptu JavaScript

119

Rysunek 5.6. ZäoĔona struktura danych po serializacji do formatu JSON

Wykorzystanie us

ĥug sieciowych

z poziomu skryptu JavaScript

Zapewniane przez Ĉrodowisko ASP.NET AJAX mechanizmy odwoäaþ do usäug sieciowych sñ
niezwykle  uĔyteczne,  poniewaĔ  automatycznie  realizujñ  wszystkie  zwiñzane  z  tñ  operacjñ
zadania. Zdarzajñ siö jednak sytuacje, w których nie moĔna ich zastosowaè. Przykäadem moĔe
byè koniecznoĈè odwoäania siö do usäugi sieciowej (w tej samej domenie), która nie zostaäa
napisana  dla  platformy  .NET,  lecz  opiera  siö  na  innych  rozwiñzaniach  serwerowych,  takich
jak PHP lub Java. Innym powodem bywa równieĔ polityka firmy dotyczñca stosowania mo-
duäów  zewnötrznych  producentów  lub  brak  akceptacji  dla  okreĈlonej  umowy  licencyjnej.
PoniewaĔ  zakres  tematyczny  ksiñĔki  wykracza  poza  samo  korzystanie  ze  Ĉrodowiska
ASP.NET AJAX i obejmuje wszystkie zagadnienia zwiñzane z tworzeniem aplikacji Ajax na
platformie  ASP.NET,  omówione  zostanñ  tutaj  takĔe  zasady  wywoäywania  zdalnych  usäug
sieciowych z poziomu skryptu JavaScript.

Zanim przystñpimy do szczegóäowego analizowania stosownych mechanizmów, warto sobie
przypomnieè, Ĕe model zabezpieczeþ jözyka JavaScript zabrania wykonywania skryptów po-
chodzñcych z róĔnych domen. Oznacza to, Ĕe nie moĔna odwoäaè siö do zdalnych witryn za
pomocñ instrukcji JavaScript (korzystajñcych z obiektu 

XMLHttpRequest

).

background image

120

_

Rozdzia

ĥ 5. Usĥugi sieciowe

Istniejñ dwie metody programowego wywoäywania usäug sieciowych w jözyku JavaScript.
Pierwsza  z  nich  polega  na  zastosowaniu  obiektu 

XMLHttpRequest

.  Natomiast  w  drugiej  za-

käada siö przygotowanie wäasnego Ĕñdania HTTP SOAP i samodzielnñ interpretacjö danych
zwracanych przez serwer. Druga metoda jest doĈè skomplikowana i bardzo podatna na bäödy.
Znacznie  lepszym  rozwiñzaniem  jest  wykorzystanie  mechanizmów  wbudowanych  w  prze-
glñdarkñ oraz oficjalnych dodatków do przeglñdarki,

Niestety, dwie najpowszechniej stosowane aplikacje — Internet Explorer i Mozilla (czyli Firefox,
Epiphany,  Camino  itd.)  —  majñ  zaimplementowane  dwie  zupeänie  róĔne  procedury  wywo-
äywania usäug sieciowych. W rezultacie programista musi powielaè kod zapewniajñcy obsäugö
kaĔdej  z  przeglñdarek.  W  koþcowej  czöĈci  podrozdziaäu  zostaäo  jednak  przedstawione  roz-
wiñzanie, które pozwala na poäñczenie obydwu modeli, a tym samym na opracowanie skryptu
(bardziej lub mniej) niezaleĔnego od rodzaju oprogramowania klienckiego.

Us

ĥugi sieciowe w przeglédarkach Internet Explorer

Kilka lat temu firma Microsoft rozpoczöäa prace na kodem skryptowym, który umoĔliwiaäby
wywoäywanie  usäug  sieciowych  z  poziomu  samej  przeglñdarki.  Zgodnie  z  zaäoĔeniami  kod
taki powinien powoäywaè obiekt 

XMLHttpRequest

, definiowaè niezbödne nagäówki HTTP dla

Ĕñdania  SOAP,  przygotowywaè  treĈè  samego  Ĕñdania,  nastöpnie  oczekiwaè  na  odpowiedĒ
SOAP i przeksztaäcaè wynik do formatu wäaĈciwego do dalszego przetwarzania w instruk-
cjach  JavaScript.  Ponadto  powinien  umoĔliwiaè  interpretowanie  informacji  generowanych
w jözyku opisu usäug sieciowych (WSDL — ang. Web Service Description Language) oraz gene-
rowanie lokalnego obiektu poĈredniczñcego.

Idea nie jest skomplikowana, ale implementacja tak. Ostateczna wersja mechanizmu (wersja
1.0.1.1120) skäada siö z niemal 2300 wierszy kodu. Niestety, w 2002 roku firma Microsoft
przerwaäa  prace  nad  komponentem  komunikacji  z  usäugami  sieciowymi.  Szkoda,  gdyĔ  do
dzisiaj jest on wykorzystywany i dziaäa poprawnie. Na szczöĈcie jest jeszcze dostöpny w ar-
chiwach  MSDN  pod  adresem  http://msdn.microsoft.com/archive/en-us/samples/internet/behaviors/
library/webservice/default.asp
.

Aby z niego skorzystaè, trzeba pobraè plik webservice.htc i zapisaè w katalogu, w którym prze-
chowywane sñ skrypty przykäadów. Rozszerzenie .htc oznacza kontrolkö HTML (HTML control),
zwanñ teĔ funkcjñ (ang. behavior) przeglñdarki Internet Explorer. Do zaäadowania pliku säuĔy
niestandardowa instrukcja stylu CSS, obsäugiwana jedynie w aplikacjach Internet Explorer.

<div id="WebService" style="behavior:url(webservice.htc);"></div>

Nazwa podana jako wartoĈè atrybutu 

id

 moĔe byè wykorzystana w skrypcie w JavaScript

zarówno do odwoäania do samej kontrolki HTML, jak i do odwoäania do usäugi sieciowej
z niñ zwiñzanej.

Powiñzanie kontrolki z usäugñ wymaga zdefiniowania odsyäacza do opisu WSDL danej usäugi
sieciowej. Wykorzystuje siö do tego celu metodö 

useService()

 zapisanñ w pliku .htc. Konieczne

jest  równieĔ  okreĈlenie  niepowtarzalnego  identyfikatora,  który  umoĔliwi  póĒniejsze  odwoäy-
wanie siö do danej usäugi sieciowej.

WebService.useService("MathService.asmx?WSDL", "MathService");

background image

Wykorzystanie us

ĥug sieciowych z poziomu skryptu JavaScript

121

Po tych operacjach moĔna wywoäaè usäugö. KolejnoĈè parametrów przekazywanych do me-
tody 

callService()

 — odpowiadajñcej za wywoäanie usäugi sieciowej — róĔni siö od stoso-

wanej w obiektach poĈredniczñcych ASP.NET AJAX. Oto lista tych parametrów:

referencja do metody zwrotnej,

nazwa wywoäywanej metody sieciowej,

parametry przekazywane do usäugi sieciowej.

Rozwiñzanie to nie zapewnia obsäugi bäödów (w przeciwieþstwie do mechanizmów ASP.NET
AJAX, które dostarczajñ wyjñtki do skryptu klienckiego).

W przypadku odwoäania do usäugi 

MathService

 podzielenie dwóch liczb wymagaäoby wy-

konania nastöpujñcej instrukcji:

WebService.MathService.callService(
  callComplete,
  "DivideNumbers",
  6, 7);

Funkcja zwrotna otrzymuje wówczas obiekt, którego atrybut 

value

 zawiera wynik zwrócony

przez usäugö sieciowñ.

function callComplete(result) {
  document.getElementsById("c").innerHTML = result.value;
}

Peäny kod aplikacji zostaä zamieszczony w przykäadzie 5.7.

Przykäad 5.7. Wywoäanie usäugi sieciowej w przeglñdarce Internet Explorer

MathServiceInternetExplorer.htm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>ASP.NET AJAX</title>

  <script language="Javascript" type="text/javascript">

  function callService(f) {
    document.getElementById("c").innerHTML = "";
    WebService.useService("MathService.asmx?WSDL", "MathService");
    WebService.MathService.callService(
      callComplete,
      "DivideNumbers",
      f.elements["a"].value, f.elements["b"].value);
  }

  function callComplete(result) {
    document.getElementById("c").innerHTML = result.value;
  }
  </script>

</head>
<body>
  <div id="WebService" style="behavior:url(webservice.htc);">
  </div>
  <form method="post" onsubmit="return false;">
    <div>
      <nobr>

background image

122

_

Rozdzia

ĥ 5. Usĥugi sieciowe

        <input type="text" id="a" name="a" size="2" />
        :
        <input type="text" id="b" name="b" size="2" />
        =
        <span id="c" style="width: 50px;"></span>
      </nobr>
      <br />
      <input type="button" value="Podziel liczby" onclick="callService(this.form);" />
    </div>
  </form>
</body>
</html>

JeĈli kontrolka HTML usäugi sieciowej nie zostanie zdefiniowana na poczñtku sekcji

<body>

,  przeglñdarka  moĔe  wygenerowaè  niepokojñce  komunikaty  o  bäödach,

wäñcznie z informacjñ o tym, Ĕe obiekt 

WebService

 nie zostaä zdefiniowany (mimo

prawidäowego dziaäania instrukcji 

window.alert(WebService)

).

Us

ĥugi sieciowe w przeglédarkach Mozilla

Obsäuga usäug sieciowych zostaäa zaimplementowana równieĔ w wydawanych ostatnio wer-
sjach przeglñdarek Mozilla. Ma ona charakter wbudowanego rozszerzenia. Niestety, kompo-
nent odpowiedzialny za komunikacjö z  usäugami sieciowymi najwyraĒniej  nie  zyskaä  szcze-
gólnego zainteresowania u osób skupionych wokóä projektu Mozilla, choè trzeba przyznaè, Ĕe
poprawnie wykonuje swoje zadanie. W rezultacie nie towarzyszy mu Ĕadna dokumentacja,
a informacje na temat jego uĔycia sñ czösto sprzeczne. Rozwiñzanie prezentowane w dalszej
czöĈci punktu pozwala na realizacjö zadnia, ale wymaga dodania sporej iloĈci kodu.

Za komunikacjö z usäugami sieciowymi odpowiada klasa 

SOAPCall

. PoniewaĔ opiera siö ona

na standardzie SOAP 1.1,  programista  musi  zdefiniowaè nagäówek 

SOAPAction

  (dostöpny

w formie wäaĈciwoĈci klasy 

SOAPClass

) oraz adres URL pliku usäugi sieciowej. Oto instrukcje

charakterystyczne dla omawianego przykäadu:

var soapcall = new SOAPCall( );
soapcall.actionURI = "http://hauser-wenz.de/AspNetAJAX/DivideNumbers";
soapcall.transportURI =
"http://localhost:1234/AJAXEnabledWebSite1/MathServiceDocEnc.asmx";

WartoĈè wäaĈciwoĈci 

transportURI

 musi bezwzglödnie odpowiadaè adresowi URL.

Trzeba wiöc pamiötaè o dostosowaniu ciñgu URI (szczególnie numeru portu, jeĈli do
uruchamiania aplikacji jest wykorzystywany serwer testowy Ĉrodowiska Visual Studio
lub Visual Web Developer) do ustawieþ lokalnego systemu.

Wszystkie  parametry  przekazywane  do  usäugi  sñ  zmiennymi  typu 

SOAPParameter

.  W  kon-

struktorze klasy parametru naleĔy wskazaè wartoĈè parametru, a nastöpnie jego nazwö.

var p1 = new SOAPParameter(6, "a");
var p2 = new SOAPParameter(7, "b");

Bardzo waĔne jest wykonanie nastöpnej czynnoĈci. Jej ewentualne pominiöcie spowoduje, Ĕe
Ĕñdanie SOAP zostanie przesäane do serwera (odebrana zostanie równieĔ wartoĈè wyniku),
ale nie bödñ do niego doäñczone parametry. W przypadku dzielenia liczb oznaczaäoby to nie-
zamierzone wygenerowanie wyjñtku dzielenia przez zero (ang. divie by zero).

background image

Wykorzystanie us

ĥug sieciowych z poziomu skryptu JavaScript

123

Zadanie polega na osobistym ustaleniu wäaĈciwego kodowania dla wartoĈci liczbowych.
W  tym  celu  naleĔy  zaäadowaè  odpowiedniñ  przestrzeþ  nazw,  która  obejmuje  typ  SOAP

integer

. Nastöpnie trzeba okreĈliè wartoĈè wäaĈciwoĈci 

schemaType

 wszystkich parametrów,

które powinny byè przekazane do usäugi sieciowej, przypisujñc im wygenerowane typy danych.
Kod realizujñcy opisane zadania zostaä zamieszczony poniĔej.

var senc = new SOAPEncoding( );
assenc = senc.getAssociatedEncoding(
  "http://schemas.xmlsoap.org/soap/encoding/",
  false);
var scoll = assenc.schemaCollection;
var stype = scoll.getType(
  "integer",
  "http://www.w3.org/2001/XMLSchema");
p1.schemaType = stype;
p2.schemaType = stype;

Kolejna  czynnoĈè  polega  na  przygotowaniu  wywoäania  usäugi  sieciowej.  SäuĔy  do  tego
metoda 

encode()

, wymagajñca przekazania do niej kilku parametrów, zgodnie z poniĔszym

przykäadem.

soapcall.encode(
  0,                                    //warto

Łð domyŁlna dla protokoĪu SOAP 1.1

  "DivideNumbers",                      //nazwa metody sieciowej
  "http://hauser-wenz.de/AspNetAJAX/",  //przestrze

Ĭ nazw

  0,                                    //liczba dodatkowych nag

Īówków

  new Array( ),                         //dodatkowe nag

Īówki

  2,                                    //liczba parametrów
  new Array(p1, p2)                     //parametry
);

W  koþcu  moĔna  wywoäaè  usäugö  sieciowñ  (w  sposób  asynchroniczny),  wykonujñc  metodö

asyncInvoke()

. Parametrem metody jest referencja funkcji zwrotnej.

soapcall.asyncInvoke(callComplete);

Funkcja zwrotna otrzymuje trzy parametry:

dokument XML bödñcy wynikiem wywoäania usäugi sieciowej,

obiekt 

SOAPCall

 (gdyby konieczne byäo przeanalizowanie nagäówków SOAP),

kod statusowy HTTP dla wywoäania.

Ostatni  etap  procedury  sprowadza  siö  do  wyodröbnienia  danych  wynikowych  z  treĈci  do-
starczonego dokumentu XML. Przyjrzyjmy siö zatem odpowiedzi XML zwracanej po odwo-
äaniu siö do  usäugi 

MathService

  —  dane  te  moĔna  pozyskaè  za  pomocñ  programu  Fiddler

(dla  systemu  Windows)  (http://www.fiddlertool.com/fiddler)  lub  rozszerzenia  przeglñdarki
Mozilla Live HTTP Headers (http://livehttpheaders.mozdev.org/):

<?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>
     <DivideNumbersResponse xmlns="http://hauser-wenz.de/AspNetAJAX/">
      <DivideNumbersResult>0.857142866</DivideNumbersResult>
    </DivideNumbersResponse>
  </soap:Body>
</soap:Envelope>

background image

124

_

Rozdzia

ĥ 5. Usĥugi sieciowe

Wiöcej  informacji  na  temat  sposobu  analizowania  Ĕñdaþ  HTTP  (wysyäanych  przez
aplikacje Ajax) oraz debugowania aplikacji Ajax znajduje siö w dodatku A.

Analizujñc dane w formacie XML, nietrudno zauwaĔyè, Ĕe wyodröbnienie wartoĈci 

0.857142866

wymaga przeprowadzenia nastöpujñcych operacji:

odwoäania siö do wäaĈciwoĈci 

body

, która zapewni dostöp do elementu 

<soap:Body>

;

odwoäania siö do wäaĈciwoĈci 

firstChild

, która zapewni dostöp do elementu 

<Divide-

NumbersResponse>

;

ponownego wykorzystania wäaĈciwoĈci 

firstChild

 do pobrania elementu 

<DivideNum-

bersResult>

;

wykorzystania po raz trzeci wäaĈciwoĈci 

firstChild

, aby uzyskaè dostöp do wözäa tek-

stowego w elemencie 

<DivideNumbersResult>

;

wykorzystania wäaĈciwoĈci 

data

 do pobrania ciñgu zapisanego w wöĒle tekstowym.

TreĈè skryptu JavaScript niezbödnego do wyodröbnienia wyniku z dokumentu dostarczonego
przez usäugö sieciowñ zostaäa zamieszczona poniĔej.

function callComplete(result, soapcall, status) {
  document.getElementById("c").innerHTML =
    result.body.firstChild.firstChild.firstChild.data;
}

ãñczñc wszystkie opisane fragmenty skryptów, uzyskujemy kod przedstawiony w przykäa-
dzie 5.8. Trzeba jednak pamiötaè, Ĕe aplikacja bödzie dziaäaäa zgodnie z oczekiwaniami tylko
wtedy, gdy system bödzie miaä dostöp do internetu — przeglñdarki Mozilla muszñ mieè do-
stöp do informacji na temat schematów SOAP.

Przykäad 5.8. Wywoäanie usäugi sieciowej w przeglñdarce Mozilla

MathServiceMozilla.htm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>ASP.NET AJAX</title>

  <script language="Javascript" type="text/javascript">
    function callService(f) {
    document.getElementById("c").innerHTML = "";
    var soapcall = new SOAPCall( );
    soapcall.actionURI = "http://hauser-wenz.de/AspNetAJAX/DivideNumbers";

soapcall.transportURI="http://localhost:1041/AJAXEnabledWebSite1/MathService.asmx";
    var p1 = new SOAPParameter(parseInt(f.elements["a"].value), "a");
    var p2 = new SOAPParameter(parseInt(f.elements["b"].value), "b");

    var senc = new SOAPEncoding( );
    assenc = senc.getAssociatedEncoding(
      "http://schemas.xmlsoap.org/soap/encoding/",
      false);
    var scoll = assenc.schemaCollection;
    var stype = scoll.getType(
      "integer",

background image

Wykorzystanie us

ĥug sieciowych z poziomu skryptu JavaScript

125

      "http://www.w3.org/2001/XMLSchema");
    p1.schemaType = stype;
    p2.schemaType = stype;

    soapcall.encode(
      0,                                    //warto

Łð domyŁlna dla protokoĪu SOAP 1.1

      "DivideNumbers",                      //nazwa metody sieciowej
      "http://hauser-wenz.de/AspNetAJAX/",  //przestrze

Ĭ nazw

      0,                                    //liczba dodatkowych nag

Īówków

      new Array( ),                         //dodatkowe nag

Īówki

      2,                                    //liczba parametrów
      new Array(p1, p2)                     //parametry
    );
    soapcall.asyncInvoke(callComplete);
  }
  function callComplete(result, soapcall, status) {
    document.getElementById("c").innerHTML =
      result.body.firstChild.firstChild.firstChild.data;
  }
  </script>

</head>
<body>
  <form method="post" onsubmit="return false;">
    <div>
      <nobr>
        <input type="text" id="a" name="a" size="2" />
        :
        <input type="text" id="b" name="b" size="2" />
        =
        <span id="c" style="width: 50px;"></span>
      </nobr>
      <br />
      <input type="button" value="Podziel liczby" onclick="callService(this.form);" />
    </div>
  </form>
</body>
</html>

Us

ĥugi sieciowe w obydwu przeglédarkach

Przeglñd  technik  korzystania  z  usäug  sieciowych  z  poziomu  skryptu  JavaScript  w  przeglñ-
darkach Internet Explorer i Mozilla zakoþczymy rozwiñzaniem, które äñczy obydwie metody
na jednej stronie. W tym celu musimy przede wszystkim ustaliè, w jaki sposób rozpoznawa-
ny  bödzie  rodzaj  przeglñdarki.  Zgodnie  z  informacjami  zamieszczonymi  w  rozdziale  2,  naj-
korzystniejsze wydaje siö sprawdzenie zestawu funkcji przeglñdarki, a nie ich typu. Zasada
ta zostaäa wykorzystana podczas opracowywania kodu z przykäadu 5.9 (jej opis znajduje siö
w rozdziale 2, w czöĈci dotyczñcej powoäywania obiektu 

XMLHttpRequest

). Rozwiñzanie po-

lega na utworzeniu obiektu wäaĈciwego dla jednej przeglñdarki. JeĈli to siö uda, dalsza czöĈè
kodu zostanie wykonana zgodnie z zaäoĔeniami. W przeciwnym przypadku wykorzystane
zostanñ instrukcje wäaĈciwe dla drugiej przeglñdarki. Poszczególne wywoäania zostaäy za-
pisane w dwóch zagnieĔdĔonych konstrukcjach 

try

 … 

catch

.

background image

126

_

Rozdzia

ĥ 5. Usĥugi sieciowe

Dost

ýp do zdalnych usĥug sieciowych

w przegl

édarkach Mozilla

Model zabezpieczeþ przeglñdarki Mozilla umoĔliwia odwoäania do zdalnych usäug sieciowych.
Wykonanie  skryptu  wiñĔe  siö  jednak  z  wyĈwietleniem  okna  dialogowego,  w  którym  uĔyt-
kownik  musi  zezwoliè  na  takñ  operacjö  (rysunek  5.7).  Wymagane  jest  w  tym  przypadku
uprawnienie 

UniversalBrowserRead

, oznaczajñce, Ĕe przeglñdarka moĔe pobieraè dane

z dowolnego serwera (wäñczajñc w to zarówno serwery zdalne, jak i lokalny system plików).

netscape.security.PrivilegeManager.enablePrivilege(
  "UniversalBrowserRead");

Rysunek 5.7. ēñdanie zwiökszenia poziomu uprawnieþ w przeglñdarce Firefox

DomyĈlna konfiguracja przeglñdarek Mozilla i Firefox (a takĔe kilku  innych)  powoduje  na-
danie wspomnianego uprawnienia tylko w dostöpie do plików lokalnych (z definicjñ protokoäu

file://

). Mechanizm ten znajduje wiöc zastosowanie gäównie w aplikacjach intranetowych.

Wyglñd okna dialogowego z Ĕñdaniem zwiökszenia poziomu uprawnieþ zostaä pokazany na
rysunku 5.7.

Przykäad 5.9. Wywoäanie usäugi sieciowej w dowolnej z przeglñdarek Internet Explorer i Mozilla

MathService.htm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>ASP.NET AJAX</title>

  <script language="Javascript" type="text/javascript">
    function callService(f) {
    document.getElementById("c").innerHTML = "";
    try {
      WebService.useService("MathService.asmx?WSDL", "MathService");
      WebService.MathService.callService(
        callComplete,
        "DivideNumbers",
        parseInt(f.elements["a"].value), parseInt(f.elements["b"].value));
    } catch (e) {
      try {
        var soapcall = new SOAPCall( );
        soapcall.actionURI = "http://hauser-wenz.de/AspNetAJAX/DivideNumbers";

background image

Czytaj dalej...

Wykorzystanie us

ĥug sieciowych z poziomu skryptu JavaScript

127

        soapcall.transportURI = "http://localhost:1041/AJAXEnabledWebSite1/
        MathService.asmx";

        var p1 = new SOAPParameter(parseInt(f.elements["a"].value), "a");
        var p2 = new SOAPParameter(parseInt(f.elements["b"].value), "b");

        var senc = new SOAPEncoding( );
        assenc = senc.getAssociatedEncoding(
          "http://schemas.xmlsoap.org/soap/encoding/",
          false);
        var scoll = assenc.schemaCollection;
        var stype = scoll.getType(
          "integer",
          "http://www.w3.org/2001/XMLSchema");
        p1.schemaType = stype;
        p2.schemaType = stype;

        soapcall.encode(
          0,                                   //warto

Łð domyŁlna dla protokoĪu SOAP 1.1

          "DivideNumbers",                      //nazwa metody sieciowej
          "http://hauser-wenz.de/AspNetAJAX/",  //przestrze

Ĭ nazw

          0,                                    //liczba dodatkowych nag

Īówków

          new Array( ),                         //dodatkowe nag

Īówki

          2,                                    //liczba parametrów
          new Array(p1, p2)                     //parametry
        );
        soapcall.asyncInvoke(callComplete);
      } catch (e) {
        window.alert("Twoja przegl

ìdarka nie jest obsĨugiwana.");

      }
    }
  }

  function callComplete(result, soapcall, status) {
    if (result.value != null) {
      document.getElementById("c").innerHTML = result.value;
    } else {
      document.getElementById("c").innerHTML =
      result.body.firstChild.firstChild.firstChild.data;
    }
  }
</script>

</head>
<body>
  <div id="WebService" style="behavior: url(webservice.htc);">
  </div>
  <form method="post" onsubmit="return false;">
    <div>
      <nobr>
        <input type="text" id="a" name="a" size="2" />
        :
        <input type="text" id="b" name="b" size="2" />
        = <span id="c" style="width: 50px;" ></span>
      </nobr>
      <br />
      <input type="button" value="Podziel liczby" onclick="callService(this.form);" />
    </div>
  </form>
</body>
</html>