background image

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

e-mail: helion@helion.pl

ASP.NET 3.5. Tworzenie
portali internetowych
w nurcie Web 2.0

Autor: Omar Al Zabir
T³umaczenie: Marek Pa³czyñski
ISBN: 978-83-246-1841-5 
Tytu³ orygina³u: 

Building a Web 2.0

Portal with ASP.NET 3.5 

Stron: 320

Poznaj sekrety zaawansowanych technologii budowy

portali internetowych Web 2.0

• Jak zaprojektowaæ witrynê dla platformy ASP.NET i ASP.NET AJAX?
• Jak rozbudowaæ serwis zgodnie z zasadami ergonomii?
• Jak zwiêkszyæ wydajnoœæ serwera?

Portale sieciowe Web 2.0, opieraj¹ce siê na technologii AJAX, umo¿liwiaj¹ u¿ytkownikom 
personalizowanie stron, a tak¿e agregowanie danych z ró¿nych Ÿróde³. Wszystko
to sprawia, ¿e s¹ doskona³ymi serwisami korporacyjnymi i nale¿¹ do najefektywniejszych 
aplikacji sieciowych. Zastosowanie mechanizmów AJAX pozwala na udostêpnienie 
interaktywnego i rozbudowanego interfejsu, dzia³aj¹cego znacznie szybciej i bardziej 
wydajnie ni¿ w tradycyjnych serwisach. Natomiast wykorzystanie wid¿etów (komponentów 
typu plag-and-play) zapewnia przejrzystoœæ architektury portalu i ³atwoœæ jego rozbudowy, 
poniewa¿ s¹ one opracowywane niezale¿nie od warstwy rdzeniowej systemu.

Ksi¹¿ka „ASP.NET 3.5. Tworzenie portali internetowych w nurcie Web 2.0” zawiera opis 
najnowszych metod i technologii projektowania oraz budowy portali z wykorzystaniem 
platformy ASP.NET i œrodowiska ASP.NET AJAX. W podrêczniku przedstawiono tak¿e 
praktyczne rozwi¹zania problemów zwi¹zanych z projektowaniem, wdra¿aniem, 
utrzymaniem, a tak¿e skalowaniem i usprawnianiem serwisu. Dziêki tej pozycji poznasz 
poszczególne fazy budowy prototypowego portalu, zaawansowane techniki technologii 
AJAX oraz sposoby optymalizacji kodu. Nauczysz siê m. in. przygotowywaæ wid¿ety 
klienckie za pomoc¹ kodu JavaScript, tworzyæ w³asne mechanizmy obs³ugi wywo³añ, 
zwiêkszaæ wydajnoœæ serwera i skalowalnoœæ us³ug sieciowych. Zdobêdziesz zatem ca³¹ 
potrzebn¹ Ci wiedzê i umiejêtnoœci, które pozwol¹ zbudowaæ stabilny, nowoczesny
i bezpieczny portal internetowy.

• Wprowadzenie do budowy portali internetowych
• Architektura portali i wid¿etów
• Projekt warstwy sieciowej w œrodowisku ASP. NET AJAX
• Projekt warstwy danych i warstwy biznesowej na platformie NET 3.5
• Wid¿ety klienckie
• Optymalizacja pracy œrodowiska ASP.NET AJAX
• Tworzenie asynchronicznych i transakcyjnych us³ug sieciowych
    z uwzglêdnieniem buforowania danych
• Skalowalnoœæ us³ug sieciowych
• Zwiêkszenie wydajnoœci serwera i klienckiej czêœci aplikacji
• Zarz¹dzanie witryn¹

Zaprojektuj bardzo wydajn¹ i supernowoczesn¹ witrynê internetow¹ 

background image

 

 

 

 

 

5

Spis tre

ļci

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

 

1.  Wprowadzenie do portali internetowych i serwisu Dropthings.com ....................... 15

Definicja portalu sieciowego 

16

Definicja portalu Web 2.0 

18

Korzystanie z portalu 

18

Nawigacja w portalu Dropthings 

19

Wykorzystanie platformy ASP.NET AJAX 

23

Wykorzystanie jözyka C# 3.0 i platformy .NET 3.5 

23

Podsumowanie 

25

Dodatkowe Ēródäa informacji 

25

  2.  Architektura portalu i wid

Ŝetów ................................................................................27

Wykorzystanie platformy widĔetów 

35

Dodawanie widĔetów 

41

Wywieranie korzystnego wraĔenia podczas pierwszej wizyty uĔytkownika 

43

Przygotowanie strony podczas drugiej wizyty uĔytkownika 

46

Zwiökszenie wydajnoĈci kodu ASP.NET AJAX 

47

Uwierzytelnianie i autoryzacja 

52

Ochrona przed atakami DoS 

54

Podsumowanie 

56

  3.  Projekt warstwy sieciowej w 

ļrodowisku ASP.NET AJAX  .........................................57

Strona startowa portalu sieciowego 

57

Budowa wäasnego rozszerzenia „przeciñgnij i upuĈè”

dla wielokolumnowej strefy zrzutu 

75

Klasa WidgetContainer 

88

Budowanie widĔetów 

95

Przeäñczanie stron — symulowanie operacji pobrania strony 

105

background image

_  Spis treļci

Wykorzystanie obiektu Profile w usäudze sieciowej 

107

Implementacja uwierzytelniania i autoryzacji 

108

Implementacja mechanizmu wylogowania 

110

Podsumowanie 

112

Dodatkowe Ēródäa informacji 

112

  4.  Projekt warstwy dost

ýpu do danych i warstwy biznesowej na platformie .NET 3.5  ....113

Podstawy mechanizmu LINQ to SQL 

113

Budowanie warstwy dostöpu do danych

z wykorzystaniem mechanizmu LINQ to SQL 

116

Podstawy technologii Windows Workflow Foundation 

124

Budowa warstwy biznesowej z wykorzystaniem mechanizmu WF 

125

Implementacja klasy DashboardFacade 

139

Podsumowanie 

144

  5.  Wid

Ŝety klienckie  ...................................................................................................... 145

OpóĒnienie äadowania widĔetów serwerowych 

146

PoĈrednik w dostöpie do danych 

149

Budowa klienckiego widĔetu RSS 

153

Budowa klienckiego widĔetu Flickr 

157

Podsumowanie 

161

  6.  Optymalizacja pracy 

ļrodowiska ASP.NET AJAX ..................................................... 163

Poäñczenie wielu wywoäaþ Ajax w jedno wywoäanie 

163

Synchronizacja i kolejkowanie odwoäaþ Ajax 

165

Zastosowanie wywoäaþ HTTP GET zamiast HTTP POST 

177

Korzystanie z funkcji this 

178

Podsumowanie 

179

  7.  Tworzenie asynchronicznych i transakcyjnych us

ĥug sieciowych

z uwzgl

ýdnieniem buforowania danych ...................................................................181

SkalowalnoĈè usäug sieciowych 

181

Asynchroniczne metody sieciowe 

183

Zmiany w Ĉrodowisku ASP.NET AJAX

umoĔliwiajñce wywoäywanie usäug sieciowych 

187

Opracowanie wäasnego mechanizmu obsäugi usäug sieciowych 

189

