Professional Documents
Culture Documents
Projektowanie aplikacji
internetowych
Autor: Randy Connolly
Tumaczenie: Pawe Gonera, Ireneusz Jakbik
ISBN: 978-83-246-1128-7
Tytu oryginau: Core Internet Application
Development with ASP.NET 2.0
Format: B5, stron: 928
oprawa twarda
Wydawnictwo Helion
ul. Kociuszki 1c
44-100 Gliwice
tel. 032 230 98 63
e-mail: helion@helion.pl
Spis treci
O autorze ..................................................................................................................................................15
Wstp ........................................................................................................................................................17
Cz I ASP.NET
23
Spis treci
Spis treci
Cz II Operacje na danych
395
10
Spis treci
11
663
12
Rozdzia 14. Personalizacja za pomoc profili oraz skadnikw Web Part .......................................733
Profile rodowiska ASP.NET ........................................................................................ 733
Definiowanie profili ............................................................................................... 734
Uycie danych profilu ............................................................................................. 735
Jak dziaaj profile? ............................................................................................... 739
Zapisywanie i odczytywanie danych profilu ............................................................... 741
Uywanie typw niestandardowych .......................................................................... 742
Praca z uytkownikami anonimowymi ...................................................................... 745
Kiedy uywa profili? ............................................................................................. 749
Skadniki Web Part ..................................................................................................... 751
Skadniki Web Part, strefy Web Part oraz meneder skadnikw Web Part .................. 753
Tworzenie skadnikw Web Part i korzystanie z nich ................................................. 756
Konstruowanie skadnikw Web Part z kontrolek uytkownika ................................... 762
Tworzenie skadnikw Web Part na podstawie kontrolek niestandardowych ................ 766
Zmiana trybw wywietlania ................................................................................... 769
Tryb projektowania ................................................................................................ 771
Tryb katalogu ........................................................................................................ 773
Tryb edycji ............................................................................................................ 774
Poczenia skadnikw Web Part ............................................................................ 780
Podsumowanie .......................................................................................................... 791
wiczenia .................................................................................................................. 792
Najwaniejsze zagadnienia .......................................................................................... 793
Odnoniki .................................................................................................................. 794
Spis treci
13
11
586
Cz II
Operacje na danych
Projektowanie aplikacji
rodowisko ASP.NET dysponuje wieloma funkcjami, ktre wspomagaj szybkie projektowanie aplikacji sieciowych. Wydajne deklaracyjne kontrolki umoliwiaj programistom
tworzenie wyszukanych interfejsw sucych do wywietlania i edycji danych przy maym
nakadzie programowania lub w ogle bez koniecznoci pisania kodu. Wygoda korzystania
z programu Visual Studio Designer i jego moc take zachcaj programistw do szybkiej
implementacji stron WWW. rodowisko ASP.NET i Visual Studio zdaj si mwi: Nie
marnuj czasu na projektowanie i planowanie; bierz si do przecigania i upuszczania i zakocz projekt!. Taka moliwo szybkiego opracowania strony jest zachcajca zwaszcza
podczas tworzenia witryny WWW z ograniczon liczb przypadkw uycia, czyli niewielkim zakresem wymogw funkcjonalnych.
Funkcjonalnoci wielu prawdziwych aplikacji sieciowych nie da si jednak opisa za
pomoc zaledwie kilku przypadkw uycia. W rzeczywistoci mog by dziesitki, a nawet
setki opisanych przypadkw, ktre wymagaj wysiku wielu programistw powicajcych
sporo czasu, aby je wszystkie zaimplementowa. To wanie podczas pracy nad takim rodzajem aplikacji sieciowych szybki styl programowania moe w rzeczywistoci spowolni
og procesw tworzenia aplikacji.
Prawdziwe projekty programistyczne s wyjtkowo wraliwe na zmiany wymaga; projekty
sieciowe s chyba jeszcze bardziej wraliwe. Oznacza to, e funkcje aplikacji sieciowej s
rzadko w peni okrelone przed rozpoczciem projektowania. Dodawane s nowe funkcje,
a z innych si rezygnuje. Zmienia si model danych oraz wymogi co do ich przechowywania. W miar przemieszczania si projektu przez poszczeglne etapy cyklu projektowania
rodowisko uruchomieniowe zmienia si poczwszy od laptopa programisty, przez serwer
testowy, serwer docelowy, a skoczywszy by moe na farmie serwerw sieciowych. Programista moe pocztkowo testowa program z baz danych programu Access, po czym
przenie dane do serwera SQL, a nastpnie, po fuzji firm, powrci do bazy danych Oracle.
Na kilka tygodni przed testowaniem alfa klient moe wprowadzi zmiany, ktre w przypadku pewnych informacji spowoduj konieczno pracy z zewntrzn usug zamiast z lokaln baz danych. Analitycy uytecznoci mog mocno skrytykowa strony witryny, co moe
spowodowa konieczno wprowadzenia zmian w interfejsie uytkownika.
To wanie w takim rodowisku programowania sieciowego zwyczaje szybkiego opracowywania projektw mog przynie wicej szkd ni korzyci. Przestrzeganie jednak zasad
prawidowego projektowania oprogramowania moe w tym samym rodowisku zwrci si
w postaci cakiem wymiernych zyskw. Powicenie czasu na utworzenie dobrze zaprojektowanej infrastruktury aplikacji moe sprawi, e aplikacje sieciowe bd atwiejsze do modyfikowania i w pielgnacji, prostsze w rozbudowie i poszerzaniu ich funkcjonalnoci, mniej
podatne na bdy, a take atwiejsze w tworzeniu. W pierwszym podrozdziale niniejszego
rozdziau podjto prb rzucenia nieco wiata na proces projektowania tego typu infrastruktury aplikacji.
Rozdzia 11.
587
Korzystanie z warstw
Jedn z najwaniejszych zalet rodowiska ASP.NET w porwnaniu z czysto skryptowymi
technologiami, takimi jak ASP albo PHP, jest moliwo tworzenia bardziej elastycznych
aplikacji za pomoc aktualnie obowizujcych dobrych praktyk projektowania obiektowo zorientowanego oprogramowania. Prawdopodobnie najwaniejsza z tych praktyk polega na
podzieleniu projektu aplikacji na dyskretne warstwy logiczne.
Czym jest warstwa? Warstwa to po prostu grupa klas, ktre s spokrewnione funkcjonalnie
lub logicznie. Uywanie warstw jest sposobem na organizowanie projektu oprogramowania
w grupy klas, ktre su wsplnemu celowi. Warstwa zatem nie jest rzecz lecz zasad organizacji. Oznacza to, e warstwy s sposobem na projektowanie aplikacji.
Powodem, dla ktrego tak wielu programistw aplikacji przyjo warstwy jako zasad organizacji swoich aplikacji, jest fakt, e warstwa nie stanowi dowolnej grupy klas. Kada warstwa aplikacji powinna by spjna (czyli klasy powinny dotyczy mniej wicej tego samego
i mie zbliony poziom abstrakcji). Spjne warstwy i klasy s zazwyczaj atwiejsze do zrozumienia, wielokrotnego uywania i pielgnowania.
Celem dzielenia na warstwy jest rozdzielenie funkcji oprogramowania midzy klasy w taki
sposb, aby zminimalizowa skojarzenia danej klasy z innymi klasami. Skojarzenie odnosi
si do liczby klas, z ktrej korzysta okrelona klasa. Kiedy pewna klasa korzysta z innej
klasy, jest od niej zalena. Wszelkie zmiany wprowadzone w interfejsie uywanej klasy mog
mie wpyw na klas od niej zalen. Kiedy klasy aplikacji s silnie skojarzone, zmiana w jednej klasie moe mie wpyw na wiele innych klas. Zredukowanie skojarze sprawia, e projekt
staje si elastyczniejszy i atwiej rozszerzalny.
Pewien stopie skojarze jest oczywicie niezbdny w kadej aplikacji w przeciwnym
razie klasy nie wchodziyby we wzajemne interakcje. Organizujc klasy aplikacji w warstwy,
mona mie nadziej na uzyskanie mniejszego stopnia skojarze ni w przypadku, gdyby
podzia na warstwy nie by przyjt zasad organizacji. Warstwa moe zalee od interfejsu
innej warstwy, jednak powinna by niezalena od jej implementacji.
Przy takim podejciu kada warstwa cechuje si cile ograniczon liczb zalenoci. Zaleno (znana take jako relacja korzystania) to taki zwizek midzy dwoma elementami, w ktrym zmiana w jednym elemencie ma wpyw na drugi element. Na rysunku 11.1 poszczeglne
warstwy s zalene tylko od warstw, ktre znajduj si poniej, to znaczy od warstw, ktre
s bardziej niskopoziomowe czy te bardziej zalene od elementw zewntrznych, takich
jak bazy danych albo usugi sieciowe.
Prosz zwrci uwag, co oznacza zaleno w odniesieniu do warstw. Oznacza mianowicie, e klasy w warstwie powyej korzystaj z klas i metod warstwy (lub warstw) poniej,
ale ju nie vice versa. Rzeczywicie, jeli zalenoci zachodz midzy wszystkimi warstwami
w obie strony, traci si cakowicie korzyci z podziau na warstwy.
588
Cz II
Operacje na danych
Rysunek 11.1.
Wizualizacja
warstw
Schemat warstw pokazany na rysunku 11.1 jest otwartym (lunym) schematem podziau
na warstwy, poniewa niektre warstwy zale od wicej ni jednej innej warstwy.
W schemacie zamknitym (nieprzejrzystym) kada warstwa zaley tylko od jednej niszej warstwy. Chocia schemat zamknity byby idealny, to jednak w praktyce jest on
czasami trudny do osignicia. Jak zauway Martin Fowler w swojej ksice Architektura
systemw zarzdzania przedsibiorstwem. Wzorce projektowe, wikszo (architektur
warstwowych) jest w wikszoci nieprzejrzysta.
Na koniec musz jeszcze wspomnie, e niektrzy autorzy uywaj terminu poziom w tym
samym znaczeniu, w jakim ja uywam terminu warstwa. Wikszo jednak wspczesnej
literatury na temat architektury i projektowania oprogramowania uywa terminu poziom
w zupenie innym znaczeniu. Znaczenie to odnosi si do granic procesu. Rne poziomy najczciej oznaczaj rne miejsca w sieci. Typowa aplikacja sieciowa moe by na przykad
rozpatrywana jako architektura trjpoziomowa: stacja robocza uytkownika jest poziomem
interfejsu uytkownika, serwer sieciowy jest poziomem aplikacji, a system zarzdzania baz
danych dziaajcy na odrbnym serwerze danych jest poziomem bazy danych, co pokazano
na rysunku 11.2. W dalszej czci niniejszej ksiki termin poziom bdzie uywany w tym
drugim znaczeniu, z kolei sowo warstwa bdzie odnosi si do pojciowego grupowania
klas w obrbie aplikacji.
Rozdzia 11.
589
Rysunek 11.2.
Poziomy
590
Cz II
Operacje na danych
Model dwuwarstwowy
Pokazano ju w poprzednim rozdziale, e jest moliwe utworzenie sterowanej danymi aplikacji sieciowej ASP.NET niemal zupenie bez koniecznoci programowania dziki kontrolce
SqlDataSource oraz innym kontrolkom danych, takim jak DetailsView i GridView. Niemniej,
jak ju wspomniano w rozdziale 9., wielu programistw nie lubi umieszcza szczegw
dostpu do bazy danych w formularzach WWW, nawet jeli dzieje si to w deklaracyjnych
formach kontrolki SqlDataSource. W rozdziale 9. utworzono seri spokrewnionych klas,
ktre obsugiway dostp do bazy danych za porednictwem programowania w technologii
ADO.NET, a nastpnie uyto ich w formularzach WWW, korzystajc z kontrolki ObjectDataSource. By to przykad architektury dwuwarstwowej.
W modelu dwuwarstwowym szczegy dostpu do danych s zawarte w odrbnych klasach,
ktre s rne od samych formularzy WWW. Dwie warstwy wystpujce w takim modelu
mona nazwa warstw prezentacji oraz warstw dostpu do danych.
Warstwa prezentacji udostpnia interfejs uytkownika aplikacji oraz obsuguje interakcj
midzy uytkownikiem i aplikacj. W tej ksice warstwa prezentacji skada si ze stron
ASP.NET wraz z ich klasami z kodem ukrytym oraz dodatkowymi kontrolkami uytkownika
lub kontrolkami niestandardowymi. Warstwa dostpu do danych udostpnia komunikacj
z systemami zewntrznymi, takimi jak bazy danych, systemami rozpowszechniania komunikatw lub zewntrzne usugi WWW, co pokazano na rysunku 11.3.
Warstwa dostpu do danych z rozdziau 9. zawieraa cay kod ADO.NET. Kada z klas
warstwy bya odpowiedzialna za tworzenie, odczytywanie, aktualizacj i usuwanie w pojedynczej tabeli bazy danych (CRUD, od ang. Create, Retrieve, Update, Delete). Na rysunku 11.4
pokazano dwie przykadowe klasy dostpu do danych oraz ich wspln klas nadrzdn.
Naley zauway, e gdy dane s odczytywane z bazy w warstwie dostpu do danych, s
one zawarte w klasie DataTable (chocia mona by te uy klasy DataSet), po czym przekazywane do warstwy prezentacji.
Rozdzia 11.
Rysunek 11.3.
Model
dwuwarstwowy
591
592
Cz II
Operacje na danych
Zalet modelu dwuwarstwowego jest jego lekko i wzgldna atwo implementacji. Model
ten moe jednak nie by idealnym rozwizaniem, jeli logika aplikacji witryny staje si bardziej zoona. Termin logika aplikacji odnosi si do midzydomenowej logiki albo przepywu procesw w samej aplikacji. Przykadem logiki aplikacji moe by przepyw pracy
w sklepie internetowym zwizany z obsug zamwienia. Po klikniciu przez uytkownika
przycisku sucego do skadania zamwie aplikacja sieciowa musi utworzy zamwienie
w bazie danych, skontaktowa si z systemem patnoci i przedoy patno. Jeli nastpi
niepowodzenie, zamwienie musi zosta wycofane, a uytkownik powiadomiony. W przeciwnym razie zamwienie musi zosta przekazane, system realizacji zamwienia powiadomiony,
a strona z potwierdzeniem zamwienia wywietlona. Taki przepyw pracy ma wiele etapw
z wieloma zestawami logiki warunkowej.
Model dwuwarstwowy moe okaza si daleki od ideau, jeli zachodzi potrzeba dodania
do aplikacji bardziej zoonych regu biznesowych. Okrelenie reguy biznesowe odnosi si
do standardowych typw walidacji danych wejciowych omwionych w rozdziale 5., a take
do bardziej zoonych regu dotyczcych danych, czsto charakterystycznych dla metod, ktrymi posuguje si organizacja, prowadzc swoj dziaalno.
W witrynach, w ktrych logika aplikacji lub reguy biznesowe s zoone, taka dodatkowa
zoono musi by zazwyczaj zaimplementowana w warstwie prezentacji, gdy uyto modelu dwuwarstwowego. W konsekwencji kody ukryte zwykle staj si zbyt skomplikowane
i przepenione powtarzalnym kodem logiki biznesowej i aplikacji. Dokonaem kiedy dla
klienta refaktoryzacji dwuwarstwowej aplikacji sieciowej ASP.NET, w ktrej kada klasa z kodem ukrytym dla wszystkich z ponad trzydziestu formularzy WWW liczya ponad 4000 wierszy. W rezultacie ich modyfikacja bya prawdziwym koszmarem z powodu ich dugoci
i zoonoci. Rozwizaniem dla tego okrelonego przypadku bya zmiana architektury witryny na model trjwarstwowy.
Model trjwarstwowy
W architekturze trjwarstwowej nowa warstwa zostaje dodana do modelu dwuwarstwowego.
Ta nowa warstwa jest oglnie znana pod nazw warstwy biznesowej (rysunek 11.5).
Najwaniejsz zmian w porwnaniu z modelem dwuwarstwowym jest brak koniecznoci
umieszczania danych z bazy w obiektach klasy DataTable. Warto przypomnie, e w modelu
dwuwarstwowym dane s zwracane z przykadowych klas dostpu do danych w obiektach
klasy DataTable (zamiast ktrych mona uy obiektw klasy DataSet). Kiedy obiekt klasy
DataTable albo DataSet zostanie bezporednio powizany z kontrolk, ma to swoje niewtpliwe zalety. Czasami jednak zachodzi potrzeba programowego uzyskania i przetworzenia
poszczeglnych danych z obiektw. Jak ju pokazano w rozdziale 8., zakodowanie takiej
funkcji jest nieco skomplikowane. Jeli naley na przykad pobra warto pola LastName
z pierwszego wiersza DataRow pierwszej tabeli DataTable w zbiorze DataSet, kod bdzie
wyglda nastpujco:
txtLastName.Text = myDataSet.Tables[0].Rows[0]["LastName"];
Rozdzia 11.
593
Rysunek 11.5.
Architektura
trjwarstwowa
594
Cz II
Operacje na danych
// Waciwoci
public int Id
{
get { return _id; }
set { _id= value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
Formularz WWW moe zatem uzyska dostp do danych z rekordu, korzystajc z duo
czystszej skadni waciwoci. Do tych waciwoci mona uzyskiwa dostp programowo
w pokazany poniej sposb:
txtName.Text = aCustomer.Name
Rozdzia 11.
595
Gwna zaleta takiego podejcia polega na tym, e warstwa prezentacji nie zaley ju od
szczegw implementacji bazy danych, poniewa nastpuje odwoanie do waciwoci obiektu,
a nie do nazwy pola w tabeli DataTable. Ponadto dziki wyeliminowaniu obiektu DataSet
albo DataTable kod sta si zdecydowanie czystszy i bardziej czytelny.
Jeli jest potrzebna weryfikacja wyrae wizania danych podczas kompilacji, mona
zastosowa bardziej rozwlek alternatyw dla metody Eval, ktr jest pokazane poniej
polecenie Container.DataItem:
<ItemTemplate>
<%# ((Book)Container.DataItem)Book.Name %>
</ItemTemplate>
Warstwa biznesowa zatem implementuje i reprezentuje biznes, czyli funkcje, logik, procesy
i dane aplikacji. W zalenoci od aplikacji w klasach tej warstwy mog by hermetyzowane:
Q
Proces lub przepyw pracy biznesu albo aplikacji, taki jak proces zamawiania
i potok realizacji albo przepyw pracy wsparcia klienta.
Usunicie regu biznesowych oraz logiki aplikacji z warstwy prezentacji sprawia, e formularze WWW staj si o wiele prostsze. Teraz mog one zawiera wycznie znaczniki oraz
obsug zdarze interfejsu uytkownika. Wszystko inne jest zawarte w pozostaych klasach.
Na rysunku 11.6 pokazano cz klas, ktrych mona uy w obrbie warstwy biznesowej
w przykadowej aplikacji Book Catalog.
Naley zauway, e obiekty biznesowe nie powinny by wycznie pojemnikami dla danych
na temat obiektu. Powinny one rwnie zawiera logik. Mog na przykad zawiera metody suce do uzyskiwania lub zapisywania swoich danych (za pomoc korzystania z klas
z warstwy dostpu do danych), implementacji logiki aplikacji, autoryzacji dostpu oraz walidacji danych wzgldem regu biznesowych.
Kolejnym elementem (rysunek 11.6) wymagajcym uwagi jest potrzeba istnienia dodatkowych obiektw biznesowych, ktre bd reprezentowa zbiory obiektw biznesowych. Te
klasy zbiorw biznesowych take nie powinny by jedynie pojemnikami dla danych, ale
powinny zawiera rwnie logik. W przykadzie pokazanym na rysunku 11.6 klasy zbiorw
biznesowych zawieraj moliwo adowania siebie samych ze rda danych (za pomoc klas
z warstwy dostpu do danych), a take aktualizacji lub dodawania siebie do rda danych.
Jest prawdopodobne, e obiekty biznesowe aplikacji bd mie cz wsplnych funkcji.
Te funkcje mona umieci we wsplnej klasie nadrzdnej. Na rysunku 11.6 jest ni klasa
AbstractBO, ktrej kod przedstawiono na listingu 11.1. Ma ona dane skadowe, ktre ledz,
czy obiekt jest nowy, czy by modyfikowany oraz czy dane podklasy s prawidowe wzgldem regu biznesowych. Poniewa klasy, ktre korzystaj z tych obiektw biznesowych mog
chcie mie moliwo sprawdzenia, ktre reguy zostay naruszone, klasa AbstractBO
przechowuje zbir naruszonych regu, a take metody suce do dodawania oraz odczytywania zbiorw, ktre ze wzgldu na prostot przykadu zostay przedstawione jako lista
596
Cz II
Operacje na danych
Rysunek 11.6.
Przykadowe
obiekty biznesowe
acuchw. Poniewa kady obiekt biznesowy wie, jak okreli, czy dane s prawidowe,
klasa AbstractBO definiuje abstrakcyjny skadnik CheckIfSubClassStateIsValid, ktry jest
zaimplementowany przez kad z jej konkretnych podklas.
W tym przykadzie kady obiekt biznesowy jest odpowiedzialny za sprawdzanie swoich
regu biznesowych. Inne podejcie, bardziej skomplikowane, ale zarazem o wikszych
moliwociach adaptacji, polega na hermetyzowaniu tych regu w obrbie ich wasnej
hierarchii obiektw. Do tych regu bdzie mg stosowa si jaki typ odrbnej klasy
zarzdzania reguami. Wicej informacji o tym rodzaju podejcia znajduje si w ksice
Jimmyego Nilssona Applying Domain-Driven Design and Patterns.
Listing 11.1. AbstractBO.cs
using System;
using System.Data;
using System.Collections.Generic;
namespace ThreeLayer.Business
{
/// <podsumowanie>
/// Reprezentuje klas nadrzdn dla wszystkich obiektw biznesowych
Rozdzia 11.
/// </podsumowanie>
public abstract class AbstractBO
{
// Dane skadowe
protected const int DEFAULT_ID = 0;
// Flagi wskazujce, czy obiekt jest nowy, czy by modyfikowany
private bool _isNew = true;
private bool _isModified = false;
// Zbir opisw wszystkich naruszonych regu
private List<string> _brokenRules = new List<string>();
/// <podsumowanie>
/// Kada klasa jest odpowiedzialna za sprawdzanie, czy jej
/// stan (dane skadowe) zawiera naruszone reguy biznesowe
/// </podsumowanie>
protected abstract bool CheckIfSubClassStateIsValid
{
get;
}
/// <podsumowanie>
/// Podklasy potrzebuj moliwoci dodawania opisu naruszonej reguy
/// </podsumowanie>
protected void AddBrokenRule(string rule)
{
_brokenRules.Add(rule);
}
/// <podsumowanie>
/// Zwr opisy wszystkich naruszonych regu
/// </podsumowanie>
public List<string> BrokenRules
{
get { return _brokenRules; }
}
/// <podsumowanie>
/// Czy obiekt biznesowy jest poprawny
/// </podsumowanie>
public bool IsValid
{
get
{
_brokenRules.Clear();
return CheckIfSubClassStateIsValid;
}
}
/// <podsumowanie>
/// Czy obiekt biznesowy by modyfikowany od czasu ostatniego zapisu
/// </podsumowanie>
protected bool IsModified
{
get { return _isModified; }
set { _isModified = value; }
}
597
598
Cz II
Operacje na danych
/// <podsumowanie>
/// Czy ten obiekt biznesowy jest nowy, czy moe
/// zawiera dane, ktre ju istniej w bazie
/// </podsumowanie>
protected bool IsNew
{
get { return _isNew; }
set { _isNew = value; }
}
}
}
Nie zamieszczam kodw dla wszystkich klas z rysunku 11.6 (chocia mona je pobra z mojej
witryny WWW pod adresem http://www.randyconnolly.com/core), jednak w listingu 11.2
prezentuj kod klasy biznesowej PublisherBO.
Listing 11.2. PublisherBO.cs
using System;
using System.Data;
using ThreeLayer.DataAccess;
namespace ThreeLayer.Business
{
/// <podsumowanie>
/// Obiekt biznesowy do przechowywania informacji o wydawcy
/// </podsumowanie>
public class PublisherBO: AbstractBO
{
// Dane skadowe
private int _id = DEFAULT_ID;
private string _name = "";
// Konstruktory
public PublisherBO() { }
public PublisherBO(int id, string name)
{
_id = id;
_name = name;
IsNew = false;
IsModified = true;
}
/// <podsumowanie>
/// Wypenia obiekt danymi na podstawie przekazanego ID
/// </podsumowanie>
/// <zwraca>
/// Warto true, jeli wypenienie danymi powiodo si,
/// w przeciwnym razie warto false
/// </zwraca>
public bool Load(int id)
{
PublisherDA da = new PublisherDA();
DataTable table = da.GetById(id);
Rozdzia 11.
599
600
Cz II
Operacje na danych
/// <podsumowanie>
/// Usuwa dane
/// </podsumowanie>
public void Delete()
{
PublisherDA da = new PublisherDA();
da.DeletePublisher(Id);
}
/// <podsumowanie>
/// Sprawdza, czy stan wewntrzny obiektu
/// biznesowego jest prawidowy
/// </podsumowanie>
protected override bool CheckIfSubClassStateIsValid
{
get
{
bool valid = true;
if (Name.Length == 0)
{
AddBrokenRule("Nazwa wydawcy nie moe by pusta");
valid = false;
}
if (Id < 0)
{
AddBrokenRule(
"Id wydawcy nie moe by mniejszy ni zero");
valid = false;
}
// Oto przykad bardziej zoonej reguy
if (IsNew)
{
// Sprawd, czy tytu ju nie istnieje
PublisherDA da = new PublisherDA();
DataTable dt = da.GetByName(Name);
if (dt.Rows.Count > 0)
{
AddBrokenRule("Nazwa wydawcy ju istnieje");
valid = false;
}
}
return valid;
}
}
// Waciwoci
public int Id
{
get { return _id; }
set {
_id = value;
IsModified = true;
}
}
Rozdzia 11.
601
602
Cz II
Operacje na danych
Przyjmijmy, e ta sama kontrolka GridView ma w kadym wierszu przycisk sucy do wybierania wiersza. Kiedy uytkownik wybierze wiersz, zostan wywietlone dane wybranego
wydawcy. Kod wykonujcy to zadanie moe wyglda nastpujco:
// Okrel ID wybranego wydawcy
int pubId = (int)grdPublishers.SelectedDataKey.Values[0];
// Utwrz obiekt biznesowy wydawcy i wczytaj jego dane
PublisherBO pub = new PublisherBO();
if (pub.Load(pubId))
{
panPublisher.Visible = true;
labId.Text = pub.Id.ToString();
txtName.Text = pub.Name;
}
W powyszym przykadzie jest tworzony obiekt biznesowy wydawcy, ktry wczytuje dane
odpowiadajce wybranemu identyfikatorowi PublisherId. Jeli wczytywanie danych zakoczy si pomylnie, wartoci pl bdzie mona odczytywa za porednictwem waciwoci
obiektu biznesowego.
W celu aktualizacji danych w bazie mona skorzysta z tej samej klasy biznesowej. Na poniszym przykadzie pokazano, jak obiekt klasy PoblisherBO jest tworzony i zapeniany danymi pochodzcymi z formularza WWW. Nastpnie obiekt ma sam siebie zaktualizowa. Jeli
aktualizacja nie powioda si na skutek naruszenia reguy biznesowej, w kontrolce formularza
zostanie wywietlony zbir acuchw z reguami.
// Pobierz wartoci ID oraz tytuu
int id = Convert.ToInt32(labId.Text);
string name = txtName.Text;
// Utwrz obiekt biznesowy wydawcy i postaraj si go zaktualizowa
PublisherBO pub = new PublisherBO(id, name);
pub.Update();
// Sprawd, czy aktualizacja udaa si
if (!pub.IsValid)
{
// Aktualizacja nie udaa si, a zatem poka naruszone reguy biznesowe
grdErrors.DataSource = pub.BrokenRules;
grdErrors.DataBind();
}
Rozdzia 11.
603
604
Cz II
Operacje na danych
jako parametr pobiera obiekt klasy PublisherBO (i ktra po prostu wywouje wasn metod
aktualizujc obiektu biznesowego) albo konieczne bdzie dodanie do obiektu biznesowego
metody statycznej, ktra aktualizuje przekazany obiekt tej klasy.
public class PublisherBO: AbstractBO
{
Inny potencjalny problem zwizany z obiektami biznesowymi oraz kontrolk ObjectDataSource polega na tym, e wewntrzna logika typowego obiektu biznesowego moe nie integrowa si dobrze z kontrolk. Zazwyczaj sposb postpowania z obiektami biznesowymi
polega na przykad na uyciu niestandardowej klasy fabrycznej w celu tworzenia i dostosowywania rnych obiektw biznesowych w aplikacji. Kontrolka ObjectDataSource tworzy
jednak wszystkie obiekty uywane w aplikacji, korzystajc z domylnego konstruktora obiektu.
Ponadto, podczas uywania waciwoci DataObjectTypeName w celu przekazania obiektu biznesowego do metody aktualizujcej, wstawiajcej lub usuwajcej jest tworzona nowa instancja obiektu biznesowego, niektre jej waciwoci s zapeniane, po czym obiekt ten zostaje
przekazany do waciwej metody (rysunek 11.7).
Rozdzia 11.
605
606
Cz II
Operacje na danych
Oczywicie, mona przeprojektowa obiekty biznesowe, aby lepiej wsppracoway z kontrolk ObjectDataSource. W rzeczywistoci naley tak postpi w celu umoliwienia stronicowania i sortowania w obiektach biznesowych opartych na kolekcjach. Niektrzy jednak
projektanci oprogramowania mog uwaa, e zmiana projektu warstwy biznesowej w celu
dostosowania jej do potrzeb warstwy prezentacji jest niczym cica nad nimi kltwa. W innych sytuacjach mog istnie obiekty biznesowe, ktrych projektu nie da si zmieni bez
szkody dla innych aplikacji. W takim przypadku naley utworzy fasad albo klas adapterow, ktra udostpni kontrolce ObjectDataSource lepiej pasujcy interfejs. Mona oczywicie podj decyzj o cakowitej rezygnacji z uywania kontrolki ObjectDataSource i przeprowadza wizanie oraz przetwarzanie danych w starowiecki sposb znany ze rodowiska
ASP.NET 1.1, ktry polega na korzystaniu z krtkich fragmentw kodu w plikach z kodem ukrytym.
Alternatyw do korzystania z modelu trjwarstwowego jest uycie modelu czterowarstwowego. Model czterowarstwowy ma wiele zalet, z ktrych jedna polega na tym, e taki model
jest potencjalnie atwiejszy do zintegrowania z kontrolk ObjectDataSource.
Model czterowarstwowy
W podstawowym modelu trjwarstwowym warstwa biznesowa nie jest szczeglnie spjna,
poniewa moe hermetyzowa dane i role biznesowe, a take logik i procesy aplikacji. Aby
uczyni warstw biznesow bardziej spjn, niektrzy programici umieszczaj logik i procesy aplikacji w warstwie prezentacji, co niestety czsto sprawia, e warstwa ta staje si
bardzo chaotyczna i trudna w modyfikacji.
Rozdzia 11.
607
Rysunek 11.8.
Model
czterowarstwowy
Obiekty warstwy logiki aplikacji nie powinny zawiera danych stanu dotyczcych biznesu,
mog jednak zawiera dane stanu dotyczce procesw aplikacji. Wikszo pracy zwizanej
z danymi biznesowymi jest przekazana warstwie domeny, ktra jest odpowiedzialna za reprezentowanie danych i regu biznesu lub aplikacji.
Poniewa warstwa domeny zawiera wanie te reguy i dane, znajduje si ona w centrum
uwagi na wstpnym etapie projektowania aplikacji. Klasy tej warstwy czsto s nazywane
encjami. Chocia klasy warstwy domeny mog by zbiene z tabelami w bazie danych (co
mona zauway na rysunku 11.10), nie jest to w adnym wypadku konieczne. Zamiast tego
klasy tej warstwy maj reprezentowa koncepcje w domenie problemu aplikacji. Rzeczywicie,
klasy domeny mona byo spotka ju w klasie Customer, w rozdziale 8.
Ostatni rzecz, na ktr naley zwrci uwag w czterowarstwowym modelu pokazanym
na rysunku 11.8, jest fakt, e klasy warstwy domeny s uywane przez pozostae trzy warstwy. Jest tak dlatego, e klasy encji w tym modelu s uywane w celu przechowywania
608
Cz II
Operacje na danych
danych, gdy s one przekazywane midzy warstwami. Peni one zatem rol, ktr w modelach dwuwarstwowym oraz trjwarstwowym odgrywaa klasa DataTable. Przypomnijmy,
e w modelach dwuwarstwowym i trjwarstwowym rne klasy dostpu do danych umieszczay dane uzyskiwane z bazy danych w obiekcie klasy DataTable i zwracay je do zgaszajcego danie. W rezultacie uytkownik dowolnej klasy dostpu do danych musia manipulowa klas ADO.NET DataTable, chocia ona sama nie bya klas dostpu do danych.
Jako rozwizanie alternatywne w modelu czterowarstwowym, pokazanym na rysunku 11.8,
klasy dostpu do danych same tworz i zapeniaj klasy encji. W sytuacjach, w ktrych s
pobierane wielokrotne rekordy danych, klasy dostpu do danych tworz wielokrotne instancje
odpowiedniej klasy encji, a nastpnie umieszczaj je w obrbie klasy EntityCollection tej
samej klasy pojemnikowej oglnego zastosowania, ktra zostaa utworzona w rozdziale 8.
Na rysunku 11.9 przedstawiono niektre przykadowe klasy z warstwy domeny. Naley zauway, e kada klasa domeny jest podklas klasy AbstractEntity, ktra jest podobna
do klasy opisanej w rozdziale 8. i z ktr ma czci wsplne, jak na przykad AbstractBO
klas bazow dla wszystkich klas biznesowych w modelu trjwarstwowym.
Rysunek 11.9.
Klasy warstwy
domeny
Rozdzia 11.
609
Rne klasy domeny maj wspln cz zespou funkcji, podobnie jak klasy obiektw biznesowych pokazane na rysunku 11.5. Gwna rnica polega na tym, e klasy domeny nie
mog wchodzi w interakcj z baz danych. W rezultacie jest usprawiedliwione uwaanie
tych klas za odpowiednik czego, co niektrzy programici znajcy jzyk Java nazywaj
obiektem transferu danych. Okrelenie to odnosi si do klasy, ktra zawiera wycznie dane
skadowe z waciwociami sucymi uzyskiwaniu dostpu do danych. Najwaniejsza rnica
midzy obiektem transferu danych a nasz klas domeny kryje si w tym, e klasa domeny
zawiera rwnie zachowania suce do sprawdzania i walidacji regu biznesowych.
Na koniec warto zauway zwizki zachodzce midzy rnymi klasami domen na rysunku 11.9. Podobnie jak w przypadku obiektw biznesowych w modelu trjwarstwowym,
encje w modelu czterowarstwowym reprezentuj koncepcje lub rzeczy w domenie problemu
aplikacji. W przykadowej aplikacji z ksikami ksika ma wydawc, seri, kategori i kilku
autorw. Encja Book ma zatem encj Publisher, encj Series, encj Category oraz zbir encji
Author. Chocia zwizki te s odzwierciedleniem modelu danych w bazie, nie s one takie
same. Encja ksiki ma na przykad obiekt encji Publisher, podczas gdy kluczem obcym rekordu Books jest pole PublisherId. Encja ksiki ma zbir obiektw encji Author, gdy tymczasem autorzy danej ksiki zawieraj si w tabelach AuthorBooks oraz Authors.
Opisywanie najlepszego sposobu projektowania modelu domeny wykracza poza zakres
niniejszego rozdziau. Czytelnicy chccy poszerzy swoje wiadomoci w przedstawionym
temacie mog zajrze do ksiek Evansa, Fowlera i Nilssona wymienionych w czci Odnoniki, pod koniec tego rozdziau.
610
Cz II
Operacje na danych
W podobny sposb zostanie zmieniona take metoda suca do odczytywania danych. W poprzedniej klasie BookDA istniaa nastpujca metoda, ktra zwracaa obiekt klasy DataTable
zawierajcy jeden wiersz danych:
public DataTable GetBookByIsbn(string isbn)
Przejcie na encje powinno mie wpyw na uproszczenie warstwy dostpu do danych. Modyfikacja metody GetAll wie si jednak z pewnym stopniem zoonoci, o ktry zostanie wzbogacona nasza warstwa. W warstwie dostpu do danych w modelu dwuwarstwowym metoda
GetAll bya zaimplementowana w klasie bazowej AbstractDA. Dla odpowiedniej instrukcji
SELECT zwracaa ona po prostu wypeniony obiekt klasy DataTable:
public DataTable GetAll()
{
string sql = SelectStatement;
return GetDataTable(sql, null);
}
Rozdzia 11.
611
Ktre z powyszych krokw s rne dla rnych podklas dostpu do danych? S to kroki 2.
oraz kroki od 8.1 do 8.3. Wszystkie pozostae kroki algorytmu s stae i nie zale od pobieranych danych. W istniejcej klasie AbstractDA zmieniajcy si krok 2. zosta obsuony
w nastpujcy sposb:
string sql = SelectStatement;
W celu uproszczenia powyszego fragmentu kodu, a take innych fragmentw zamieszczonych w niniejszym rozdziale, pominito w nich obsug wyjtkw oraz inne
szczegy. Pene wersje s dostpne na mojej witrynie pod adresem http://www.
randyconnolly.com/core.
Gdy przykadowa wersja szablonu metody jest ju zaimplementowana, mona zacz implementacj algorytmu GetAll klasy AbstractDA. Aby byo atwiej, zajmiemy si krokami
od 5. do 10.
612
Cz II
Operacje na danych
EntityCollection<AbstractEntity> collection;
Collection = new EntityCollection<AbstractEntity>();
DbDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
collection.Add( CreateAndFillEntity(reader) );
}
reader.Close();
conn.Close();
return(collection);
Poniewa jest zwracany zbir, a nie obiekt klasy DataTable, nie ma potrzeby uywania klasy
DataAdapter w celu jego wypenienia. Zamiast tego mona skorzysta z o wiele szybszej klasy
DataReader. Wystarczy po prostu przebiec w ptli przez zwrcony czytnik danych, aby kada
podklasa odczytaa rekord, utworzy i wypeni odpowiedni encj, a nastpnie doda j
do zbioru.
W poprzednim przykadzie kryje si jednak pewien problem. W rozdziale 8. klasa EntityCollection zostaa zdefiniowana za pomoc typw oglnych, aby bya zbiorem silnie typizowanym, a w przytoczonym przykadzie jest zwracany zbir obiektw klasy AbstractEntity.
Oznacza to, e kada klasa, ktra przetwarza wspomniany zbir, musi rzutowa encje na odpowiedni typ w pokazany poniej sposb:
PublisherDA dao = new PublisherDA();
EntityCollection<AbstractEntity> collection = dao.GetAll();
Publisher pub = (Publisher)collection[0];
W klasie AbstractDA naley uy parametru typu w miejscach, w ktrych wczeniej nastpowao odwoanie do klasy AbstractEntity. Definicja klasy abstrakcyjnej CreateAndFillEntity zmieni si zatem nastpujco:
protected abstract T CreateAndFillEntity(DbDataReader reader);
Rozdzia 11.
613
Jeli pola dla kadej z tych dodatkowych tabel zostan doczone do instrukcji SELECT dotyczcej ksiek (tak jak w nastpnym przykadzie), bdzie mona utworzy i wypeni encje
Publisher, Category oraz Series po odczytaniu rekordu ksiki.
protected override string SelectStatement
{
get {
return "SELECT ISBN,Title,YearPublished,BriefDescription,
Description,PublisherName,Books.PublisherId As
BookPublisherId,SeriesName,Books.SeriesId As
BookSeriesId,CategoryName,Books.CategoryId As
BookCategoryId FROM Series INNER JOIN
(Publishers INNER JOIN (Categories INNER JOIN
Books ON Categories.CategoryId = Books.CategoryId)
ON Publishers.PublisherId = Books.PublisherId)
ON Series.SeriesId = Books.SeriesId";
}
}
Obsuga autorw ksiek jest nieco bardziej skomplikowanym zagadnieniem, poniewa tabele Books oraz Authors wie relacja wiele do wielu. Metoda GetAuthors klasy AuthorDA
jest uywana w celu uzyskania zbioru obiektw klasy Author na podstawie biecej wartoci
pola ISBN. Kada encja Author w tym zbiorze jest nastpnie dodawana do encji Book w sposb
pokazany poniej:
614
Cz II
Operacje na danych
Metoda GetAuthorsForIsbn klasy AuthorDA pobiera tabele AuthorBooks oraz Author, a zwraca
list encji Author zgodnych z przekazan wartoci pola ISBN.
public EntityCollection<Author> GetAuthorsForIsbn(string isbn)
{
EntityCollection<Author> collection =
new EntityCollection<Author>();
using (DbConnection conn =
DatabaseActions.Factory.CreateConnection())
{
conn.ConnectionString =
DatabaseActions.ConnectionSetting.ConnectionString;
conn.Open();
Rozdzia 11.
615
Na koniec naley w podobny sposb zmodyfikowa metody Update oraz Insert klasy BookDA,
aby tabele potomne take podlegay aktualizacji.
616
Cz II
Operacje na danych
Aktualizacja ksiki
Przedstawiona warstwa logiki aplikacji jest przede wszystkim warstw usugow, poniewa nie zawiera adnych przykadw bardziej zoonej logiki aplikacji ani procesw.
Jeli w niniejszym rozdziale pokazano by klas OrderLogic, byoby widocznych wicej metod zorientowanych na procesy, takich jak na przykad CheckOutPipeline albo
MoveProductFromDistributorToInventory.
Jak ju wspomniano, klasy w warstwie logiki aplikacji prawie w ogle nie zawieraj stanu i przekazuj wikszo swoich zada innym warstwom. Na listingu 11.3 przedstawiono
przykadow implementacj wymienionych powyej funkcji w klasie BookCatalogLogic.
Rozdzia 11.
617
618
Cz II
Operacje na danych
Rozdzia 11.
619
Rysunek 11.12.
BookPortal.aspx
620
Cz II
Operacje na danych
<asp:ObjectDataSource ID="dsPublishers" runat="server"
TypeName="FourLayer.ApplicationLogic.BookCatalogLogic"
SelectMethod="GetAllPublishers" />
<asp:ObjectDataSource ID="dsCategories" runat="server"
TypeName="FourLayer.ApplicationLogic.BookCatalogLogic"
SelectMethod="GetAllCategories" />
Rozdzia 11.
621
622
Cz II
Operacje na danych
kategorii ksiek.
<asp:GridView ID="grdCategories" runat="server"
DataSourceID="dsCategories" DataKeyNames="Id"
AutoGenerateColumns="False"
OnSelectedIndexChanged="grdCategory_SelectedIndexChanged">
<Columns>
<asp:TemplateField HeaderText="Kategorie">
<ItemTemplate>
<asp:LinkButton ID="btnSelectCategory"
runat="server"
Text='<%# Eval("Name") %>'
CommandName="Select" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Rozdzia 11.
623
dsBooks.SelectMethod = "GetBooksByCategory";
dsBooks.SelectParameters.Clear();
Parameter p = new ControlParameter("catId", "grdCategories",
"SelectedDataKey.Values[0]");
dsBooks.SelectParameters.Add(p);
}
listy z wydawcami, seriami oraz kategoriami, a take lista ksiek. Lista ksiek
powinna ulega zmianie po wybraniu wydawcy, serii albo kategorii.
Przykad 11.4. Dodanie moliwoci przegldania oraz edycji danych wybranej ksiki
Kontrolka DetailsView zostanie uyta w celu wywietlania i edycji wszystkich danych wybranej ksiki.
1.
624
Cz II
Operacje na danych
<asp:TemplateField HeaderText="Autorzy">
<ItemTemplate>
<asp:GridView id="grdAuthors" runat="server"
AutoGenerateColumns="false" ShowHeader="false"
DataSource='<%# Bind("Authors") %>'>
<Columns>
<asp:BoundField DataField="Name" />
</Columns>
</asp:GridView>
</ItemTemplate>
<EditItemTemplate>
<a href='EditAuthors.apx?book=<%#
Eval("ISBN") %>'>
Edit Authors
</a>
</EditItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="YearPublished"
HeaderText="Rok" />
<asp:TemplateField HeaderText="Opis">
<ItemTemplate>
<%# Eval("BriefDescription")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtBrief" runat="server"
TextMode="multiLine" Columns="45" Rows="7"
Text='<%# Bind("BriefDescription") %>'/>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Wydawca">
<ItemTemplate>
<%# Eval("BookPublisher.Name") %>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="drpPublisher" runat="server"
DataSourceID="dsPublishers" DataValueField="Id"
DataTextField="Name"
SelectedValue='<%# Bind("PublisherId") %>' />
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Seria">
<ItemTemplate>
<%# Eval("BookSeries.Name") %>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="drpSeries" runat="server"
DataSourceID="dsSeries" DataValueField="Id"
DataTextField="Name"
SelectedValue='<%# Bind("SeriesId") %>' />
</EditItemTemplate>
</asp:TemplateField>
Rozdzia 11.
625
<asp:TemplateField HeaderText="Kategoria">
<ItemTemplate>
<%# Eval("BookCategory.Name") %>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="drpCategory" runat="server"
DataSourceID="dsCategories" DataValueField="Id"
DataTextField="Name"
SelectedValue='<%# Bind("CategoryId") %>' />
</EditItemTemplate>
</asp:TemplateField>
<asp:CommandField ButtonType="Image"
ShowEditButton="true" ShowCancelButton="true"
CancelImageUrl="images/btn_cancel.gif"
EditImageUrl="images/btn_edit.gif"
UpdateImageUrl="images/btn_update.gif" />
</Fields>
</asp:DetailsView>
626
Cz II
Operacje na danych
Rozdzia 11.
627
Rysunek 11.13.
Naruszone
reguy biznesowe
na stronie
BookPortal.aspx
Podsumowanie
W niniejszym rozdziale skupiono si na implementacji warstwowych architektur aplikacji
sieciowych. Fakt, e utworzenie aplikacji sieciowej moe by skomplikowanym przedsiwziciem, stanowi uzasadnienie dla dobrze zaprojektowanej infrastruktury aplikacji. Prawdziwa aplikacja sieciowa moe zawiera dziesitki, a nawet setki opisanych przypadkw
uycia, co sprawia, e niezbdne staje si poczenie wysiku wielu programistw. To wanie w takim rodzaju aplikacji sieciowych prawidowe zasady projektowania oprogramowania
s tak wane. W niniejszym rozdziale omwiono jedn z najwaniejszych idei wykorzystywanych podczas projektowania nowoczesnego, zoonego oprogramowania: pojciowe
628
Cz II
Operacje na danych
wiczenia
Rozwizania poniszych wicze mona znale na mojej stronie WWW pod adresem
http://www.randyconnolly.com/core. Znajduj si tam take dodatkowe wiczenia, ktre s
dostpne wycznie dla nauczycieli i wykadowcw.
1.
Najwaniejsze zagadnienia
Q
Adapter
Domena
Encja
Logika aplikacji
Obiekt biznesowy
Poziom
Rozdzia 11.
Przypadki uycia
Reguy biznesowe
Skojarzenia
Spjno
Warstwa
Warstwa biznesowa
Warstwa domeny
Warstwa prezentacji
Zaleno
629
Odnoniki
Frank Bouma, Solving the Data Access Problem: to O/R Map or Not to O/R Map,
http://weblogs.asp.net/fbouma.
Frank Buschmann i inni, Pattern-Oriented Software Architecture: A System of Patterns,
John Wiley & Sons 1996.
Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software, Addison-Wesley 2004.
Martin Fowler, Architektura systemw zarzdzania przedsibiorstwem. Wzorce projektowe,
Helion 2005.
Craig Larman, Agile and Iterative Development: A Managers Guide, Addison-Wesley 2003.
Microsoft, Application Architecture for .NET: Designing Applications and Services, Microsoft 2003.
Jimmy Nilsson, Applying Domain-Driven Design and Patterns, Addison-Wesley 2006.