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¹
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
6
_ 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
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
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.
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.
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);
}
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.
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.
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
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.
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);
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
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:
x
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.
x
WidĔet kliencki nie jest wyposaĔony w kontrolkö
MultiView
. Komunikat o postöpie prac
jest wyĈwietlany przez skrypt JavaScript.
x
WidĔet kliencki nie zawiera kontrolki
DataList
, poniewaĔ odpowiedni kod HTML zwiñ-
zany z kanaäami RSS jest generowany przez skrypt JavaScript.
x
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.
x
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} );
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);
}
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);
}
}
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:
x
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.
x
TreĈè kontrolki jest buforowana w pamiöci przeglñdarki, co eliminuje koniecznoĈè wy-
miany danych przez sieè.
x
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;
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";
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>
<asp:LinkButton ID="ShowNext" runat="server" >Next ></asp:LinkButton></center>
</div>