Przygotowanie asynchronicznego poĈrednika,

który bödzie uwzglödniaä buforowanie danych 

200

Skalowanie i zabezpieczanie usäug poĈredniczñcych 

202

Podsumowanie 

207

background image

 

 

 

Spis tre

ļci 

_ 

7

  8.  Zwi

ýkszanie wydajnoļci i skalowalnoļci serwera ...................................................209

Uzupeänienie kodu o funkcje umoĔliwiajñce identyfikacjö

problemów wydajnoĈciowych 

210

Optymalizacja potokowego przetwarzania Ĕñdaþ HTTP 

211

Optymalizacja platformy ASP.NET 2.0 (lub 3.5) przed udostöpnieniem serwisu 

212

Optymalizacja zapytaþ kierowanych do tabel usäugi ASP.NET Membership 

213

Optymalizacja usäugi Profile platformy ASP.NET 2.0 (lub 3.5)

przed udostöpnieniem serwisu 

216

Zagadnienia zwiñzane z wykorzystaniem platformy ASP.NET

na serwerach uĔytkowych 

231

Przekierowanie ruchu do nowej witryny 

233

Podsumowanie 

235

  9.  Zwi

ýkszenie wydajnoļci klienckiej czýļci aplikacji ..................................................237

Buforowanie danych sieciowych 

237

Sieci dostarczania treĈci 

248

Optymalizacja pracy interpretera JavaScript w przeglñdarce Internet Explorer 

252

Zmniejszenie rozmiaru pola danych w wywoäaniach usäug sieciowych 

260

ãadowanie interfejsu uĔytkownika na Ĕñdanie 

261

Odczyt z wyprzedzeniem w wywoäaniach Ajax 

264

Ukrywanie kodu HTML w obszarze <textarea> 

264

Podsumowanie 

267

  10.  Rozwi

ézywanie typowych problemów z wdroŜeniem i utrzymaniem witryny

oraz zarz

édzaniem nié ..............................................................................................269

Uruchamianie witryny w farmie serwerów 

269

TrzynaĈcie katastrof, które mogñ wystñpiè w kaĔdej chwili 

276

Wybór odpowiedniej firmy hostingowej 

288

Wybór narzödzia do monitorowania pracy witryny 

290

Konfiguracja wskaĒników wydajnoĈci 

292

Podsumowanie 

299

Skorowidz ............................................................................................................................. 301

background image

145

ROZDZIA

Ĥ 5.

Wid

Ŝety klienckie

