Artykuł opublikowany na Codeguru.pl
Warstwy (Layers, tiers)
Warstwowa struktura aplikacji stanowi logiczną dekompozycję systemu. Podział na warstwy (layers, tiers) umożliwia przedstawienie różnych aspektów aplikacji. Pozwala zrozumieć złożone systemy i daje przejrzystość aplikacji. Jednym z najbardziej znanych modeli warstwowych jest 7-warstwowy model ISO, obrazujący budowę protokołów sieciowych.
Klarowność aplikacji WWW używających ASP.NET wymaga także użycia wielowarstwowego modelu aplikacji. Rysunek poniżej przedstawia 3-wartwowy model aplikacji web’owej.
Rys.1 Trzywarstwowy model aplikacji
Każdy z przedstawionych poziomów odpowiada za inne aspekty funkcjonowania systemu. Warstwa prezentacji (Presentation Layer) jest odpowiedzialna za komunikację użytkownika z systemem. Znajdują się tu klasy specyfikujące strony aspx.
Warstwa usług (Business Layer) zawiera klasy, które sterują aplikacją i odpowiadają za jej działanie. Poziom ten stanowi most pomiędzy warstwami danych i prezentacji.
Warstwa danych (Integration Layer) reprezentuje bazę danych.
Elementy poszczególnych warstw nie mają dostępu do elementów innych warstw. Logiczne elementy warstw nie reprezentują ich fizycznego rozmieszczenia. Warstwy mogą znajdować się po stronie serwera jak i po stronie klienta co przedstawiono w tabeli 1.
Tabela 1. Architektury aplikacji wielowarstwowych.
Aplikacje ASP.NET pracują w konfiguracji „cienkiego klienta”, tzn. warstwa prezentacji w postaci stron ASP jest realizowana na przeglądarce internetowej, po stronie klienta, a pozostała funkcjonalność systemu jest dostarczana przez serwer.
Przykładem 3-warstwowej struktury aplikacji ASP.NET jest program „Student”, służący do ewidencjonowania danych o studentach. Funkcjonalność aplikacji w prosty sposób możemy przedstawić w postaci diagramu przypadków użycia.
Rys. 2 Diagram przypadków użycia
Jedynym aktorem, który korzysta z systemu jest „Użytkownik”. Otrzymuje on jako wynik działania usługi „Zobacz dane o studentach” – bazę danych w postaci tabelarycznej. Usługa ta może być rozszerzona o edycję danych studentów. Obrazuje to przypadek użycia „Edytuj dane”. Każdy przypadek użycia jest zbiorem scenariuszy, realizujących różne warianty wykonania przypadku użycia. W omawianej usłudze „Zobacz dane o studentach”, w prezentowanej aplikacji, głównym scenariuszem jest przedstawienie tabeli z danymi. Scenariusz ten prezentuje diagram sekwencji (rys. 3), który przedstawia przepływ komunikatów pomiędzy obiektami.
Rys. 3 Diagram sekwencji
Przedstawione diagramy UML, prezentują model usług i zachowania aplikacji „Student”. Cały zakres złożoności aplikacji najlepiej specyfikuje kod programu i dlatego w dalszej części artykułu zaprezentowano kod aplikacji napisany w C#.
Obiekty klas określone w scenariuszu (rys. 3) zapisane są w plikach, które znajdują się w projekcie aplikacji. Poniżej przestawiono strukturę plików projektu (rys. 4).
Rys. 4 Widok struktury plików
Natomiast składniki znajdujące się na serwerze bazy danych możemy przeglądać w innym oknie, gdyż tabela z danymi i z procedurami wbudowanymi zamieszczona jest w oknie Server Explorer (rys. 5).
Rys. 5 Umiejscowienie procedur wbudowanych i tabeli
Warstwa prezentacji
Ta warstwa jest odpowiedzialna za komunikację użytkownika z systemem. Rezydują w niej klasa Studenci w pliku Studenci.aspx.cs i klasa EdytujStudent w pliku EdytujStudent.aspx.cs. Plik Studenci.aspx przedstawia tabelę z danymi studentów.
Rys. 6 Strona Studenci.aspx z przykładowymi danymi
Plik Studenci.aspx jest zapisany w HTML i przedstawia szkielet strony. Określa takie elementy, jak pozycje kontrolek, ich kolory i czcionki. Plik Studenci.aspx jest uszczegółowiony przez kod i procedury obsługi zdarzeń wymagane do poprawnej pracy strony. Kod i procedury obsługi zdarzeń są zapisane w pliku Studenci.aspx.cs, którego najważniejszą część stanowi metoda Page_Load:
private void Page_Load(object sender, System.EventArgs e)
{
// ***Wczytanie danych do tabeli***
//Tworzenie egzemplarza dla klasy StudentCRT
Student.StudentCTR dane = new Student.StudentCTR();
//Załadowanie danych do kontrolki myDataGrid
myDataGrid.DataSource = dane.ZobaczStudentow();
myDataGrid.DataBind();
}
Natomiast plik EdytujStudent.aspx umożliwia użytkownikowi dodanie danych, edycję i kasowanie.
Rys. 7 Strona EdytujStudent.aspx
Kod i procedury obsługi zdarzeń umożliwiające poprawne działanie strony są zapisane w pliku EdytujStudent.aspx.cs.
Ważnym elementem uruchamia strony jest weryfikacja czy zmiennej nrAlbumu jest przypisana wartość. Jeśli zmienna nie jest pusta następuje wczytanie jednego wiersza z danymi studenta Zdarzenia te mają miejsce w metodzie Page_Load:
private void Page_Load(object sender, System.EventArgs e)
{
//sprawdzenie czy strona jest uruchamiana z parametrem określającym nr Albumu
// parametr ten stanowi wartość komórki w kolumnie nrAlbumu w tabeli Student
if (Request.Params["nrAlbumu"] != null)
{
//Przypisanie parametru do zmiennej NrAlbumu
// zmiana typu zmiennej z integer na string
NrAlbumu = Int32.Parse(Request.Params["nrAlbumu"]);
}
if (Page.IsPostBack == false)
{
//Przypisanie zawartości kontrolki
nrAlbumuLabel.Text="brak";
//Sprawdzenie czy został już przypisany nr albumu
if (NrAlbumu!= 0)
{
// ***Pobieranie jednego wiersza z danymi studenta z tabeli Student***
// Tworzenie egzemplarza klasy StudentCRT
Student.StudentCTR dane = new Student.StudentCTR();
//Wczytanie danych
SqlDataReader dr = dane.ZobaczJednegoStudenta(NrAlbumu);
// czytanie pierwszego wiersza
dr.Read();
// do każdego pola jest przypisywana wartość komórki z tabeli Student
NazwiskoPole.Text = (String) dr["nazwisko"];
ImiePole.Text = (String) dr["imie"];
AdresPole.Text = (String) dr["adres"];
WydzialPole.Text = (String) dr["wydzial"];
// zamknięcie odczytu danych
dr.Close();
//Przypisanie kontrolce wartości zmiennej NrAlbumu
//jednocześnie następuje zapisanie tej zmiennej w postaci string
nrAlbumuLabel.Text =NrAlbumu.ToString();
}
}
}
Kliknięcie w dowolny przycisk umożliwia odpowiednio zatwierdzenie lub skasowanie danych, lub zrezygnowanie z edycji. Poniżej znajduje się przykładowa obsługa przycisku Kasuj
// Zdarzenie DeleteBtn_Click wywołane przyciskiem "Kasuj" umożliwia
// skasowanie danych
private void DeleteBtn_Click(Object sender, EventArgs e)
{
//Sprawdzenie czy wiersz zawiera dane
if (NrAlbumu != 0) {
// Tworzenie egzemplarza klasy StudentCTR
Student.StudentCTR dane = new Student.StudentCTR ();
//Wywołanie metody
dane.KasujStudenta(NrAlbumu);
}
// powrót na stronę początkową
Server.Transfer("Studenci.aspx");
}
Warstwa usług
Warstwa ta zawiera klasę StudentCTR, która odpowiada za funkcjonalność aplikacji. Klasa ta jest umieszczona w pliku StudentCTR.cs .
Klasa StudentCTR zawiera metody, które umożliwiają edycję danych czyli: skasowanie danych w metodzie KasujStudent, dodawanie danych w metodzie DodajStudenta i modyfikację danych w metodzie PoprawStudenta. Za wyświetlanie danych odpowiadają metody: w układzie tabelarycznym – ZobaczStudentow a przy wyświetleniu jednego wiersza ZobaczJednegoStudenta.
Sposób implementacji przykładowej metody zawarty jest poniżej:
public SqlDataReader ZobaczJednegoStudenta(int NrAlbumu)
{
// tworzenie egzemplarza dla połączenia z bazą danych
// parametryPolaczenia są pobierane z pliku Web.config
SqlConnection conn= new SqlConnection(ConfigurationSettings.AppSettings["parametryPolaczenia"]);
//Definiowanie polecenia z bazą danych
SqlCommand comm = new SqlCommand("Zobacz_JednegoStudenta", conn);
// Zdefiniowanie polecenia jako Stored Procedure
comm.CommandType = CommandType.StoredProcedure;
// Dodawanie parametrów do Stored Procedure
SqlParameter parameternrAlbumu = new SqlParameter("@nrAlbumu", SqlDbType.Int, 4);
parameternrAlbumu.Value = NrAlbumu;
comm.Parameters.Add(parameternrAlbumu);
// Otworzenie połączenia z bazą danych
conn.Open();
//Wykonanie polecenia i zamknięcie połączenia z bazą danych
SqlDataReader result = comm.ExecuteReader(CommandBehavior.CloseConnection);
// Zwrot wyniku
return result;
}
Metody klasy StudentCTR łączą się z bazą danych za pomocą obiektu conn.
SqlConnection conn= new SqlConnection(ConfigurationSettings.AppSettings["parametryPolaczenia"]);
Jak widać w linii tej nie ma danych o serwerze, nazwie bazy danych, czy rodzaju połączenia.
Wszystkie dane potrzebne do połączenia zostały zapisane w pliku konfiguracyjnym aplikacji Web.config. Za definiowanie połączenia odpowiada w tym pliku ten fragment kodu:
<appSettings>
<add key="parametryPolaczenia" value="server=localhost;Trusted_Connection=true;database=Studenci_Bazadanych" />
</appSettings>
Dzięki takiemu rozwiązaniu w razie zmian w parametrach połączenia z bazą danych musimy poprawić dane tylko w jednej linijce kodu.
Procedury wbudowane (ang. Stored Procedures)
Procedury wbudowane (procedury przechowywane) są to polecenia, które są zapisane na serwerze baz danych i które zostały napisane specjalnie dla danego typu bazy danych. Dzięki temu, różne aplikacje mogą się odwoływać do zasobów bazy danych i modyfikować jej zawartość bez podawania składni SQL.
W przedstawionym powyżej kodzie polecenia SQL nie są definiowane w kodzie programu. Aplikacja odwołuje się do procedur zapisanych na bazodanowym serwerze SQL. Przykładowo dla metody PoprawStudenta odbywa się to w następujący sposób:
SqlCommand comm = new SqlCommand("Popraw_Studenta", conn);
comm.CommandType = CommandType.StoredProcedure;
Fizycznie polecenia te są zapisane w bazie danych, ale logicznie funkcjonują one w warstwie usług, gdyż zawierają komendy w języku SQL, które sterują bazą danych.
Poniżej zaprezentowano przykładową procedurę umożliwiającą poprawienie danych studenta:
ALTER PROCEDURE Popraw_Studenta
( — zmienne wejściowe
@nazwisko nvarchar (20),
@imie nvarchar (20),
@adres nvarchar (100),
@wydzial nvarchar (50),
@nrAlbumu int
)
AS
UPDATE Student –popraw w tabeli Student
SET — przypisz wartości komórkom ze zmiennych wejściowych
nazwisko=@nazwisko,
imie=@imie,
adres=@adres,
wydzial=@wydzial,
dataModyfikacji=GetDate()
WHERE — przy spełnieniu warunku, że
nrAlbumu=@nrAlbumu — wartość komórki nrAlbumu odpowiada wartości zmiennej @nrAlbumu
Procedury wbudowane są bardzo wygodą formą implementacji poleceń SQL. Należy jednak pamiętać, że aby móc z nich korzystać należy nadać im prawo do wykonywania czy to poprzez zmianę praw dostępu w Enterprise Manager (zawartego w SQL Server 2000), czy to po przez uruchomienie skryptu SQL np.:
GRANT EXECUTE ON Dodaj_Studenta TO public
GRANT EXECUTE ON Kasuj_Studenta TO public
GRANT EXECUTE ON Popraw_Studenta TO public
GRANT EXECUTE ON Zobacz_JednegoStudenta TO public
GRANT EXECUTE ON Zobacz_Studentow TO public
Rys. 8 Umiejscowienie skryptów bazy danych
Warstwa danych
W warstwie danych znajduje się baza danych – Studenci_Bazadanych. Zawarta jest w niej jedna tabela o nazwie Student. Tabela Student posiada sześć kolumn.
Rys. 9 Tabela Student (widok tworzenia)
Kolumna nrAlbumu jest kluczem głównym. Natomiast wartości w niej zawarte są unikalne i dzięki temu mamy pewność, że nr albumu będzie niepowtarzalny. Kolumna dataModyfikacji zawiera datę i czas ostatniego zapisu danych zawartych w wybranym do edycji wierszu. Zawartość tej komórki nie jest pobierana z danych wejściowych, jak w przypadku pozostałych kolumn, ale dynamicznie wywoływana podczas zapisywania po przez polecenie GetDate (patrz procedury wbudowane np.:Popraw_Studenta). Pozostałe kolumny z Tabeli Student przedstawiają dane o studentach.
Po stworzeniu tabeli należy pamiętać o przyznaniu praw do wykonywania poleceń SQL. Możemy to zrobić w dwojaki sposób albo poprzez Enterprise Managera, albo poprzez uruchomienie następującego skryptu:
GRANT SELECT ON dbo.Student TO public AS dbo
GRANT UPDATE ON dbo.Student TO public AS dbo
GRANT INSERT ON dbo.Student TO public AS dbo
GRANT DELETE ON dbo.Student TO public AS dbo
Ważne jest także aby uprawnienia do bazy danych miał użytkownik ASPNET. Można to zrobić używając Enterprise Managera lub poprzez uruchomienie poniższego skryptu (tekst napisany kursywą należy zastąpić ustawieniami indywidualnymi)
DECLARE @username sysname
SELECT @username = ´nazwa komputera\ASPNET´
USE master
EXEC sp_grantlogin @username
USE Studenci_Bazadanych
EXEC sp_grantdbaccess @username
EXEC sp_addrolemember N´db_owner´, @username
Analizując kod programu można zauważyć, że żaden element nie przekracza granic swojej warstwy. Jedynie dane przenikają granice warstw. Ma to swoje ogromne zalety, gdyż nie jesteśmy zmuszeni do realizacji danej warstwy z góry określonym rozwiązaniem technicznym. W podanym przykładzie zastosowano SQL Server jako bazę danych, ale nic nie stoi na przeszkodzie by bazą danych był np. MS Access. Sytuacja ta dotyczy też języka w którym tworzymy aplikację, gdyż wykorzystanym do implementacji językiem programowania nie musi być C#, z powodzeniem może go zastąpić np. Visual Basic.
Podsumowanie
Zastosowanie wielowarstwowej struktury oprogramowania umożliwia dekompozycję programu, a co za tym dalej idzie, wprowadza porządek już podczas implementacji komponentów. W dużych systemach jest to bardzo ważne i pozwala na rozdzielenie kompetencji często niezależnych zespołów odpowiedzialnych za warstwę danych, warstwę logiki biznesowej i warstwę prezentacji.
Użycie Visual Studio. NET wraz z tą techniką umożliwia intuicyjne, sprawne i wydajne tworzenie aplikacji web’owych, dla których podstawę architektoniczną stanowią .NET Framework (z ASP i ADO .NET) oraz IIS z Microsoft SQL Server’em.
Przedstawione rozwiązanie trójwarstwowej struktury aplikacji daje możliwość łatwej jej rozbudowy poprzez dokładanie nowych elementów systemu bez utraty przejrzystości struktury aplikacji. W konsekwencji mamy w rękach narzędzie, które umożliwia wytwarzanie np.: wielkich portali internetowych świadczących swoim klientom bardzo zaawansowane usługi web’owe.
Kod źródłowy i skrypty do utworzenia bazy danych znajdują się poniżej w pliku archiwum.zip
Wykaz literatury
Eeles P.: „Layering Strategies”, Rational Software Ltd., 2002
Esposito D.: „ASP.NET oraz ADO.NET”, RM, Warszawa 2002
Sharp J, Jagger J.: „Visual C#.NET”, RM, Warszawa 2002
Dodawanie komentarzy zostało zablokowane.