W rozdziale 3. zostaäy opisane zagadnienia zwiñzane z budowaniem widĔetów serwerowych
— widĔetu czytnika RSS (lub Atom) oraz widĔetu fotograficznego Flickr. Zaletñ stosowania
widĔetów serwerowych jest to, Ĕe moĔna wykorzystywaè komfortowe Ĉrodowisko pracy
(oprogramowania Visual Studio) do ich tworzenia i debugowania, uĔywajñc przy tym swoje-
go  ulubionego  jözyka  programowania  (C#  lub  VB.NET).  Jednak  widĔety  serwerowe  opóĒ-
niajñ äadowanie strony i wymagajñ czöstego odsyäania danych. Wszystkie widĔety widoczne
na stronie muszñ zostaè zaäadowane po stronie serwera podczas pierwszego pobierania stro-
ny oraz w czasie jej asynchronicznych uaktualnieþ. JeĈli widĔety pobierajñ dane z zewnötrz-
nych Ēródeä, czas pobierania strony zaleĔy od äñcznego czasu  przygotowania  kaĔdej  z  nich.
Ponadto  widĔety  serwerowe  wymagajñ  odsyäania  danych  nawet  podczas  nieskomplikowa-
nych  operacji  takich  jak  stronicowanie  lub  edytowanie  pozycji  na  liĈcie.  Przekazywanie  da-
nych jest konieczne, poniewaĔ po stronie serwera jest przechowywany model obiektu, który
z kolei jest powiñzany z informacjami zapisanymi w bazie danych. Po stronie klienta nie sñ
przechowywane  Ĕadne  informacje,  które  mogäyby  usprawniè  niektóre  operacje  realizowane
w przeglñdarce. Zatem mimo Ĕe widĔety serwerowe znacznie uäatwiajñ opracowywanie ko-
du i zarzñdzanie nim, charakteryzujñ siö niĔszñ wydajnoĈciñ pracy w porównaniu z  widĔe-
tami klienckimi.

WidĔety klienckie bazujñ przede wszystkim na technologii JavaScript, dziöki czemu zapew-
niajñ znacznie wyĔszy poziom interaktywnoĈci i funkcjonalnoĈci w operacjach niewymagajñ-
cych odsyäania danych. WidĔety klienckie pobierajñ dane z zewnötrznych Ēródeä bezpoĈred-
nio  z  poziomu  skryptu  JavaScript  i  przechowujñ  model  obiektu  oraz  informacje  o  stanie
obiektu po stronie klienta. Dziöki temu realizujñ zadania stronicowania, edycji czy sortowania
bezpoĈrednio w przeglñdarce bez odsyäania danych do serwera. Co wiöcej, widĔety klienckie
mogñ  buforowaè  zewnötrzne  informacje  w  pamiöci  przeglñdarki,  wiöc  przygotowywanie
strony podczas kolejnych wizyt uĔytkownika moĔe przebiegaè znacznie szybciej niĔ w przy-
padku widĔetów serwerowych. Dane niezbödne do wyĈwietlenia elementu sñ bowiem prze-
chowywane  w  przeglñdarce.  W  tym  rozdziale  zostanie  omówione  zagadnienie  opóĒnienia
äadowania widĔetów serwerowych w celu przyspieszenia äadowania strony. Rozwiñzanie to
zostanie przedstawione na przykäadzie dwóch klienckich widĔetów — czytnika danych RSS
oraz komponentu wyĈwietlajñcego fotografie serwisu Flickr. Opisana zostanie takĔe procedu-
ra budowy poĈredniczñcej usäugi sieciowej, która pozwoli widĔetom klienckim na pobieranie
danych z zewnötrznych Ēródeä i buforowanie ich w pamiöci przeglñdarki.

background image

146

_

Rozdzia

ĥ 5. WidŜety klienckie

Opó

Śnienie ĥadowania widŜetów serwerowych

Podczas interpretowania skryptu strony na serwerze konieczne jest wykonanie kodu wszyst-
kich zawartych na niej widĔetów. Powoduje to znaczne opóĒnienie w dostarczaniu treĈci za-
równo  podczas  pierwszej  wizyty,  jak  i  w  czasie  kolejnych  wizyt  oraz  w  przypadku  przeäñ-
czania zakäadek. WidĔety pobierajñ dane z zewnötrznych Ēródeä lub serwerowej bazy danych
w kodzie zdarzenia 

Page_Load

. Wywoäanie tego zdarzenia w kaĔdym z widĔetów (które

funkcjonujñ w taki sam sposób jak kontrolki sieciowe) okazuje siö czasochäonne. Aby zwiök-
szyè odczuwalnñ szybkoĈè äadowania strony, trzeba dostarczyè do przeglñdarki szkielet wi-
dĔetów  wraz  z  komunikatami  informujñcymi  o  pobieraniu  danych,  a  nastöpnie  stopniowo
wypeäniaè poszczególne kontrolki wäaĈciwñ treĈciñ.

Rozwiñzanie to jest wykorzystywane na przykäad w portalu Pageflakes, w którym najpierw
äaduje siö szablon  widĔetów,  a w  obszarze  kaĔdej  z  kontrolek  wyĈwietla  siö  komunikat
o trwajñcym procesie pobierania informacji.  KaĔdy  z widĔetów wywoäuje  usäugö  sieciowñ
i pobiera dane niezbödne do  wyĈwietlenia  swojej  zawartoĈci.  Mimo Ĕe  caäkowity  czas  äado-
wania strony jest doĈè däugi (kaĔdemu widĔetowi odpowiada co najmniej jedno wywoäanie
usäugi  sieciowej),  subiektywne  odczucie  uĔytkownika  okazuje  siö  korzystniejsze,  poniewaĔ
moĔe on obserwowaè caäy proces. W rezultacie zaäadowanie kolejno wszystkich widĔetów na
stronö  jest  postrzegane  jako  znacznie  szybszy  proces  niĔ  w  klasycznym  mechanizmie  gene-
rowania dokumentu.

OpóĒnione äadowanie oznacza, Ĕe widĔety nie pobierajñ danych w kodzie zdarzenia 

Page_Load

,

ale w procedurze asynchronicznej aktualizacji wyzwalanej przez komponent stopera. WidĔet
najpierw wyĈwietla komunikat o postöpie äadowania, a nastöpnie wykorzystuje obiekt 

Timer

do  wyzwolenia  asynchronicznej  aktualizacji.  Z  kolei  w  czasie  asynchronicznej  aktualizacji
komponent  pobiera  informacje  z  zewnötrznych  Ēródeä  danych  i  przygotowuje  kod  wyni-
kowy. Technika ta eliminuje problem wstrzymywania wykonywania procedury 

Page_Load

w  oczekiwaniu  na  dostarczenie  zewnötrznych  danych.  Czas  äadowania  caäej  strony  nie  jest
wówczas uzaleĔniony od szybkoĈci gromadzenia danych z zewnötrznych Ēródeä. Jednym
z  najäatwiejszych  sposobów  implementacji  omawianego  rozwiñzania  jest  zastosowanie  kon-
trolki 

MultiView

, która bödzie zawieraäa widok z komunikatem o postöpie prac oraz widok

obejmujñcy  gäówny  interfejs  uĔytkownika  widĔetu.  Kontrolka 

Timer

  moĔe  zainicjowaè  ode-

säanie danych po  pewnym czasie  (na  przykäad  100 ms), które  z  kolei spowoduje zmianö
widoku na wäaĈciwy interfejs uĔytkownika oraz wyäñczenie stopera.

Opó

Śnienie ĥadowania widŜetu RSS (Atom)

Pierwszy etap prac polega na przeksztaäceniu widĔetu RSS w taki sposób, aby opóĒniä äado-
wanie treĈci, oraz na podzieleniu procedury äadowania danych na dwie fazy. Po modyfikacji
strona bödzie pobierana bardzo szybko. Jednak w miejscu widĔetów wyĈwietli siö komunikat
informujñcy  o  äadowaniu  danych.  Poszczególne  widĔety  bödñ  äadowane  kolejno  jeden  po
drugim.  Interfejs  uĔytkownika  widĔetu  trzeba  wiöc  podzieliè  na  dwa  widoki,  obsäugiwane
przez  kontrolkö 

MultiView

. Pierwszy  z  nich  obejmuje  jedynie  komunikat  o  postöpie  prac.

Natomiast  drugi  wykorzystuje  kontrolkö 

DataList

  o  nazwie 

FeedList

.  Kod  stosownego

skryptu zostaä przedstawiony w listingu 5.1.

background image

Opó

Śnienie ĥadowania widŜetów serwerowych

147

Listing 5.1. WidĔet RSS z opóĒnionym äadowaniem podzielony na dwa widoki.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="RSSWidget.ascx.cs"
Inherits="Widgets_RSSWidget" EnableViewState="false" %>
<asp:Panel ID="SettingsPanel" runat="Server" Visible="False" >
...
</asp:Panel>

<asp:MultiView ID="RSSMultiview" runat="server" ActiveViewIndex="0">

<asp:View runat="server" ID="RSSProgressView">
    <asp:image runat="server" ID="image1" ImageAlign="middle"
        ImageUrl="~/indicator.gif" />
    <asp:Label runat="Server" ID="label1" Text="Loading..." Font-Size="smaller"
        ForeColor="DimGray" />
</asp:View>

<asp:View runat="server" ID="RSSFeedView">

    <asp:DataList ID="FeedList" runat="Server" EnableViewState="False">
    <ItemTemplate>
    <asp:HyperLink ID="FeedLink" runat="server" Target="_blank"
        CssClass="feed_item_link" NavigateUrl='<%# Eval("link") %>'
        ToolTip='<%# Eval("description") %>'>
    <%# Eval("title") %>
    </asp:HyperLink>
    </ItemTemplate>
    </asp:DataList>

</asp:View>

</asp:MultiView>

<asp:Timer ID="RSSWidgetTimer" Interval="1" OnTick="LoadRSSView" runat="server" />

Kontrolka 

Timer

  wywoäuje  serwerowñ  funkcjö 

LoadRSSView

  w  sposób  asynchroniczny.

Funkcja z kolei zmienia bieĔñcy widok na 

RSSFeedView

 i wyĈwietlane informacje RSS zgod-

nie z kodem zamieszczonym w przykäadzie 5.2. Definicja funkcji znajduje siö w pliku kodu
towarzyszñcym kontrolce sieciowej czytnika RSS.

Listing 5.2. Funkcja LoadRSSView widĔetu RSS wyzwalana przez kontrolkö Timer.

protected void LoadRSSView(object sender, EventArgs e)
{
    this.ShowFeeds( );
    this.RSSMultiview.ActiveViewIndex = 1;
    this.RSSWidgetTimer.Enabled = false;
}

Po  wprowadzeniu  zmian  w  czasie  pierwszego  äadowania  funkcja 

Page_Load

  nie  wykonuje

Ĕadnych operacji. Jej zadanie polega na pobieraniu danych RSS jedynie w czasie asynchro-
nicznych  aktualizacji.  PoniewaĔ  procedura  obsäugi  zdarzenia 

Page_Load

  koþczy  siö  bez-

zwäocznie, czas äadowania widĔetu nie zaleĔy od czasu pobrania informacji z zewnötrznych

Ēródeä danych. Kod rozwiñzania zostaä przedstawiony w listingu 5.3.

Listing 5.3. Podczas pierwszego äadowania zdarzenie Page_Load nie powoduje wykonania jakichkolwiek instrukcji.

protected void Page_Load(object sender, EventArgs e)
{
    if (!this._Host.IsFirstLoad) this.LoadRSSView(sender, e);
}

background image

148

_

Rozdzia

ĥ 5. WidŜety klienckie

Procedura obsäugi zdarzenia 

Page_Load

 wywoäuje funkcjö 

LoadRSSView

 jedynie w przypad-

ku aktualizacji. Wówczas kod 

LoadRSSView

 jest wykonywany bardzo szybko, poniewaĔ dane

zostajñ zapisane w pamiöci podröcznej Ĉrodowiska ASP.NET.

Opó

Śnienie ĥadowania widŜetu Flickr

Procedura  opóĒnienia  äadowania  widĔetu  Flickr  jest  analogiczna  do  procedury  opóĒnienia

äadowania  widĔetu  RSS.  Do  wyĈwietlenia  komunikatu  o  postöpie  prac  trzeba  zastosowaè
kontrolkö 

MultiView

,  która  jako  drugi  widok  wyĈwietli  zaäadowane  przez  stronö  zdjöcia.

W czasie pierwszego pobierania dokumentu kod procedury 

Page_Load

 nie powinien wyko-

nywaè  Ĕadnych  czynnoĈci,  wiöc  nie  spowoduje  opóĒnienia  w  dostarczaniu  strony.  Po  prze-
kazaniu komunikatu do przeglñdarki kontrolka 

Timer

 powinna wywoäaè operacjö asynchro-

nicznej aktualizacji. Wówczas strumieþ plików zdjöciowych zostanie pobrany z serwisu Flickr
i zinterpretowany przez kod interfejsu uĔytkownika.

Problemy wynikaj

éce z opóŚnienia ĥadowania widŜetów

Choè czas pobierania strony wydaje siö krótszy, w rzeczywistoĈci caäkowity czas äadowania
danych jest znacznie däuĔszy, poniewaĔ kaĔdy widĔet musi wykonaè co najmniej jednñ asyn-
chronicznñ  aktualizacjö.  Ponadto  technika  ta  wiñĔe  siö  ze  znacznym  obciñĔeniem  skryptu
Default.aspx  ze  wzglödu  na  koniecznoĈè  asynchronicznego  aktualizowania  danych  podczas
pierwszego  äadowania.  Skrypt  Default.aspx  nie  jest  przetwarzany  raz,  ale  n  razy  przy  n  wi-
dĔetach o opóĒnionym äadowaniu danych. Asynchroniczne aktualizacje bazujñ na Ĕñdaniach
HTTP  POST,  wiöc  nie  ma  moĔliwoĈci  buforowania  informacji  pobranych  z  zewnötrznych

Ēródeä w pamiöci podröcznej przeglñdarki. Nawet jeĈli informacje w danym kanale RSS nie
zmieniñ  siö  przez  tydzieþ,  bödñ  musiaäy  zostaè  przesäane  z  serwera  podczas  ka

Ĕdej  asyn-

chronicznej aktualizacji wykonanej w tym okresie. Dane nie sñ buforowane w przeglñdarce,
wiöc czas kolejnego äadowania widĔetu nie ulega skróceniu.

Na rysunku 5.1 zostaä przedstawiony zapis asynchronicznych aktualizacji z odwoäaniem do
strony Default.aspx wykonanych przez cztery widĔety RSS z zaimplementowanñ funkcjñ opóĒ-
nionego äadowania. We wszystkich przypadkach przesyäane sñ Ĕñdania HTTP POST.

Podczas kolejnych wizyt wykonanie tych samych czterech asynchronicznych aktualizacji
koþczy  siö  zwróceniem  identycznych  wyników,  poniewaĔ  informacje  w  kanale  RSS  nie
zmieniajñ  siö  zbyt  czösto.  Nie  ma  jednak  moĔliwoĈci  zbuforowania  odpowiedzi  i  wyelimi-
nowania w ten sposób niepotrzebnych odwoäaþ. Zgodnie z wczeĈniejszym  stwierdzeniem
asynchroniczne aktualizacje, jako Ĕñdania HTTP POST, nie podlegajñ rejestracji w pamiöci
podröcznej.

Aby skróciè czas äadowania widĔetów w czasie kolejnych wizyt, naleĔy pobraè dane z prze-
glñdarki z  wykorzystaniem  Ĕñdania  HTTP  GET.  Niezbödne  jest  w  tym  przypadku  wygene-
rowanie  takich  nagäówków  odpowiedzi,  które  wskaĔñ  dane  w  pamiöci  podröcznej  przeglñ-
darki.  Do  pobrania  informacji  z  pierwotnego  Ēródäa  danych  trzeba  wykorzystaè  skrypt
JavaScript. Musi on równieĔ odpowiednio zinterpretowaè pobrane dane i przygotowaè wäa-
Ĉciwy kod HTML. A poniewaĔ nie moĔna uĔyè serwerowych mechanizmów generowania
kodu HTML, trzeba zaprojektowaè skrypty klienckie w taki sposób, aby wykorzystywaäy dane
z wczeĈniejszych wizyt na stronie.

background image

Po

ļrednik w dostýpie do danych

149

Rysunek 5.1. OdpowiedĒ na Ĕñdanie asynchronicznego uaktualnienia po uwzglödnieniu opóĒnienia
w äadowaniu widĔetu.

Jednak  przeglñdarki  nie  pozwalajñ  na  miödzydomenowe  odwoäania  do  usäug  sieciowych.
Nie moĔna wiöc zastosowaè techniki XML HTTP do bezpoĈredniego pobierania danych z ze-
wnötrznych domen. Niedopuszczalne jest na przykäad zaäadowanie dokumentu XML wprost
spod adresu http://msdn.microsoft.com/rss.xml. MoĔliwe jest natomiast wywoäanie jednej z wäa-
snych  usäug  sieciowych,  która  bödzie  peäniäa  rolö  poĈrednika  (proxy)  w  dostöpie  do  orygi-
nalnego Ēródäa danych. W nastöpnym podrozdziale zostanie przedstawiony sposób przygo-
towania  wspomnianego  poĈrednika,  który  bödzie  pobieraä  informacje  spod  zewnötrznych
adresów URL i realizowaä zadania zwiñzane z inteligentnym buforowaniem danych.

Po

ļrednik w dostýpie do danych

PoĈrednik w dostöpie do danych jest usäugñ sieciowñ, pracujñcñ na jednym z serwerów ser-
wisu, która moĔe pobieraè informacje spod zewnötrznych adresów URL i przekazywaè je do
przeglñdarki (rysunek 5.2).

Rysunek 5.2. Przeglñdarka wysyäa Ĕñdanie do usäugi poĈrednika, a ta pobiera informacje ze Ēródäa danych.

background image

150

_

Rozdzia

ĥ 5. WidŜety klienckie

Usäuga poĈrednika moĔe zbuforowaè dane na serwerze i na pewien czas wyeliminowaè ko-
niecznoĈè  ponawiania  wywoäaþ  pod  ten  sam  adres  URL.  Na  przykäad  jeĈli  stu  uĔytkowni-
ków korzysta z tego samego kanaäu RSS, a informacje w kanale nie zmieniajñ siö przez wiele
dni, usäuga poĈrednika moĔe zbuforowaè dane pochodzñce ze pierwotnego Ēródäa na jeden
dzieþ  i  obsäugiwaè  setki  lub  tysiñce  zapytaþ  bezpoĈrednio  z  wykorzystaniem  danych  zgro-
madzonych w pamiöci serwera. Opisany mechanizm zostaä zilustrowany na rysunku 5.3.

Rysunek 5.3. Usäuga poĈrednika buforuje dane w pamiöci serwera i uniemoĔliwia wywoäywanie
zewnötrznej usäugi przez wielu uĔytkowników.

Buforowanie  danych  po  stronie  serwera  znacznie  zwiöksza  szybkoĈè  pobierania  informacji,
poniewaĔ  ogranicza  transmisjö  sieciowñ  do  pojedynczego  odwoäania.  Serwer  nie  musi  ko-
munikowaè siö z zewnötrznym Ēródäem danych. PoĈrednik moĔe dodatkowo  wygenerowaè
nagäówki, które poinformujñ przeglñdarkö o obowiñzku zbuforowania odpowiedzi na okre-

Ĉlony czas. Przed upäywem tego czasu ewentualne odwoäania do poĈrednika bödñ zastöpo-
wane  pobraniem  danych  z  pamiöci  podröcznej,  co  jest  wyjñtkowo  szybkie.  Zatem  kolejne
odwoäania do serwera proxy w celu pobrania tych samych danych nie bödñ wcale wymagaäy
przesyäania Ĕñdaþ przez sieè, tak jak to zostaäo pokazane na rysunku 5.4.

Rysunek 5.4. JeĈli odpowiedĒ jest zbuforowana w pamiöci przeglñdarki, Ĕñdanie nie zostaje dostarczone
do poĈrednika, przez co nie powoduje wygenerowania jakiegokolwiek ruchu sieciowego.

Oznacza to, Ĕe jeĈli usäuga poĈrednika pobierze dane RSS i wymusi zbuforowanie ich w prze-
glñdarce na godzinö, uĔytkownik bödzie mógä przejĈè do innego serwisu, a po powrocie widĔet
RSS  natychmiast  wyĈwietli  swojñ  treĈè  bez  odwoäywania  siö  do  serwera.  JeĔeli  wiöc  dana

background image

Po

ļrednik w dostýpie do danych

151

strona  byäaby  zäoĔona  z  samych  widĔetów  RSS,  caäa  jej  treĈè  zostaäaby  zaäadowana  po  jed-
nym  odwoäaniu  do  skryptu  Default.aspx.  Wszystkie  pozostaäe  informacje  byäyby  zarejestro-
wane  w  pamiöci  podröcznej  przeglñdarki.  Zasada  wykorzystania  mechanizmu  buforowania
danych po stronie klienta do  zwiökszenia  szybkoĈci  pobierania  danych  RSS  zostaäa  opisana
w rozdziale 9.

Us

ĥuga sieciowa poļrednika w dostýpie do danych

Usäuga  poĈrednika  w  dostöpie  do  danych  zostaäa  zdefiniowana  w  pliku  Proxy.asmx  i  obej-
muje trzy metody:

GetString(url, cacheDuration)

Metoda ta zwraca dane spod okreĈlonego adresu URL w formie ciñgu tekstowego i bufo-
ruje je po stronie przeglñdarki na okreĈlony czas (

cacheDuration

).

GetXml(url, cacheDuration)

Metoda ta zwraca dokument XML pobrany spod okreĈlonego adresu URL i buforuje go
po stronie przeglñdarki na okreĈlony czas (

cacheDuration

).

GetRss(url, count, cacheDuration)

Metoda ta pobiera spod okreĈlonego adresu URL dane kanaäu RSS przeksztaäcone w pro-
jekcjö  LINQ  (opisanñ  w  rozdziale  3.).  Informacje  sñ  przechowywane  po  stronie  serwera
przez 15 minut, a po stronie klienta zgodnie z wartoĈciñ 

cacheDuration

.

Dziaäanie metod 

GetString

 i 

GetXml

 nie jest szczególnie skomplikowane. Sprowadza siö do

uĔycia obiektu 

WebClient

 w celu pozyskania danych spod podanego adresu URL i zbuforo-

wania odpowiedzi na okreĈlony czas w pamiöci podröcznej. Kod obydwu metod zostaä przed-
stawiony w listingu 5.4.

Listing 5.4. Metody GetString i GetXml usäugi sieciowej poĈrednika.

[WebMethod]
[ScriptMethod(UseHttpGet=true)]
public string GetString(string url, int cacheDuration)
{
    using( WebClient client = new WebClient( ) )
    {
        string response = client.DownloadString(url);
        this.CacheResponse(cacheDuration);
        return response;
    }
}

[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat=ResponseFormat.Xml)]
public string GetXml(string url, int cacheDuration)
{
    return GetString(url, cacheDuration);
}

RóĔnica miödzy metodami 

GetString

 i 

GetXml

 sprowadza siö do tego, Ĕe metoda 

GetString

zwraca ciñg treĈci zgodnie z formatem JSON, natomiast metoda 

GetXml

 zwraca ciñg tekstowy

dokumentu XML. Atrybut 

ResponseFormat

 metody 

GetXml

 stanowi informacjö dla Ĉrodowi-

ska ASP.NET AJAX o obowiñzku wygenerowania dokumentu XML w formie zwykäego tekstu
zamiast przeksztaäcania go w format JSON.

background image

152

_

Rozdzia

ĥ 5. WidŜety klienckie

Metoda 

GetRss

  jest  jednak  nieco  bardziej  skomplikowana.  Jej  zadanie  polega  na  pobraniu

danych  kanaäu  RSS  i  przechowaniu  ich  przez  15  minut  w  pamiöci  podröcznej  platformy
ASP.NET.  Dziöki  temu  kolejne  odwoäania  do  tego  samego  serwera  sñ  realizowane  z  wyko-
rzystaniem  pamiöci  podröcznej  Ĉrodowiska  ASP.NET.  Metoda 

GetRss

  przygotowuje  dodat-

kowo  specjalny  nagäówek  odpowiedzi,  który  zapewnia  zbuforowanie  danych  po  stronie
przeglñdarki na okreĈlony czas. WidĔet przetwarzajñcy informacje RSS moĔe wiöc kontrolo-
waè czas przechowywania odpowiedzi w przeglñdarce.

W listingu 5.5 zostaä zawarty ten sam kod äadowania i interpretacji danych RSS, który zostaä
zaprezentowany w rozdziale 3. w czöĈci dotyczñcej widĔetu RSS.

Listing 5.5. Metoda GetRss w usäudze sieciowej poĈrednika.

[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public object GetRss(string url, int count, int cacheDuration)
{
    var feed = Context.Cache[url] as XElement;
    if( feed == null )
    {
        if( Context.Cache[url] == string.Empty ) return null;
        try
        {
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            request.Timeout = 15000;
            using( WebResponse response = request.GetResponse( ) )
            {
                using( XmlTextReader reader = new XmlTextReader( response.
                GetResponseStream( ) ) )
                {
                    feed = XElement.Load(reader);
                }
            }

            if( feed == null ) return null;
            Context.Cache.Insert(url, feed, null, DateTime.MaxValue, TimeSpan.
                FromMinutes(15));
        }
        catch
        {
            Context.Cache[url] = string.Empty;
            return null;
        }
    }

    XNamespace ns = "http://www.w3.org/2005/Atom";

    // Sprawdzenie, jakie dane s

ą przetwarzane: RSS czy Atom.

    try
    {
        // RSS.
        if( feed.Element("channel" ) != null )
            return (from item in feed.Element("channel").Elements("item")
                select new
                {
                    title = item.Element("title").Value,
                    link = item.Element("link").Value,
                    description = item.Element("description").Value
                }).Take(count);

background image

Budowa klienckiego wid

Ŝetu RSS

153

        // Atom.
        else if( feed.Element(ns + "entry") != null )
            return (from item in feed.Elements(ns + "entry")
                select new
                {
                    title = item.Element(ns + "title").Value,
                    link = item.Element(ns + "link").
                    Attribute("href").Value,
                    description = item.Element(ns + "content").Value
                }).Take(count);

        // B

áĊdny format.

        else
            return null;
    }
    finally
    {
    this.CacheResponse(cacheDuration);
    }
}

Trudno

ļci w projektowaniu usĥugi sieciowej poļrednika

W aplikacjach bazujñcych na widĔetach klienckich usäuga sieciowa poĈrednika jest najczöĈciej
wykorzystywanñ  usäugñ sieciowñ witryny. Za kaĔdym razem, kiedy skrypt JavaScript musi
pobraè dane z zewnötrznej domeny, musi teĔ wywoäaè jednñ z metod usäugi. W zwiñzku
z tym podczas projektowania usäugi sieciowej poĈrednika trzeba wziñè pod uwagö wiele za-
gadnieþ  zwiñzanych  ze  skalowalnoĈciñ  rozwiñzania.  Poäñczenie  generowane  przez  tysiñce
widĔetów, które z kolei wymuszajñ ustanowienie tysiöcy poäñczeþ z serwerami spoza dome-
ny, wprowadza istotne obciñĔenie procesów ASP.NET. Czas odpowiedzi zdalnych serwerów
jest nieprzewidywalny i zmienny. Mocno obciñĔony serwis zewnötrzny moĔe dostarczyè od-
powiedĒ po 20 lub nawet 30 sekundach, co oznacza, Ĕe odwoäanie do usäugi poĈrednika zo-
stanie na ten czas zawieszone. JeĈli taki problem siö powtórzy dla 100 Ĕñdaþ przychodzñcych,
wszystkie  dostöpne  wñtki  robocze  Ĉrodowiska  ASP.NET  zostanñ  wykorzystane.  Aplikacja
sieciowa nie bödzie mogäa obsäugiwaè Ĕadnych Ĕñdaþ, dopóki Ĕñdania przesäane do zdalnych
usäug nie zostanñ zrealizowane lub przerwane (poniewaĔ dopuszczalny czas realizacji upäy-
nie) i nie zwolniñ wñtku roboczego ASP.NET. UĔytkownicy bödñ mieli wraĔenie powolnego
dziaäania serwisu lub nawet zaobserwujñ  brak reakcji na Ĕñdania. Zagadnienia zwiñzane ze
skalowalnoĈciñ aplikacji sieciowych, które w duĔej mierze zaleĔñ od dziaäania usäug sie-
ciowych,  oraz  z  pobieraniem  informacji  z  zewnötrznych  Ēródeä  danych  zostaäy  opisane
w rozdziale 6.

Po  zaimplementowaniu  opisanych  rozwiñzaþ  dysponujemy  wszystkimi  metodami,  które  sñ
potrzebne do pobierania informacji z zewnötrznych Ēródeä danych bezpoĈrednio do przeglñ-
darki z wykorzystaniem serwera proxy.

Budowa klienckiego wid

Ŝetu RSS

Utwórzmy klienckñ wersjö widĔetu RSS. Informacje z kanaäu RSS moĔna buforowaè po stro-
nie klienta, poniewaĔ nie zmieniajñ siö szczególnie czösto. Nic nie stoi na przeszkodzie, aby
byäy przechowywane w pamiöci podröcznej na przykäad przez godzinö. Pamiötajmy, Ĕe po-
pularne serwisy RSS majñ wielu odbiorców, a buforowanie informacji po stronie serwera

background image

154

_

Rozdzia

ĥ 5. WidŜety klienckie

i  dostarczanie  ich  do  setek  lub  tysiöcy  uĔytkowników  eliminuje  koniecznoĈè  wielokrotnego
pobierania tych samych danych bezpoĈrednio ze Ēródäa informacji.

Oto wykaz kilku najwaĔniejszych róĔnic miödzy klienckimi i serwerowymi widĔetami RSS:

WidĔet  kliencki  nie  pozyskuje  danych  RSS  za  pomocñ  kodu  serwerowego,  wiöc  nie
obejmuje kodu LINQ to XML, który pobieraäby odpowiedni dokument XML. Kod LINQ
to XML jest zawarty w usäudze poĈrednika.

WidĔet kliencki nie jest wyposaĔony w kontrolkö 

MultiView

. Komunikat o postöpie prac

jest wyĈwietlany przez skrypt JavaScript.

WidĔet kliencki nie zawiera kontrolki 

DataList

, poniewaĔ odpowiedni kod HTML zwiñ-

zany z kanaäami RSS jest generowany przez skrypt JavaScript.

Zaäadowanie  danych  RSS  do  przeglñdarki  naleĔy  do  zadaþ  klasy  JavaScript  o  nazwie

FastRssWidget

, zapisanej w pliku FastRssWidget.js. Klasa ta odpowiada za wywoäanie

usäugi sieciowej poĈrednika i zinterpretowanie pozyskanych danych.

W rozwiñzaniu bazujñcym na widĔetach klienckich obiekt klasy 

FastRssWidget

 jest po-

woäywany przez kontrolkö serwerowñ. Ta sama kontrolka przekazuje odpowiedni skrypt
startowy z adresami URL kanaäów i äaduje caäy kod do przeglñdarki klienckiej.

Analizujñc listing 5.6, moĔna zauwaĔyè, Ĕe poza obszarem ustawieþ i pustym panelem widĔet
nie zawiera Ĕadnych elementów interfejsu uĔytkownika.

Listing 5.6. W nowej wersji rozwiñzania skrypt FastRssWidget.ascx nie zawiera prawie Ĕadnych elementów
interfejsu uĔytkownika.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="FastRssWidget.ascx.cs"
Inherits="Widgets_FastRssWidget" EnableViewState="false" %>
<asp:Panel ID="SettingsPanel" runat="Server" Visible="False" >
...
</asp:Panel>

<asp:Panel ID="RssContainer" runat="server"></asp:Panel>

W serwerowym kodzie widĔetu zdarzenie 

Page_Load

 rejestruje znacznik wäñczenia skryptu

FastRssWidget.js, zgodnie z przykäadem zamieszczonym w listingu 5.7.

Listing 5.7. Zdarzenie Page_Load kontrolki FastRssWidget dodaje znacznik skryptu odpowiedzialny
za zaäadowanie pliku FastRssWidget.js, a nastöpnie inicjalizuje klasö, wyĈwietlajñcñ dane po stronie klienta.

protected void Page_Load(object sender, EventArgs e)
{
    if (this._Host.IsFirstLoad)
    {
        ScriptManager.RegisterClientScriptInclude(this,
            typeof(Widgets_FastRssWidget),
            "FastRssWidget",
            this.ResolveClientUrl(
                this.AppRelativeTemplateSourceDirectory
                + "FastRssWidget.js"));

        ScriptManager.RegisterStartupScript(this,
            typeof(Widgets_FastRssWidget),
            "LoadRSS",
            string.Format("
                var rssLoader{0} =
                    new FastRssWidget( '{1}', '{2}', {3} );

background image

Budowa klienckiego wid

Ŝetu RSS

155

                    rssLoader{0}.load( );",
                    this.UniqueID,
                    this.Url,
                    this.RssContainer.ClientID,
                    this.Count),
                true);
    }
}

Nastöpnie  kod  zdarzenia  wprowadza  instrukcjö  JavaScript,  która  powoäuje  obiekt  klasy
i przekazuje  do  niej  adres  URL,  identyfikator  zewnötrznego  panelu  klienckiego  oraz  liczbö
pozycji kanaäu, które naleĔy wyĈwietliè. Operacja ta jest realizowana tylko raz, podczas pierw-
szego  äadowania  widĔetu.  Klasa  kliencka  wykorzystuje  te  trzy  parametry,  odwoäujñc  siö  do
usäugi poĈrednika. W odpowiedzi na Ĕñdanie otrzymuje dane RSS, które przeksztaäca w od-
syäacze wyĈwietlane w zewnötrznym panelu. Identyfikator panelu jest przekazywany do kla-
sy klienckiej z serwera. SäuĔy on do wyznaczenia elementu 

DIV

,

 który powinien zostaè wyko-

rzystany do wyĈwietlenia odsyäaczy.

Jednak podczas odsyäania danych po stronie klienta trzeba ponownie wygenerowaè kod tre-
Ĉci kontrolki. A to dlatego, Ĕe operacja asynchronicznej aktualizacji uwzglödnia odesäanie do
przeglñdarki  pustego  panelu  kontenera  bez  odsyäaczy  wygenerowanych  wczeĈniej  przez
skrypt JavaScript. W praktyce w czasie asynchronicznych uaktualnieþ usuwane sñ wszystkie
elementy interfejsu uĔytkownika, które zostaäy utworzone w wyniku dziaäania kodu klienc-
kiego.  Odpowiedni  skrypt  JavaScript  musi  je  wiöc  odtworzyè  po  kaĔdorazowym  odesäaniu
danych. Zadanie to jest realizowane przez procedurö obsäugi zdarzenia 

OnPreRender

. Przesyäa

ona do jednostki klienckiej blok skryptu, który przywraca poczñtkowñ wartoĈè adresu URL
oraz  wartoĈè  parametru 

Count

,  a  nastöpnie  wywoäuje  funkcjö 

load

  wczeĈniej  utworzonego

obiektu klasy 

FastRssWidget

. Caäa operacja jest zbliĔona do procedury pierwszego äadowania

kodu, podczas której tworzony jest obiekt klasy z odpowiednimi parametrami i wywoäywana
jest funkcja 

load

. Jedyna róĔnica polega na tym, Ĕe za drugim razem nie jest tworzony nowy

obiekt klasy — realizacja kodu bazuje na zaäoĔeniu, Ĕe obiekt juĔ istnieje. Rozwiñzanie to zo-
staäo przedstawione w listingu 5.8.

Listing 5.8. W czasie zdarzenia OnPreRender do klienta jest wysyäany blok skryptu, który odĈwieĔa interfejs
uĔytkownika.

protected override void OnPreRender(EventArgs e)
{

    base.OnPreRender(e);

    if (!this._Host.IsFirstLoad)
        ScriptManager.RegisterStartupScript(this,
            typeof(Widgets_FastRssWidget),
            "LoadRSS",
            string.Format("
                rssLoader{0}.url = '{1}';
                rssLoader{0}.count = {2};
                rssLoader{0}.load( );",
                this.UniqueID,
                this.Url,
                this.Count),
            true);
}

background image

156

_

Rozdzia

ĥ 5. WidŜety klienckie

To  wszystkie  zmiany  wprowadzane  po  stronie  serwera.  Kod  klasy  klienckiej  jest  nieco  bar-
dziej skomplikowany. Trzeba bowiem przenieĈè znacznñ czöĈè skryptu serwerowego do kodu
klienckiego. TreĈè klasy jest zapisana w pliku FeedRssWidget.js.

Konstruktor klasy oraz funkcja 

load

 zostaäy przestawione w listingu 5.9.

Listing 5.9. Kliencka klasa FeedRssWidget.

var FastRssWidget = function(url, container, count)
{
    this.url = url;
    this.container = container;
    this.count = count;
}

FastRssWidget.prototype = {

    load : function( )
    {
        var div = $get( this.container );
        div.innerHTML = "Loading...";
        Proxy.GetRss ( this.url, this.count, 10, Function.createDelegate( this, this.
        onContentLoad ) );
    },

Parametry przekazywane do konstruktora to adres URL, identyfikator kontenera oraz liczba
odsyäaczy prezentowanych w obszarze treĈci. Pobranie informacji RSS naleĔy do zdaþ meto-
dy 

load

, która z kolei wywoäuje funkcjö 

Proxy.GetRss

, przekazujñc do niej ciñg URL, infor-

macjö o liczbie odsyäaczy oraz czas przechowywania danych w pamiöci podröcznej (wyraĔo-
ny  w  minutach).  OdpowiedĒ  jest  buforowana  na  10  minut,  wiöc  powtórne  pobranie  strony
lub ponowne przejĈcie do strony po wizycie w innym serwisie w ciñgu 10 minut spowoduje
dostarczenie odpowiedzi bezpoĈrednio z pamiöci podröcznej przeglñdarki bez ustanawiania
poäñczenia z usäugñ sieciowñ poĈrednika. Funkcja obsäugi odpowiedzi zostaäa przedstawiona
w listingu 5.10.

Listing 5.10. Metoda Proxy.GetRss wywoäuje funkcjö onContentLoad jako funkcjö zwrotnñ,
generujñcñ odsyäacze do komunikatów kanaäu.

onContentLoad : function( rss )
{
    var div = $get( this.container );
    div.innerHTML = "";

    for( var i = 0; i < rss.length; i ++ )
    {
        var item = rss[i];

        var a = document.createElement("A");
        a.href = item.link;
        a.innerHTML = item.title;
        a.title = item.description;
        a.className = "feed_item_link";
        a.target = "_blank";
        div.appendChild(a);
    }
}

background image

Budowa klienckiego wid

Ŝetu Flickr

157

Funkcja 

onContentLoad

 tworzy odsyäacze do poszczególnych komunikatów RSS w kodzie

klienckim. Przygotowany w ten sposób widĔet kliencki ma kilka zalet  w  porównaniu  z  wi-
dĔetem serwerowym. Oto one:

Nie sñ pobierane Ĕadne dane mechanizmu 

ViewState

, poniewaĔ kontrolka sieciowa nie

obejmuje prawie Ĕadnych elementów interfejsu uĔytkownika. IloĈè danych przekazywa-
nych  podczas  pierwszego  äadowania  i  w  czasie  asynchronicznych  uaktualnieþ  jest  nie-
wielka.

TreĈè  kontrolki  jest  buforowana  w  pamiöci  przeglñdarki,  co  eliminuje  koniecznoĈè  wy-
miany danych przez sieè.

TreĈè  kontrolki  jest  dostarczana  za  pomocñ  usäugi  poĈrednika,  a  nie  w  wyniku  asyn-
chronicznej  aktualizacji.  Rozwiñzanie  to  pozwala  na  wykorzystanie  zalet  buforowania
serwerowego.

Budowa klienckiego wid

Ŝetu Flickr

Budowa klienckiego widĔetu Flickr przebiega wedäug tych samych zasad, które obowiñzujñ
podczas przygotowywania widĔetu RSS. Kod serwerowy nie dostarcza gotowego dokumentu
HTML.  Klasa  kliencka  pozyskuje  stosowny  kod  za  poĈrednictwem  metody 

Proxy.GetXml

.

Pobiera caäy dokument XML do jednostki klienckiej, co pozwala na uzupeänienie go w prze-
glñdarce o funkcje stronicowania äadowanych zdjöè i nie wymaga asynchronicznych aktuali-
zacji lub wywoäaþ poĈrednich. UĔytkownik moĔe przeglñdaè zdjöcia po bardzo krótkim cza-
sie  oczekiwania,  a  zwrócony  dokument  XML  zostaje  przechowany  w  pamiöci  podröcznej
przeglñdarki  przez  10  minut.  W  przypadku  ewentualnych  kolejnych  wizyt  (w  ciñgu  10  mi-
nut) dokument XML zostanie dostarczony z bufora przeglñdarki, wiöc widĔet Flickr zaäaduje
siö  natychmiast  i  bez  koniecznoĈci  asynchronicznego  aktualizowania  treĈci  lub  odwoäaþ  do
usäugi poĈrednika.

Kliencka klasa 

FastFlickrWidget

 ma ten sam format, jaki zostaä opisany w przypadku klasy

FastRssWidget

.  TreĈè  klasy  znajduje  siö  w  pliku  Widgets\FastFlickrWidget.js.  Jest  równieĔ

przedstawiona w listingu 5.11.

Listing 5.11. Konstruktor i funkcja load klasy FastFlickrWidget.

var FastFlickrWidget = function(url, container, previousId, nextId)
{
    this.url = url;
    this.container = container;
    this.pageIndex = 0;
    this.previousId = previousId;
    this.nextId = nextId;
    this.xml = null;
}

FastFlickrWidget.FLICKR_SERVER_URL="http://static.flickr.com/";
FastFlickrWidget.FLICKR_PHOTO_URL="http://www.flickr.com/photos/";

FastFlickrWidget.prototype = {
    load : function( )
    {
        this.pageIndex = 0;

background image

158

_

Rozdzia

ĥ 5. WidŜety klienckie

        var div = $get( this.container );
        div.innerHTML = "Loading...";

        Proxy.GetXml( this.url, 10, Function.createDelegate(this,
this.onContentLoad));
    },
    onContentLoad : function( xml )
    {
        this.xml = xml;
        this.showPhotos( );
    },

Konstruktor klasy pobiera cztery parametry: adres URL kanaäu Flickr, identyfikator elementu

DIV

 bödñcego kontenerem dla treĈci oraz identyfikatory odsyäaczy do wczeĈniejszej i nastöp-

nej  strony.  Przekazanie  odsyäaczy  jest  niezbödne,  poniewaĔ  kod  klasy  zmienia  sposób  ich
prezentacji w zaleĔnoĈci od indeksu przeglñdanej strony.

Funkcja 

showPhotos

 (przedstawiona w listingu 5.12) wykonuje wszystkie operacje niezbödne

do utworzenia tabeli (o wymiarach 3x3 pola) oraz wyĈwietlenia odsyäaczy i zdjöè.

Listing 5.12. Funkcja showPhotos z pliku FastFlickrWidget.js.

showPhotos : function( )
{
    var div = $get( this.container );
    div.innerHTML = "";

    if( null == this.xml )
        return (div.innerHTML = "Error occured while loading Flickr feed");

    var photos = this.xml.documentElement.getElementsByTagName("photo");

    var row = 0, col = 0, count = 0;

    var table = document.createElement("table");
    table.align = "center";
    var tableBody = document.createElement("TBODY");
    table.appendChild( tableBody );
    var tr;

    for( var i = 0; i < 9; i ++ )
    {
        var photo = photos[i + (this.pageIndex * 9)];

        if( photo == null )
        {
            Utility.nodisplay( this.nextId );
            break;
        }

        if( col == 0 )
        {
            tr = document.createElement("TR");
            tableBody.appendChild(tr);
        }

        var td = document.createElement("TD");

        var img = document.createElement("IMG");
        img.src = this.getPhotoUrl(photo, true);
        img.style.width = img.style.height = "75px";
        img.style.border = "none";

background image

Czytaj dalej...

Budowa klienckiego wid

Ŝetu Flickr

159

        var a = document.createElement("A");
        a.href = this.getPhotoPageUrl(photo);
        a.target = "_blank";
        a.title = this.getPhotoTitle(photo);

        a.appendChild(img);
        td.appendChild(a);
        tr.appendChild(td);

        if( ++ col == 3 ) { col = 0; row ++ }
    }

    div.appendChild(table);

    if( this.pageIndex == 0 ) Utility.nodisplay(this.previousId);
},
previous : function( )
{
    this.pageIndex --;
    this.showPhotos( );
    Utility.display( this.nextId, true );
    if( this.pageIndex == 0 )
        Utility.nodisplay( this.previousId );
},

next : function( )
{
    this.pageIndex ++;
    this.showPhotos( );
    Utility.display( this.previousId, true );
}

PowyĔszy  kod  powstaä  niemal  wprost  z  przeksztaäcenia  kodu  C#  serwerowego  widĔetu
Flickr w odpowiadajñcy mu skrypt JavaScript. MoĔna w nim zauwaĔyè odwoäania do klasy

Utility

,  która  jest  niestandardowñ  klasñ,  obejmujñca  kilka  uĔytecznych  funkcji,  odpowie-

dzialnych  miödzy  innymi  za  wyĈwietlanie  i  ukrywanie  elementów  interfejsu  uĔytkownika
oraz przetwarzanie elementów modelu DOM w sposób niezaleĔny od rodzaju przeglñdarki.
Kod klasy 

Utility

 jest zawarty w pliku MyFramework.js zapisanym w gäównym katalogu projektu.

Kontrolka  serwerowa  obejmuje  panel  ustawieþ  i  podstawowe  elementy  interfejsu  uĔytkow-
nika — pusty kontener oraz odsyäacze do poprzedniej i nastöpnej strony. Deklaracja kontrolki
zostaäa przedstawiona w listingu 5.13.

Listing 5.13. Plik FastFlickrWidget.ascx.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="FastFlickrWidget.ascx.cs"
Inherits="Widgets_FastFlickrWidget" EnableViewState="false" %>
<asp:Panel ID="settingsPanel" runat="server" Visible="False">
...
</asp:Panel>

<asp:Panel ID="FlickrPhotoPanel" runat="server">

</asp:Panel>

<div style="text-align: center; width:100%; white-space:nowrap">
<asp:LinkButton ID="ShowPrevious" runat="server" >< Prev</asp:LinkButton>
&nbsp;
<asp:LinkButton ID="ShowNext" runat="server" >Next ></asp:LinkButton></center>
</div>