Prof. dr. Hab. Inż. Włodzimierz Khadzhynov. Programowanie w środowisku.net

Wielkość: px
Rozpocząć pokaz od strony:

Download "Prof. dr. Hab. Inż. Włodzimierz Khadzhynov. Programowanie w środowisku.net"

Transkrypt

1 Prof. dr. Hab. Inż. Włodzimierz Khadzhynov Programowanie w środowisku.net 1

2 Spis treści Architektura.NET oraz ASP.NET... 4 Kompilacja aplikacji ASP.NET... 5 Oddzielanie kodu od treści... 9 Importowanie przestrzeni nazw Obrabianie zdarzeń na stronach ASP.NET Mechanizm delegacji zdarzeń Formularze internetowe Formularzy HTML oraz formularzy 21 Kontrolki HTML Bezpieczeństwo w ASP.NET Podstawowe zagadnienia bezpieczeństwa aplikacji 28 Uwierzytelnianie Uwierzytelnianie przez Windows Uwierzytelnianie za pośrednictwem formularza Uwierzytelnianie przy użyciu usługi Passport Personalizacja Model dostawców w ASP.NET Wstawianie użytkowników Korzystanie z kontrolki WWW CreateUserWizard Tworzenie strony powitalnej Tworzenie strony logowania Konfigurowanie aplikacji ASP.NET Dostęp do baz danych za pomocą ADO.NET Otwarcie połączenia z baza danych Dodawanie danych przy pomocy ADO.NET Modyfikacja danych przy pomocy ADO.NET Usuwanie danych przy pomocy ADO.NET Czytanie danych z bazy danych za pomocą ADO.NET oraz obiektów klasy DataReader. 59 Wykorzystanie parametrów w instrukcjach SQL Wykorzystanie zapamiętanych procedur Dostęp do danych przy wykorzystaniu obiektów klasy DataSet Filtracja i sortowanie danych w klasie DataTable Wykorzystanie klas DataRelation Struktura klas obiektu DataAdapter Wykorzystanie transakcji w ADO.NET Aktualizacja źródeł danych w DOTNET Blokowanie pesymistyczne Blokowanie optymistyczne Użycie XML Czytanie danych XML Zapis danych XML Walidacja plików XML Związki pomiędzy obiektami klas DataSet oraz Xml Wykorzystanie obiektowego modelu dokumentu XML dla czytania danych Modyfikacja danych w obiektowym modelu dokumentów XML Wiązanie danych

3 Wiązanie danych z kontrolką Repeater oraz obiektem DataReader Wykorzystanie kontrolki REPEATER oraz obiektu DataReader dla formowania listy wypunktowanej Wiązanie danych z kontrolką DropDownList Wykorzystanie kontrolki DataList Edytowanie wyświetlanych pozycji w kontrolce DataList Przykład stworzenia aplikacji z kontrolką DataList w środowisku MS Visual Studio Wykorzystanie kontrolki DataGrid Odwzorowanie kolumn w kontrolce DataGrid Edytowanie danych w kontrolce DataGrid Wykorzystanie szablonów w kontrolce DataGrid Sortowanie danych w kontrolce DataGrid Podział na strony wyświetlanych danych w obiekcie DataGrid Kontrolki walidacyjne ASP.NET Opracowanie interfejsów graficznych (GUI) za dopomogą stron wzorcowych Tworzenie interfejsu graficznego za dopomogą tematów i skórek Opracowanie mechanizmów nawigacji witryn Tworzenie serwisów Technologia AJAX w ASP.NET Technologia Web Parts w ASP.NET

4 Architektura.NET oraz ASP.NET Technologia DOTNET (oraz ASP.NET) udostępniają projektantom następne nowe funkcji i możliwości w porównaniu z innymi technologiami : Tworzenie skompilowanego kodu programowego na poziomie serwera; Metodykę code-behind kodu fonu, przeznaczonej dla oddzielenia logiki serwera od klienckiego formularza; Model wiązania danych; Instalację aplikacji za dopomogą xcopy ; Walidację formularzy na poziomie klienta i serwera; Unifikację języków programowania; Unifikację narzędzie do projektowania aplikacji; Jedyny sposób debugowania aplikacji Web i aplikacji lokalnych. Zasadniczym podejściem w technologii MS.NET jest koncepcja projektowania obiektowego. Microsoft.NET to jest środowisko do stworzenia oprogramowania, które jest niezależnym od platformy systemów operacyjnych i sprzętu oraz które pozwoli opracowywać, kompilować, testować oraz uruchamiać programy wykorzystujące swoje części napisane w różnych językach oprogramowania. Microsoft.NET jest zbudowana jako architektura otwarta, która może być wykorzystana do stworzenia aplikacji Windows lub WWW. ASP.NET to jest kolekcja klas platformy Microsoft.NET, którzy są przeznaczone do obsługiwania poleceń protokołu HTTP oraz do realizacji aplikacji WWW. Praktyczną realizacją Microsoft.NET dla konkretnego systemu operacyjnego jest platforma.net Framework. Platforma.NET Framework jest nadbudową do systemu operacyjnego. Struktura komponentów tej platformy jest pokazana na rys.1. The.NET Framework Components Visual Basic C++ C# XML Web Services Perl Python ASP.NET ADO.NET and XML User Interface.NET Framework Class Library Common Language Runtime Message Queuing COM+ (Transactions, Partitions, Object Pooling) IIS WMI Win32 Rys.1 4

5 .NET Framework realizuje zadania wirtualnego systemu operacyjnego, który na dolnym poziomie jest oparty na konkretnym systemu Win32 oraz na górnym - z systemami oprogramowania oraz aplikacjami którzy odpowiadają standardom Common Language Specification (CLS). Na rys.1 są pokazane poziomy i komponenty.net Framework: Win32 system operacyjny, gdzie istnieje.net Framework (Windows 2000, XP, itp.). Aplication Services (Usługi aplikacji) - zbiór usług systemu operacyjnego, którzy mogą być wywołane przez odpowiednie klasy w bibliotece klas.net Framework. Głównymi usługami aplikacji są: komponenty COM+, usługi kolejkowania (Message Queuing), IIS oraz instrumenty Windows (Windows Management Instrumentation). CLR Common Language Runtime (Wspólne Środowisko Uruchomieniowe). CLR to jest maszyna wirtualna, która upraszcza instalowanie aplikacji poleceniem xcopy, zapewni trwałe oraz bezpiecznie środowisko do uruchomienia, wspólny system typów, nadzór nad wykonywaniem aplikacji, kompilacja kodu aplikacji na 1 i 2 etapie, optymalizacja kodu(różne języki programowania), automatyczne zarządzanie pamięcią, debugowanie, bardzo szeroki zestaw przestrzeni nazw(bibliotek)..net Framework Class Library (Biblioteka klas.net Framework) to są serwisy, którzy mogą być wykorzystane dla projektowania aplikacji. Te klasy pozwalają zrealizować dostęp do różnego rodzaju funkcji systemowych (dostęp do baz danych, wykorzystanie kontrolek itp.) zgodnie z zasadami projektowania obiektowego. Wszystkie aplikacji.net (WWW, Windows), którzy mogą być stworzone w różnych językach oprogramowania, wykorzystają te same klasy. Użytkownik ma możliwość stworzenia własnych klas. ADO.NET - to jest następna wersja technologii ADO dostępu do baz danych. Zawiera nowe możliwości skutecznego dostępu do danych bez konieczności stałego połączenia ze źródłem danych. ADO.NET wykorzysta standard XML dla dostępu i przesyłania danych. ASP.NET to jest środowisko projektowania WWW aplikacji w specyfikacjach CLR. Te aplikacji mogą być uruchamiane przez interfejsy użytkownika (User Interface) lub istnieć w postaci WEB Serwisu (XML Web Services). User Interfaces (Interfejs użytkownika) zawiera: Web Forms (formularzy) - popierają protokół HTTP, Windows Forms - wykorzystają funkcji interfejsów Windows. XML Web Services - usługi WWW, mogą być wykorzystane przez różne aplikacji WWW w Internecie.. NET Framework zawiera narzędzie do projektowania i rozpowszechnienia tych usług. Języki oprogramowania - muszą być kompatybilnymi z CLS(Common Language Specification). Ponieważ maszyna wirtualna CLR powinna zapewniać prawidłową współpracę wszystkich części aplikacji, zdefiniowano podstawowy podzbiór cech, które musi mieć każdy język programowania. W przeciwnym razie obiekty napisane w różnych językach nie mogłyby współdziałać. Podzbiór ten jest zdefiniowany w CLS. Kompilacja aplikacji ASP.NET Kompilacja aplikacji.net ma dwa niezależne etapy (rys.2). 5

6 C# VB.NET C++.NET Inne 1 etap kompilacji Kod pośredni kompilacji: Metadane +MSIL 2 etap kompilacji Win 2000 WinXP Linux Inne Rys.2 Język kompatybilny z platformą.net nazywa się językiem zarządzalnym. Kod aplikacji napisanej w dowolnym języku zarządzalnym jest najpierw przekształcany na język pośredni MSIL(Microsoft Intermediate Language). Kod aplikacji w języku MSIL jest niezależny od języka wysokiego poziomu i nie zależy od systemu operacyjnego. Plik pośredni MSIL to jest plik w formacie tekstowym który zawiera metadane. Metadane są to definicje klas, właściwości, metod, a kod MSIL zawiera ich implementację. Drugi etap kompilacji polega na skompilowaniu kodu w języku MSIL na instrukcję języka maszynowego procesora głównego oraz wybranego systemu operacyjnego oraz pozwala na uruchomienie napisanej aplikacji w wybranym środowisku. Kompilatory uczestniczące w 2 etapie kompilacji określane są skrótem JIT (Just-in-time na czas). Dokładniej trzeba ich byłoby nazywać kompilatorami na kod procesora (JIC just-in-code). Na rys. 3 jest pokazana kolejność etapów kompilacji. Rys.3 W środowisku CLR został zdefiniowany Wspólny system typów CTS(Common Type System). Jest to zestaw typów, jakie mogą zostać standardowo zaimplementowane podczas deklaracji metadanych i informacji zapisanych w kodzie MSIL wspólny dla wszystkich języków zarządzanych. To dlatego kod MSIL jest niezależny od języka programowania aplikacji. 6

7 (Demonstracja -> D:\2310B\Media\2310B_01A001.htm) Schemat etapów kompilacji jest pokazany na rys. 4. Kompilacja Program Kod pośredni MSIL i metadane CLR - Common Language Runtime Aplikacja Rys. 4 Rezultatem każdego z tych etapów kompilacji są komponenty (podzespoły).net (assembly) w postaci plików dll, zawierające kody pośrednie MSIL lub kody maszynowe. Komponent.NET (podzespół) jest to podstawowa jednostka, która może być wielokrotnie używaną przez CLR. W technologii.net CLR realizuje w pewnym stopniu funkcji maszyny wirtualnej Java. Komponenty dll zawierają inne pliki, na przykład strony ASP.NET, obrazy czy pliki źródłowe VB.NET. Komponent.Net (podzespół) zawiera wewnętrzny manifest, który stanowi metadanowy opis kodu i zasobów umieszczonych wewnątrz komponentu. Wspólne Środowisko Uruchomieniowe CLR może wykonać tylko kod umieszczony w komponencie dll. Dlatego nawet strony ASP.NET są umieszczane w komponentach dll tworzonych dynamiczne, kiedy pojawia się żądanie danej strony. Kod komponentu zawiera w tym przypadku skompilowany kod programu, który trzeba realizować na serwerze oraz statyczne elementy HTML. Wszystkie klasy, którzy są wykorzystane ASP.NET są magazynowane w następnych bibliotekach komponentów dll: Systemowych, Globalny archiwum komponentów (GAC Global assembly cache), Lokalny archiwum komponentów. Wszystkie potrzebne klasy muszą być załadowane przez Proces roboczy ASP.NET (Workprocess ASP.NET). Na rys. 5 jest pokazany przykład tego procesu oraz przestrzeń pamięci aplikacji ASP.NET z różnymi modułami komponentów. Biblioteka komponentów systemowych jest ustalona uruchamianiu usługi.net. Biblioteka zawiera klasy systemowe niezbędne dla aplikacji ASP.NET. Globalny archiwum komponentów GAC zawiera biblioteki dll użytkownika, którzy mogą być dostępne wszystkim aplikacjom ASP.NET na tym komputerze. Lokalny archiwum komponentów jest dostępny tylko dla jednej aplikacji. 7

8 Polecenie HTTP: GET /foo/foo.aspx Odpowiedz HTTP: HTTP/ Hello World! WorkProcess ASP.NET AppDomain Komponenty Systemowe: System.web.dll System.data.dll mscorsvr.dll Komponenty GAC: mygacutil.dll... Komponenty lokalne: mypage.dll... Rys.5 Główne zalety wykorzystania tego modelu kompilacji: Prędkość aplikacji ASP.NET w porównaniu z innymi technologiami wymagającymi interpretację kodu stron(asp, PHP). Oddzielne strony są skompilowane w klasy, każda strona ma odpowiedni kod programowy. Dla debagowania stron mogą być wykorzystane te same narzędzie, co i do debagowania kodu programowego. Błędy na stronach są odwzorowane jako błędy kompilacji klas programowych. To oznaczy, że większa część błędów będzie odszukana na etapie kompilacji. Przykład strony dla demonstracji odczytania typów stworzonych dla strony klas jest pokazany w listingu hello.aspx. (uruchom: Listing hello.aspx <%@ Page Language = "VB" %> <script runat = "server"> sub Page_Load (obj as object, e as eventargs) lblmessage.text = "hello! To jest ASP.Net!" end sub </script> <HTML> <% 8

9 Response.Output.Write ("<p> My Page type is: {0}</p>", _ Me.GetType()) Response.Output.Write ("<p> My Page Base type is: {0}</p>", _ Me.GetType().BaseType) %> <BODY> <asp:label id="lblmessage" runat="server"/> </BODY> </HTML> Typem każdej strony jest typ ASP.ImieStrony_aspx (imię pliku z symbolem. zamienionym na symbol _ ). Klasą bazową dla każdej strony jest klasa System.Web.UI.Page. Każda strona ASP.NET jest odziedziczona od tej klasy. Klasa Page zawiera obiekty Application, Session, Cache oraz właściwości i metody. Właściwościami klasy Page są: Response, Request oraz Server. To oznaczy, że istnieje kompatybilność że wcześniejszą wersją ASP. Kod źródłowy strony ASP.NET może zawierać znaczniki HTML, kody scenariuszy w tagach <%..%> lub w znacznikach <script runat = server>...</script>. Te kody będą rozmieszczone w definicji odpowiedniej klasy oraz w funkcjach klasy, którzy będą wywołane przy zdarzeniach. W listingu 1 zostało wykorzystane wyrażenie: Response.Output.Write ( format As String, arg0 as Object), gdzie Format As String zawiera sposób formatowania następnego argumentu arg0, który musi być typem Object. Pozycja {0} w łańcuchu znaków string pierwszego argumentu wyznacza miejsce drukowania następnego parametru, który będzie przekształcony do typu string. Oddzielanie kodu od treści Wcześniej stworzone przez Microsoft środowisko czasu wykonywania ASP w ramach serwera IIS umożliwiało programistom opracowanie programów, które dynamiczne konstruowały strony oferowany przez IIS. Strona ASP zawierała w sobie połączenie statycznego kodu HTML i kodu skryptowego. Gdy jakiś klient żądał strony ASP, serwer IIS znajdował stronę ASP i uaktywniał procesor ASP. Procesor ASP wczytywał stronę i kopiował jej elementy HTML w postaci niezmienionej do strony wynikowej. Oprócz tego procesor ASP interpretował elementy skryptowe ujęte w znaczniki <%...%>. Kod skryptowy wykonywał program, którego wynikiem były ciągi kodów HTML. Ciągi te były wstawiane przez procesor ASP do miejsc, w których na stronie ASP znajdowały się elementy skryptowe, zastępując je. Środowisko ASP jest stosunkowo proste w użyciu dla prostych zadań. Wraz z rosnącymi żądaniami użytkowników powstają wymagania do łatwości programowania oraz do sprawności działania aplikacji. Wadą ASP jest obecność kodu typu spagetti, gdy w tym samym pliku są przyplątane skrypty oraz znaczniki HTML. ASP.NET oferuje znaczną poprawę w tym zakresie. ASP.NET wygląda tak jak oryginalne ASP i większość starego kodu można przenieść na nową platformę bez zmian lub z niewielkimi zmianami. Ale wewnętrzne ASP.NET został kompletnie przebudowany tak, by mógł korzystać ze środowiska obiektowego.net Framework. ASP.NET pozwoli oddzielić kod HTML od logiki programu przy użyciu techniki zwanej kodem schowanym (code-behind). Zamiast łączyć znaczniki HTML z kodem, można umieszczać kod w osobnym pliku, do którego strona ASPX odwołuje się za pomocą odsyłaczy. Każda strona.aspx musi dziedziczyć klasę PAGE, ale plik.aspx nie musi być bezpośrednią klasą potomną od klasy PAGE. Ten plik może tylko dziedziczyć po tej klasie. To oznaczy, że można stworzyć pewną klasę pośrednią, dziedziczącą po klasie PAGE i zażądać, aby plik ImieStrony.aspx (klasy ASP.ImieStrony_aspx) dziedziczył po tej klasie 9

10 pośredniej. Ta nowa klasa pośrednia może udostępniać dowolne możliwości funkcjonalne, które będą dostępne dla klas a plikami źródłowymi.aspx (rys.6). System.Web.UI.Page Klasa pośrednia: Public Class mypr.codebehind1 Inherits Page End Class Klasa dynamiczna utworzona na podstawie pliku.aspx : ASP.CodeBehind1_aspx: <% Page Language = vb Inherits = "mypr.codebehind1" Codebehind ="mypr.codebehind1.vb" %> <html> <body> </body></html> Rys. 6 Ta technologia pozwoli rozpatrywać oddzielnie kody logiki biznesowej od kodów prezentacji stron HTML. Do klasy pośredniej można dodawać różne metody logiki biznesowej, obrabiania zdarzeń, pola i struktury danych. Wszystko to będzie odziedziczone przez klasą pliku ImieStrony.aspx. Plik ImieStrony.aspx nie będzie obciążony liniami kodów. Dla wyznaczenia klasy pośredniej w pliku.aspx musi być odpowiednia dyrektywa Page. W środowisku MS VisualStudio ta dyrektywa jest wygenerowana w sposób automatyczny i zawiera słowa kluczowe : Language, Inherits, Codebehind. Przykład dyrektywy Page jest pokazany na rys.4. Słowo kluczowe Codebehind jest zrozumiale tylko dla środowiska MS VisualStudio oraz wyznaczy plik źródłowy klasy pośredniej. Standard ASP.NET nie zawiera tego formatu, zamiast Codebehind jest wykorzystywane słowo kluczowe src. Przykład dyrektywy dla wyznaczenia pliku z kodem klasy pośredniej w standardzie ASP.NET jest pokazany w następnym kodzie: <!- Codebehind1.aspx -> <%@ Page Language = VB src = CodeBehind1.aspx.vb Inherits myproj.codebehind1 %> <!- -> Plik, który jest wyznaczony przez słowo kluczowe src będzie odkompilowany w oddzielny moduł strony i rozmieszczony w katalogu /bin projektu. Istnieją następne możliwości implementacji kodu programowego do stron ASPX: Kod mieszany (Mixed code) gdy na tej samej stronie kod programowy logiki biznesowej jest przemieszany z kodem HTML logiki prezentacyjnej w znacznikach <%...%>. Ten sposób jest bardzo zły, nie pozwoli w sposób skuteczny opracować logikę biznesową oraz logikę prezentacyjną. Wykorzysta ten sposób w technologii ASP. 10

11 Kod sekcji skryptowych (Inline code) gdy na tej samej stronie kod logiki biznesowej jest zawarty w sekcji <SCRIPT>...</SCRIPT>. W tym przypadku istnieją w tym samym pliku sekcji kodu HTML oraz sekcji kodu programu (Rys. 7) Kod oddzielony od treści (Code-behind). Ten sposób jest rozpatrzony wyżej oraz wykorzysta się w MS VS. Writing Inline Code Code and content in the same file Different sections in the file for code and HTML <HTML> <asp:button id="btn" runat="server"/> </HTML> <SCRIPT Language="vb" runat="server"> Sub Sub btn_click(s As As Object, e As As EventArgs) Handles btn.click End End Sub Sub </SCRIPT> Rys. 7 Technologia ASP.NET pozwoli wykorzystać dowolny sposób implementacji kodu. W przypadkach Mixed code oraz Inline code wszystkie kody są na tej samej stronie ASPX. W przypadku Code-behind code mamy do czynienia dba pliki (Rys.8). Zaletą sposobu Codebehind code jest możliwość niezależnego projektowania interfejsu użytkownika i logiki biznesowej. Rys.8 11

12 Importowanie przestrzeni nazw Przestrzeń nazw platformy.net to jest zbiór prototypów wyznaczonych obiektów klas. Na przykład klasy bazowe, którzy przeznaczone dla funkcjonowania aplikacji w środowisku CLR są zgromadzone w przestrzeni nazw System. W tej przestrzeni są rózne serwisy dla realizacji operacji wejścia wyjścia, bezpieczeństwa, dostępu do danych oraz inne. Dla dostępu do więcej wąskich przestrzeń nazw można wykorzystać np. następne referencję: System.Web lub System.Data. Dostęp do obiektów w przestrzeniach nazw można uzyskać na stronach typu Mixed Code ( z kodem HTML oraz skryptami ) przez dyrektywę Import, np: <% Import Namespace = System.Drawing %> W tym przypadku w skryptach zdefiniowanych w znacznikach <script>...<script/> na tej stronie będą dostępne klasy z kolekcji System.Drawing. Dyrektywa Import informuje kompilator że trzeba wykorzystać kolekcję klas System.Drawing. Domyślnie do każdej strony ASP.NET automatyczne importowane są następujące przestrzenie nazw: System System.Collection System.IO System.Web System.Web.UI System.Web.UI.HtmlControls Syste.Web.UI.WebControls Przestrzenie te są częścią ASP.NET. Nie trzeba ich importować w sposób jawny ani też nigdy nie będą widoczne żadne polecenia stosowane do ich importowania. Przy stworzeniu projektów w Visual Studio Net do każdego projektu są dopasowane następne przestrzenie nazw: System, System.Data, System.Drawing, System.Web, System.XML. Na stronach typu Code-behind code w klasach programowych przestrzenie nazw mogą być wyznaczone przez słowa kluczowe Imports: Imports System.Xml Aby korzystać z obiektów, nie trzeba importować przestrzeni nazw tego obiektu. Można wykorzystać pełną nazwę tego obiektu, która zawiera nazwę przestrzeni nazw, np:... Dim reader As System.Xml.XmlTextReader reader = New System.Xml.XmlTextReader(Server.MapPath("books.xml")) Obrabianie zdarzeń na stronach ASP.NET Zdarzenia są sposobem na to, by umożliwić klasie wysyłanie sygnału wskazującego, że zaszła określona sytuacja o pewnym znaczeniu. Zdarzenia są najczęściej stosowane w interfejsach użytkownika zbudowanych z formularzy WWW (lub Windows), gdzie sygnalizują pro klikniecie przycisku, wprowadzenie znaków z klawiatury lub inne czynności. Zdarzenia mogą również zostać użyte do sygnalizowania innych ważnych wydarzeń, które nie mają nic wspólnego z interfejsem użytkownika, takich jak zmiana stanu jakiegoś obiektu w programie. Obecność klasy pośredniej dla stron ASPX pozwoli definiować w tej klasie metody do obrabiania zdarzeń. Technologia ASP.NET zawiera dwa poziomy obrabiania zdarzeń: Poziom aplikacji Poziom strony. 12

13 Metody do obrabiania zdarzeń na poziomie aplikacji muszą być zdefiniowane w pliku Global.asa. Metody dla obrabiania zdarzeń na poziomie strony mogą być odziedziczone z klas nadrzędnych lub wyznaczone w klasie tej samej strony. Klasa bazowa PAGE dziedziczy od klasy Control cztery zdarzenia: Init Load PreRender Unload. Dla każdego zdarzenia jest wyznaczona metoda wirtualna do obrabiania tego zdarzenia. Warunki inicjacji tych zdarzeń są następujące: Init będzie inicjowane do prezentacji kontrolek strony. Te zdarzenie trzeba wykorzystać dla inicjacji procesów prezentacji kontrolek oraz dla wyznaczenia procedur obrabiania przyszłych zdarzeń. Inicjalizacja kontrolek zdarza się do momentu obrazowania kontrolki na ekranie, dlatego nie można odwołać się do właściwości kontrolek w tym zdarzeniu. Load zachodzi, kiedy zostali stworzone wszystkie kontrolki strony oraz rozpoczyna się ładowanie strony do przeglądarki. Kiedy wynika się te zdarzenie wszystkie kontrolki są stworzone oraz obrazowane. Do właściwości tych kontrolek można zrealizować dostęp w tym zdarzeniu. PreRender jest inicjowane po realizacji wszystkich zdarzeń do formowania klientem pliku HTML. Unload jest sformowane, kiedy strona zakończy się swoje istnienie i będzie unieruchomiona. W listingu event0.aspx.vb (projekt events.event0) jest pokazany przykład kodu klasy pośredniej do testowania zdarzeń strony. Kod strony jest pokazany w listingu event0.aspx. Listing event0.aspx.vb. Public Class event0 Inherits System.Web.UI.Page Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init Trace.Write("Page_Init Event Handler", "Teraz jestem w Page_Init event handler!") End Sub Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Trace.Write("Page_Load Event Handler", "Teraz jestem w Page_Load event handler!") End Sub Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender Trace.Write("Page_PreRender Event Handler", "Teraz jestem w Page_PreRender event handler!") End Sub Private Sub Page_Unload(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Unload Trace.Write("Page_Unload Event Handler", "Teraz jestem w Page_Unload event handler!") End Sub End Class Kod strony event0.aspx zawiera tylko jedną dyrektywę Page: Listing listingu event0.asp. 13

14 Page Trace="True" CodeBehind="event0.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="events.event0" %> <!- demonstracja zdarzen strony PAGE-> Za dopomogą atrybutu Trace= True jest wyznaczona możliwość trasowania. Właściwość AutoEventWireup="true" ustali format Visual Basic 6.0 do specyfikacji wygenerowanych procedur zdarzeń. Przy AutoEventWireup="false" jest odłączony mechanizm poszukiwania funkcji obrabiania zdarzeń w czasie działania kodu aplikacji tym przypadku aplikacja działa szybsze, dlatego że nie trzeba szukać jakie metody są skojarzone z konkretnymi zdarzeniami. Dla trybu AutoEventWireup="false" są niezbędne wcześniejsze rejestracje procedur obrabiania zdarzeń przez słowo kluczowe Handles. Te procedury mogą być skojarzone z odpowiednimi zdarzeniami w następne sposoby: Po domyśleniu Przez mechanizm delegacji zdarzeń (klas delegatów zdarzeń) Przez definicję w sposób jawny ( w kodzie HTML do prezentacji kontrolek) Sposób ustalenia zdarzeń po domyśleniu jest wykorzystany w listingach 3,4. Nazwy procedur obrabiania zdarzeń ustalone zgodnie z wzorcem: ImięObiekta_TypZdarzenia. Sposób po domyśleniu realizuje mechanizm delegacji w sposób niejawny. Mechanizm delegacji zdarzeń. Delegat to jest specjalny typ klasy, który przechowuje referencję do metod. Definicja delegata zawiera prototyp typu funkcji(metody), która może być w delegacie zapisana. Klasa delegata oznaczana jest słowem kluczowym delegate. Wskazuje on rodzaje metod, które mogą posłużyć do utworzenia jego instancji, ale nie określa nazwy żadnej konkretnej metody, lecz jedynie typy argumentów i typ wartości zwracanej przez metodę. Może to być metoda zwykła lub metoda statyczna. Jeśli tylko sygnatura metody odpowiada sygnaturze zdefiniowanej przez delegat, może ona zostać skojarzona z tym delegatem, podobne jest z parametrami danej metody. Umożliwia to programowe modyfikowanie metod, a także dodawanie nowych metod do istniejących już klas. Delegaty mogą być również przekazywane jako parametry, co pozwoli realizować wywołania zwrotne (callback). Wywołanie zwrotne występuje wówczas, gdy metoda otrzymuje jako parametr delegata wskazującego na pewną metodę, którą należy wielokrotnie, cyklicznie wywoływać. Dla przykładu, można przedstawić pewną długo pracującą metodę okresowo wywołującą inną metodę, która uaktualnia pasek postępu pierwszej metody. Przykład definicji klasy delegatów jest pokazany niżej: public delegate void MessagePrintDelegate(string msg); private delegate int GetCountDelegate(Person obj1, Person obj2); protected delegate void LongRunningDelegate(MessagePrintDelegate mpcallback); Instancja delegata może być utworzona jako zwykła klasa do której jest przypisana konkretna metoda(może to być metoda zwykła lub statyczna), która musi odpowiadać sygnaturze delegata. Istnije tylko jedno wymaganie: funkcja musi odpowiadać prototypowi użytemu podczas deklaracji delegata, np.: MessagePrintDelegate mpdel = new MessagePrintDelegate(PrintMessage); GetCountDelegate gcd = new GetCountDelegate(GetCount); LongRunningDelegate lrd = new LongRunningDelegate(LongRunningMethod); Przykład wykorzystania delegatów w C# dla realizacji wywołania zwrotnego jest pokazany w listingu DelegateSimple.Program.cs. 14

15 1. using System; 2. using System.Collections.Generic; 3. using System.Text; 4. namespace DelegateSimple 5. { 6. class Program 7. { 8. public delegate void MessagePrintDelegate(string msg); 9. private delegate int GetCountDelegate(Person obj1, Person obj2); 10. protected delegate void LongRunningDelegate(MessagePrintDelegate mpcallback); 11. static void Main(string[] args) 12. { 13. MessagePrintDelegate mpdel = new 14. MessagePrintDelegate(PrintMessage); 15. GetCountDelegate gcd = new GetCountDelegate(GetCount); 16. int count = gcd(new Person(), new Person()); 17. Console.WriteLine("Otrzymano wartość: {0}", count); 18. LongRunningDelegate lrd = new 19. LongRunningDelegate(LongRunningMethod); 20. lrd(mpdel); 21. Console.ReadLine(); 22. } 23. static void LongRunningMethod(MessagePrintDelegate mpd) 24. { 25. for (int i = 0; i < 99; i++) 26. { 27. if (i % 10 == 0) 28. { 29. mpd(string.format("praca w toku... Wykonano {0}%", i)); 30. } 31. } 32. } 33. static int GetCount(object obj1, object obj2) 34. { 35. // wykonaj jakieś operacje 36. Random rnd = new Random(); 37. return rnd.next(); 38. } 39. static void PrintMessage(string msg) 40. { 41. Console.WriteLine("[{0}] {1}", 42. DateTime.Now.ToShortTimeString(), msg); 43. } 44. } 45. class Person 46. { 47. } 48. class Contact : Person 49. { 50. } 51. } 15

16 Kowariancja i kontrawariancja Kowariancja odnosi się do zdolności metody delegata do zwracania pochodnych typów danych. Przykład. Załóżmy, że mamy delegata zdefiniowanego w następny sposób: delegate Person GetPersonDelegate(); wówczas kowariancja umożliwia poprawnie wykonanie się poniższych linii kodów: GetPersonDelegate gpd = new GetPersonDelegate (GetPerson); GetPersonDelegate gpd = new GetPersonDelegate (GetContact); Kontrawariancja dotyczy zdolności metody delegata do pobierania jako parametrów obiektów klas pochodnych. Większość kontrolek serwerowych mogą generować zdarzenia na serwerze. Przykładem generacji zdarzenia jest przycisk typu BUTTON. Po kliknięciu tego przycisku zawartość formy strony ASP (wyznaczoną znacznikami <form...</form HTML) przekazuje się do serwera za dopomogą metody POST. Kontrolki w odpowiedzi na poczynania użytkownika uruchamiają zdarzenia. Musi być stworzona w głównej klasie strony ASPX funkcja obsługująca zdarzenie. Po domyśleniu to jest metoda o nazwie <Nazwa_kontrolki>_<Nazwa_zdarzenia>. W przypadku kontrolki z indeksem BUTTON1 to jest metoda Button1_Click. Visual Studio.NET tworzy automatyczne funkcji dla obrabiania zdarzeń. Gdy kontrolka uruchamia zdarzenie, mechanizm zdarzeń CLR szuka funkcji obsługi cechującej się odpowiedniej nazwą. Mechanizm zdarzeń.net pozwoli w sposób dynamiczny ustalić związki pomiędzy obiektem, który jest źródłem zdarzenia oraz obiektem, który musi otrzymać komunikat pro zdarzenie. Dla realizacji tego mechanizmu są przeznaczona klasa specjalna delegate. Delegat to jest obiekt specjalny, który pozwoli źródłu zdarzenia połączyć się z funkcją obrabiania tego zdarzenia. W odróżnieniu od innych klas delegat zawiera tylko sygnaturę metody realizującą zdarzenie. Funkcję obsługi można dodać dynamicznie w czasie wywołania kodu za pomocą specjalnej funkcji Visual Basica AddHandler oraz operatora AddressOf. Format tego operatora następny: AddressOf procedurename Operator AddressOf tworzy obiekt klasy delegate, który odwoła do funkcji procedurename. Przykład wyznaczenia procedur do obrabiania zdarzeń przez mechanizm delegatów jest pokazany w events.event1.vb. Listing events.event1.vb Public Class event1 Inherits System.Web.UI.Page Protected Overrides Sub OnInit(ByVal e As EventArgs) AddHandler Me.Load, New EventHandler(AddressOf MyLoadHandler) AddHandler Me.PreRender, New EventHandler(AddressOf MyPreRenderHandler) End Sub Protected Sub MyLoadHandler(ByVal src As Object, ByVal e As EventArgs) Trace.Write("Load Event Handler", "Teraz jestem w MyLoadHandler event handler!") End Sub Protected Sub MyPreRenderHandler(ByVal src As Object, ByVal e As EventArgs) Trace.Write("PreRender Event Handler", "Teraz jestem w MyPreRenderHandler event handler!") End Sub End Class W tym listingu w klasie event1 funkcja OnInit jest przesłaniana metoda klasy macierzystej. W tej metodzie w sposób dynamiczny są wyznaczone nowe procedury dla obrabiania zdarzeń Load oraz PreRender. 16

17 Wyznaczenie procedur zostało zrealizowano za dopomogą specjalnej funkcji Visual Basica AddHandler: AddHandler Me.Load, New EventHandler(AddressOf MyLoadHandler) Pierwszym argumentem tej funkcji jest obiekt klasy Event klasy macierzystej: Me.Load. Drugim argumentem jest obiekt klasy EventHandler. Parametrem wejściowym konstruktora EventHandler() jest obiekt klasy delegat który został stworzony przez operator AddressOf. Operator AddressOf ma tylko jeden parametr: sygnaturę procedury: MyLoadHandler. Przykład dynamicznego stworzenia funkcji obsługiwania zdarzeń jest pokazany w listingu Events2.aspx.vb (projekt events). Listing Events2.aspx.vb 1. Public Class WebForm1 Inherits System.Web.UI.Page 2. Sub TestEvents() 3. Dim Obj As New Class1 4. ' Associate an event handler with an event. 5. AddHandler Obj.Ev_Event, AddressOf myevents 6. Obj.CauseSomeEvent() ' Ask the object to raise an event. 7. End Sub 8. Sub myevents() 9. ' This procedure handles events raised by the object Obj. 10. Me.Label1.Text = "EventHandler złapal zdarzenie (event)." 11. End Sub 12. Public Class Class1 13. Public Event Ev_Event() ' Declare an event. 14. Sub CauseSomeEvent() 15. RaiseEvent Ev_Event() ' Raise an event. 16. End Sub 17. End Class 18. Protected WithEvents Label1 As System.Web.UI.WebControls.Label Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init 21. InitializeComponent() 22. End Sub 23. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 24. Me.TestEvents() 25. End Sub 26. End Class W liniach definiowana klasa Class1. W tej klasie w linii 13 zostało zadeklarowane zdarzenie Ev_Event() bez parametrów wejściowych. Funkcja realizująca bezpośrednio te zdarzenie nie jest zdefiniowana w tej klasie oraz będzie dołączona w sposób dynamiczny. Klasa Class1 zawiera metodę CauseSomeEvent(), która zawiera jedną linię 15. Operator RaiseEvent wywoła zdarzenie Ev_Event(). W liniach 2 7 zdefiniowana metoda TestEvents() klasy WebForm1. W linii 3 tej metody zdefiniowany obiekt Obj który prezentuje klasę Class1. W linii 5 za dopomogą instrukcji : AddHandler Obj.Ev_Event, AddressOf myevents zdarzeniu Ev_Event została przypisana realna funkcja z nazwą myevents, realizująca tę zdarzenie. Sama funkcja myevents zdefiniowana w liniach Format operatora RaiseEvent następny: RaiseEvent eventname[( argumentlist )] Przykład wyznaczenia zdarzeń obiektów kontrolek serwerowych jest pokazany w listingu Events3.aspx.vb ( projekt events). Listing Events3.aspx.vb 17

18 1. Public Class WebForm2 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() End Sub 5. Protected WithEvents _MyButton As System.Web.UI.WebControls.Button 6. Protected WithEvents _message As System.Web.UI.WebControls.Label 7. Protected WithEvents Button1 As System.Web.UI.WebControls.Button 8. Protected WithEvents Label1 As System.Web.UI.WebControls.Label 9. Private designerplaceholderdeclaration As System.Object 10. Protected Sub OnClickMyButton(ByVal src As Object, ByVal e As EventArgs) 11. _message.text = "You clicked the button ""Click me""!" 12. End Sub 13. Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init 14. InitializeComponent() 15. AddHandler _MyButton.Click, AddressOf OnClickMyButton 16. End Sub 17. #End Region 18. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 19. End Sub 20. Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click 21. Label1.Text = "to button!" 22. End Sub 23. Private Sub _MyButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _MyButton.Click 24. _message.text = "Tego komunikatu nie będzie!" 25. End Sub 26. End Class W liniach 5-8 zdefiniowane obiekty kontrolek serwerowych razem ze słowami kluczowymi Protected WithEvents co oznaczy, że kontrolki mogą generować zdarzenia. W linii 15 sekcji Page_Init do zdarzenia Click kontrolki _MyButton jest przypisana metoda OnClickMyButton. Przy kliknięciu _MyButton będzie komunikat "You clicked the button ""Click me""!". Kod funkcji tej kontrolki po domyśleniu w liniach nigdy nie będzie uruchamiany. Dla obrabiania zdarzeń kontrolki Button1 wykorzysta się po domyśleniu metoda Button1_Click (linii 20-22). Większość kontrolek serwerowych mogą generować zdarzenia na serwerze. Przykładem generacji zdarzenia jest przycisk typu BUTTON. Po kliknięciu tego przycisku zawartość formy strony ASP (wyznaczoną znacznikami <form...</form HTML) przekazuje się do serwera za dopomogą metody POST. Kontrolki w odpowiedzi na poczynania użytkownika uruchamiają zdarzenia. Musi być stworzona w głównej klasie strony ASPX funkcja obsługująca zdarzenie. Po domyśleniu to jest metoda o nazwie <Nazwa_kontrolki>_<Nazwa_zdarzenia>. W przypadku kontrolki z indeksem BUTTON1 to jest metoda Button1_Click. Visual Studio.NET tworzy automatyczne funkcji dla obrabiania zdarzeń. Gdy kontrolka uruchamia zdarzenie, mechanizm zdarzeń CLR szuka funkcji obsługi cechującej się odpowiedniej nazwą. Mechanizm zdarzeń.net pozwoli w sposób dynamiczny ustalić związki pomiędzy obiektem, który jest źródłem zdarzenia oraz obiektem, który musi otrzymać komunikat pro zdarzenie. Dla realizacji tego mechanizmu są przeznaczona klasa specjalna delegate. Delegat to jest obiekt specjalny, który pozwoli źródłu zdarzenia połączyć się z funkcją obrabiania tego zdarzenia. W odróżnieniu od innych klas delegat zawiera tylko sygnaturę metody realizującą zdarzenie. 18

19 Funkcję obsługi można dodać dynamicznie w czasie wywołania kodu za pomocą specjalnej funkcji Visual Basica AddHandler oraz operatora AddressOf. Format tego operatora następny: AddressOf procedurename Operator AddressOf tworzy obiekt klasy delegate, który odwoła do funkcji procedurename. Przykład wyznaczenia procedur do obrabiania zdarzeń przez mechanizm delegatów jest pokazany w events.event1.vb. Listing events.event1.vb Public Class event1 Inherits System.Web.UI.Page Protected Overrides Sub OnInit(ByVal e As EventArgs) AddHandler Me.Load, New EventHandler(AddressOf MyLoadHandler) AddHandler Me.PreRender, New EventHandler(AddressOf MyPreRenderHandler) End Sub Protected Sub MyLoadHandler(ByVal src As Object, ByVal e As EventArgs) Trace.Write("Load Event Handler", "Teraz jestem w MyLoadHandler event handler!") End Sub Protected Sub MyPreRenderHandler(ByVal src As Object, ByVal e As EventArgs) Trace.Write("PreRender Event Handler", "Teraz jestem w MyPreRenderHandler event handler!") End Sub End Class W tym listingu w klasie event1 funkcja OnInit jest przesłaniana metoda klasy macierzystej. W tej metodzie w sposób dynamiczny są wyznaczone nowe procedury dla obrabiania zdarzeń Load oraz PreRender. Wyznaczenie procedur zostało zrealizowano za dopomogą specjalnej funkcji Visual Basica AddHandler: AddHandler Me.Load, New EventHandler(AddressOf MyLoadHandler) Pierwszym argumentem tej funkcji jest obiekt klasy Event klasy macierzystej: Me.Load. Drugim argumentem jest obiekt klasy EventHandler. Parametrem wejściowym konstruktora EventHandler() jest obiekt klasy delegat który został stworzony przez operator AddressOf. Operator AddressOf ma tylko jeden parametr: sygnaturę procedury: MyLoadHandler. Przykład dynamicznego stworzenia funkcji obsługiwania zdarzeń jest pokazany w listingu Events2.aspx.vb (projekt events). Listing Events2.aspx.vb 27. Public Class WebForm1 Inherits System.Web.UI.Page 28. Sub TestEvents() 29. Dim Obj As New Class1 30. ' Associate an event handler with an event. 31. AddHandler Obj.Ev_Event, AddressOf myevents 32. Obj.CauseSomeEvent() ' Ask the object to raise an event. 33. End Sub 34. Sub myevents() 35. ' This procedure handles events raised by the object Obj. 36. Me.Label1.Text = "EventHandler złapal zdarzenie (event)." 37. End Sub 38. Public Class Class1 39. Public Event Ev_Event() ' Declare an event. 40. Sub CauseSomeEvent() 41. RaiseEvent Ev_Event() ' Raise an event. 42. End Sub 19

20 43. End Class 44. Protected WithEvents Label1 As System.Web.UI.WebControls.Label Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init 47. InitializeComponent() 48. End Sub 49. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 50. Me.TestEvents() 51. End Sub 52. End Class W liniach definiowana klasa Class1. W tej klasie w linii 13 zostało zadeklarowane zdarzenie Ev_Event() bez parametrów wejściowych. Funkcja realizująca bezpośrednio te zdarzenie nie jest zdefiniowana w tej klasie oraz będzie dołączona w sposób dynamiczny. Klasa Class1 zawiera metodę CauseSomeEvent(), która zawiera jedną linię 15. Operator RaiseEvent wywoła zdarzenie Ev_Event(). W liniach 2 7 zdefiniowana metoda TestEvents() klasy WebForm1. W linii 3 tej metody zdefiniowany obiekt Obj który prezentuje klasę Class1. W linii 5 za dopomogą instrukcji : AddHandler Obj.Ev_Event, AddressOf myevents zdarzeniu Ev_Event została przypisana realna funkcja z nazwą myevents, realizująca tę zdarzenie. Sama funkcja myevents zdefiniowana w liniach Format operatora RaiseEvent następny: RaiseEvent eventname[( argumentlist )] Przykład wyznaczenia zdarzeń obiektów kontrolek serwerowych jest pokazany w listingu Events3.aspx.vb ( projekt events). Listing Events3.aspx.vb 27. Public Class WebForm2 28. Inherits System.Web.UI.Page 29. #Region " Web Form Designer Generated Code " 30. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() End Sub 31. Protected WithEvents _MyButton As System.Web.UI.WebControls.Button 32. Protected WithEvents _message As System.Web.UI.WebControls.Label 33. Protected WithEvents Button1 As System.Web.UI.WebControls.Button 34. Protected WithEvents Label1 As System.Web.UI.WebControls.Label 35. Private designerplaceholderdeclaration As System.Object 36. Protected Sub OnClickMyButton(ByVal src As Object, ByVal e As EventArgs) 37. _message.text = "You clicked the button ""Click me""!" 38. End Sub 39. Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init 40. InitializeComponent() 41. AddHandler _MyButton.Click, AddressOf OnClickMyButton 42. End Sub 43. #End Region 44. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 45. End Sub 46. Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click 47. Label1.Text = "to button!" 20

21 48. End Sub 49. Private Sub _MyButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _MyButton.Click 50. _message.text = "Tego komunikatu nie będzie!" 51. End Sub 52. End Class W liniach 5-8 zdefiniowane obiekty kontrolek serwerowych razem ze słowami kluczowymi Protected WithEvents co oznaczy, że kontrolki mogą generować zdarzenia. W linii 15 sekcji Page_Init do zdarzenia Click kontrolki _MyButton jest przypisana metoda OnClickMyButton. Przy kliknięciu _MyButton będzie komunikat "You clicked the button ""Click me""!". Kod funkcji tej kontrolki po domyśleniu w liniach nigdy nie będzie uruchamiany. Dla obrabiania zdarzeń kontrolki Button1 wykorzysta się po domyśleniu metoda Button1_Click (linii 20-22). Formularze internetowe Formularzy HTML oraz formularzy WWW Formularze zawierają komponenty interfejsu graficznego oraz pozwalają realizować pracę interaktywną klienta. Formularz ma dwa zadania: pierwszym z nich jest zebranie informacji podanych przez użytkownika, a drugim przesłanie ich do wyznaczonej strony na serwerze w celu ich przetworzenia. Dzięki zastosowaniu formularzy, aplikacja internetowa może zażądać otrzymania danych od użytkownika i wykorzystać te dane do podejmowania decyzji. W standardzie HTML wszystkie elementy interfejsu graficznego (pola formularzy) muszą być rozlokowane w znacznikach <form>, </form> na stronie klienta. Technologia ASP.NET pozwoli wykorzystać dwa typy formularzy: Formularzy HTML Formularzy WWW. Formularzy HTML składają część standardu HTML oraz są wykorzystane w tradycyjnym ASP. One zawierają elementy, które tworzą interfejs użytkownika z elementów HTML. To są: przyciski, pola wyboru, listy i odsyłacze prezentowane odpowiednimi znacznikami HTML. W aplikacjach internetowych użytkownicy wprowadzają dane do tych elementów i wysyłają formularz, który przesyła dane do serwera. Zasady działania formularzy HTML są pokazane na rys.9. Te formularzy mogą przesyłać dane tylko do strony z ustalonym adresem w polu ACTION znacznika <form>. Protokół przesyłania musi być wyznaczony w polu METHOD przez wartości GET lub POST. W tym przypadku serwer komunikuje się z klientem tylko za pomocą komunikatów żądań i przekazywania formularzy. Przy wykorzystaniu formularzy HTML serwer nie ma informacji o interfejsie użytkownika oraz o rodzaje danych, które zostaną przesłane. Serwer ma tylko dane, które prześle formularz. Po przesłaniu danych wprowadzonych za pomocą formularza, są one usuwane przez serwer i serwer zapomina pro komunikację. Przy wykorzystaniu formularzy HTML niema możliwości sterować zdarzeniami oddzielnych elementów formularza. Modeli tego typu komunikacji pomiędzy klientem a serwerem nazywają modelami żądanie odpowiedź. 21

22 Klient 1.Tworzy elementy interfejsu 2.Wprowadzanie danych i wysyłanie formularza 3.Wysylanie danych Serwer 4 Otrzymuje dane Rys.9 Technologia ASP.NET zawiera nowy typ formularzy WWW (WEB).Formularze WWW składają się z elementów, które tworzą interfejs użytkownika oraz mogą być przesłane w obu kierunkach: klient-serwer oraz serwer-klient. Wyznaczenie adresy strony docelowej nie jest potrzebne. Jeśli nie jest określone pole ACTION formularz powraca do samego siebie. Ten rodzaj formularzy nazywa się formularzami zwrotnymi (postback forms). Dla analizy danych można na tej samej stronie umieścić fragmenty kodów, które zajmą się danymi wejściowymi. Współczesne technologii projektowania oprogramowania obiektowego potrzebują obecności gotowych komponentów lub kapsułek funkcjonalnych do projektowania aplikacji. W formularzach WWW te komponenty nazywają się kontrolkami i są wykorzystywane do tworzenia interfejsów graficznych, realizacji dostępu do baz danych, walidacji danych, prezentacji danych na stronach WWW, nawigacji na stronach WWW, przesyłania komunikatów poczty elektronicznej, generacji obiektów programowych użytkownika itp. Technologia ASP.NET zawiera następne typy kontrolek: kontrolki HTML, kontrolki WWW, kontrolki walidacji danych, kontrolki użytkownika. Każda z tych kontrolek jest prezentowana odpowiednim kodem HTML wewnątrz znaczników <form>...</form> na stronie klienta. Proces komunikacji serwera z klientem przy wykorzystaniu formularzy WWW jest pokazany na rys. 10. Skoro klient zarządza danej strony, ASP.NET przekształca kontrolki WWW w kod HTML, który jest zrozumiały dla przeglądarki i przesyła go do klienta. Za pomocą skryptów po stronie klienta, generowanych automatycznie przez ASP.NET, elementy tych kontrolek alarmują serwer za każdym razem, kiedy wystąpi odpowiednie wydarzenie, na przykład zostanie naciśnięty przycisk. W ten sposób serwer jest stale informowany o tym, co dzieje się na komputerze klienta. 22

23 Serwer: 1.Tworzenie elementów interfejsu użytkownika 2.Wysylanie elementów w kodzie HTML Klient: 4.Wysłanie danych z powrotem do serwera 3. Wypelnianie formularza i wysłanie Rys.10 Ten sposób komunikacji pomiędzy klientem a serwerem nazywa się modelem sterowania zdarzeniami (event driven model). Technologia ASP.NET do przysyłania danych w obu kierunkach wykorzysta model żądanie-odpowiedź na dolnym poziomie komunikacji. Nadbudowanie modelu sterowanego zdarzeniami nad modelem żądanie-odpowiedź umożliwia tworzenie aplikacji na zasadach programowania obiektowego. Kody definicji Formularzy WWW przypominają tradycyjne formularzy HTML. Różnica polega na tym, że formularzy WWW oprócz elementów HTML mogą zawierać kontrolki które są utworzone na serwerze oraz maja stałe połączenie przez kanał wirtualny z klientem. Kontrolki serwerowe (server controls) mają kod programowy na serwerze oraz odpowiedni kod HTML i skrypty na stronie klienta. Przy wykorzystaniu formularzy z kontrolkami serwerowymi serwer ma wszystkie informacje na temat interfejsu użytkownika i jakich danych oczekuje. Na serwerze są tworzone serwerowe obiekty sterujące, przedstawiające składniki interfejsu użytkownika. W przeciwieństwie do składników formularzy HTML, obiekty te są sterowalne można manipulować ich atrybutami, zdarzeniami, metodami. Kod strony formularza WWW zawiera następne części: elementy interfejsu użytkownika, które są wyświetlane oraz związane z nimi funkcje. Przykład formularza jest pokazany w wydruk0503.aspx (Projekt formularzy, wydruk0503.aspx). Listing wydruk0503.aspx. 1. <%@ Page Language="vb" CodeBehind="wydruk0503.aspx.vb" AutoEventWireup="false" Inherits="formularze.wydruk0503" %> 2. <HTML> 3. <script runat="server"> 4. sub Button1_Click(obj as object, e as eventargs) 5. Label1.Text="You clicked <b>" & obj.text & "</b>" 6. end sub 7. </script> 8. <body> 9. <font size="5">asp.net jest platforma Microsoft </font> 23

24 10. <hr> 11. <p> 12. <form runat="server"> 13. <asp:button id="button1" runat="server" Text="Przycisk1" 14. OnClick="Button1_Click" /> 15. <p> 16. <asp:label id="label1" runat="server" /> 17. </form> 18. </p> 19. </body> 20. </HTML> Każdy obiekt serwerowy musi mieć ustalony parametr runat="server". Kontrolki serwerowe muszą być skojarzone z zdarzeniami przez OnClick="kontrolka_zdarzenie" lub przez delegację zdarzenia w klasie. Zdarzenia są wysyłane do serwera na dwa sposoby: natychmiast po wystąpieniu lub zbiorowo w jednym komunikacie. Natychmiastowy sposób można zrealizować za dopomogą właściwości kontrolki AutoPostBack=true(kiedy kontrolka zawiera tą właściwość, np. kontrolka textbox). W przypadku sposobu zbiorowego wszystkie zdarzenia są buforowane(cached), to znaczy że zapisane są na komputerze-kliencie, dopóki użytkownik nie zdecyduje się przesłać dane. Po przesyłaniu formularza do serwera zostanie zrealizowana następna kolejność zdarzeń : 1. Page_Init. W tym zdarzeniu są stworzone oraz inicjowane kontrolki serwerowe. 2. Generowanie zdarzenia Page_Load. 3. Obsługa zdarzeń z bufora (na przykład Textbox1_Changed) oraz zdarzeń którzy spowodowali przesłanie formularza(na przykład Button1_Click). Jeśli wystąpi kilka zdarzeń jednocześnie, to przetwarzane są bez określonej kolejności. 4. Generowanie zdarzenia Page_Unload. Cykl życiowy obrabiania zdarzeń na stronie jest pokazany na rys.11. Understanding the Page Event Life Cycle Page_Init Control events Change Events Action Events Page_Load Textbox1_Changed Button1_Click Page_Unload Page is disposed Rys.11 W środowisku ASP.NET zapamiętany są widoki stanu każdej kontrolki. Tak samo dzieje się dla danych wprowadzonych przez użytkownika. Jeśli użytkownik wpisze swoje dane w pole tekstowym, okaże się, że wprowadzony tekst pozostaje w tym polu po wysłaniu z powrotem formularza do klienta. Tradycyjne formularzy HTML nie mają tej możliwości, wprowadzane dane są usuwane po każdym przesłaniu. W technologii ASP.NET osiągnięto to przez wystawienie na wyjściu zawartości ukrytych pól formularza HTML za każdym razem, kiedy formularz otrzyma polecenie runat="server". Na stronie klienta w tym przypadku jest sformowany znacznik typu hiden oraz zmienna z nazwiskiem _viewstate która zawiera 24

25 ciąg znaków. Zmienna _viewstate jest przeznaczona do przechowywania zawartości kontrolek. W ASP.NET nie jest konieczne ponowne wprowadzanie przez użytkownika wartości serwerowych elementów sterujących (kontrolek) po przesłaniu formularza, ponieważ jest to robione automatycznie w systemie. Obiekt PAGE zawiera atrybut IsPostBack, który wskazuje, czy dany formularz został wysłany. Kiedy IsPostBack=false formularz nie był jeszcze żadnego razu przesłany do klienta. Zasady wykorzystania atrybutu IsPostBack są pokazane na rys.12. Handling Page Postback Events Page_Load fires on every request Initialize controls Use Page.IsPostBack to execute conditional logic Private Sub Sub Page_Load(ByVal s As As System.Object, _ ByVal e As As System.EventArgs) _ Handles MyBase.Load If If Not Not Page.IsPostBack Then 'executes only only on on initial page page load load End End If If 'this code executes on on every request End End Sub Sub Page.IsPostBack prevents reloading for each postback Rys.12 Formularze internetowe zapisują widok stanu każdej z kontrolek za pomocą ukrytych pól formularza. (Demonstracja postback forms: D:\2310B\Media\2310B_05A002.htm) Kontrolki HTML Elementy kodu HTML są elementami przetwarzanymi wyłącznie po stronie klienta. Na przykład, fragment kodu <input type= text id= Pole1 value= Kowalski > jest przetwarzany do postaci pola tekstowego na przeglądarce. Kontrolki HTML są elementami przetwarzanymi po stronie serwera. Są to obiekty tworzone na serwerze, posiadające atrybuty, metody i zdarzenia, które można odpowiednio obsłużyć. Służą do generowania kodu HTML przesyłanego do przeglądarki. Kontrolki HTML są łatwe do tworzenia ze zwykłego kodu HTML: do każdego elementu HTML dodaje się atrybut runat= server. Każdy z elementów HTML na stronie klienta w tym przypadku ma odpowiadający mu serwerowy obiekt sterujący HTML. (Pokazać formularze.upr.aspx, HTML, Synchronize Dokument online) Klasy wszystkich kontrolek HTML są dziedziczone od klasy HtmlControl. Klasa HtmlControl jest dziedziczona od klas Control oraz Object. Przykład hierarchii klas dla kontrolek HtmlButton, HtmlInputText oraz HtmlInputButton są pokazane na rys System.Object System.Web.UI.Control System.Web.UI.HtmlControls.HtmlControl System.Web.UI.HtmlControls.HtmlContainerControl System.Web.UI.HtmlControls.HtmlButton Rys.13 System.Object System.Web.UI.Control 25

26 System.Web.UI.HtmlControls.HtmlControl System.Web.UI.HtmlControls.HtmlInputControl System.Web.UI.HtmlControls.HtmlInputText Rys14 System.Object System.Web.UI.Control System.Web.UI.HtmlControls.HtmlControl System.Web.UI.HtmlControls.HtmlInputControl System.Web.UI.HtmlControls.HtmlInputButton Rys.15 Po domyśleniu komponenty panelu HTML w Visual Studio.NET nie są obiektami serwerowymi. Żeby przekształcić komponent HTML do postaci kontrolki HTML trzeba na panelu projektu w menu kontekstowym kontrolki wybrać opcję Run As Server Control. Ta opcja powoduje wygenerowanie atrybutu runat = server do definicji kontrolki. Przykład kodu do manipulowania atrybutami kontrolek HTML jest pokazany w projektu formularze.wydruk0506.aspx. <%@ Page Language="vb" AutoEventWireup="false" Inherits="formularze.wydruk0506" CodeFile="wydruk0506.aspx.vb" %> <HTML> <body> <font size="5">kontrolki HTML </font> <hr> <form method="post" runat="server"> <input type="button" id="left" runat="server" Value="Lewy" OnServerClick="Click"> <input type="button" id="center" runat="server" Value="Srodkowy" OnServerClick="Click"> <input type="button" id="right" runat="server" Value="Prawy" OnServerClick="Click"> tekstu. HtmlInputButton. </body> </HTML> <img src="bike.gif" id="rower_image" runat="server" alt="to jest mój rower!"> <div id="label1" runat="server"> <p> To jest tekst przykladowy. Kiedy powyzsze przyciski zostaly nacisniete obraz przesunie sie dokola </p> </div> </form> Przyklad ten to przedstawienie obiektów HtmlImage i Namespace formularze Partial Class wydruk0506 Inherits System.Web.UI.Page #Region " Web Form Designer Generated Code " 26

27 'This call is required by the Web Form Designer. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() End Sub Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init 'CODEGEN: This method call is required by the Web Form Designer 'Do not modify it using the code editor. InitializeComponent() End Sub Sub Click(ByVal obj As Object, ByVal e As EventArgs) Select Case obj.value Case "Lewy" rower_image.align = "left" Case "Prawy" rower_image.align = "right" Case "Srodkowy" rower_image.align = "center" End Select Left.Style("Border-Style") = "notset" Right.Style("Border-Style") = "notset" Center.Style("Border-Style") = "notset" obj.style("border-style") = "inset" End Sub #End Region Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here End Sub End Class End Namespace 27

28 Bezpieczeństwo w ASP.NET W ASP.NET zostali zrealizowane usługi uwierzytelniania(authentication) oraz autoryzacji które działają wspólnie z IIS. Ustawienia mechanizmów bezpieczeństwa, z których będą korzystały aplikacje ASP.NET umieszcza się m.in. w plikach konfiguracyjnych będącymi dokumentami XML o ściśle określonej strukturze. Wyróżniamy dwa rodzaje plików konfiguracyjnych ASP.NET: 1. Znajdujący się w katalogu: %WinDir%\Microsoft.NET\Framework\ <version>\config plik Machine.config zawierający ustawienia globalne dla całego serwera. Ze względu na możliwość popełnienia błędu, który może mieć wpływ na działanie wszystkich aplikacji zainstalowanych na serwerze, nie jest zalecana bezpośrednia ingerencja w zawartość tego pliku. 2. Web.config zawierający konfigurację dla katalogu, w którym się znajduje oraz podkatalogów. Każda aplikacja ASP.NET musi posiadać przynajmniej jeden plik Web.config, który jest umieszczony je katalogu głównym. Każdy z podkatalogów aplikacji może zawierać własny Web.config nadpisujący ustawienia bardziej ogólne. W momencie dostępu do zasobu ASP.NET określa dla niego konfigurację poprzez hierarchiczne prześledzenie ustawień. Podstawowe zagadnienia bezpieczeństwa aplikacji WWW Protokół zabezpieczania w WWW zawiera następnie kroki (rys.16): Identyfikacja(autentyfikacja) użytkownika czyli uwierzytelnienie. To jest proces określenia tożsamości użytkownika żądającego dostępu do informacji. Tożsamość najczęściej jest określana przez nazwę i hasło użytkownika. Dzięki uwierzytelnianiu można uzyskać pewność, że użytkownik, który przesłał zadanie, jest tym za kogo siebie podaje. Jeśli system zabezpieczenia nie będzie w stanie określić tożsamość użytkownika na podstawie przesłanych informacji uwierzytelniających, to proces uwierzytelniania nie zostanie wykonany poprawnie, a anonimowy użytkownik nie uzyska dostępu do zasobów informacyjnych. Jeśli jednak informacje uwierzytelniające okażą się poprawne, to użytkownik uzyska dostęp do systemu i zostanie mu przydzielona odpowiednia tożsamość. Po określeniu tożsamości użytkownika system sprawdza, do jakich zasobów może on uzyskać dostęp. Proces ten nazywany jest autoryzacją. Personalizacja (impersonation) to jest czynność, która pozwoli procesu ASP.NET być uruchomianym z identyfikatorem użytkownika oraz z jego uprawnieniem. Kiedy użytkownik niema uprawnień dostępu do wyznaczonych resursów, to procesy systemowe ASP.NET także nie będą miały dostępu do tych resursów. 28

29 Podanie danych uwierzytelnienia jest Uwierzytelniony? Nie Tak Próba uzyskania dostępu do zasobów Brak dostępu Autoryzowany? Nie Tak Personalizacja danej tożsamości Rys.16 Uwierzytelnianie Środowisko ASP.NET obsługuje następne cztery różne tryby uwierzytelniania: 1. NONE nie są używane żadne usługi uwierzytelniania ASP.NET. 2. WINDOWS standardowe uwierzytelnianie Windows z IIS. 3. FORMS ASP.NET wymaga, aby wszystkie moduły obsługujące żądania stron zawierały cookies wydane przez serwer. Użytkownicy próbujący uzyskać dostęp do zabezpieczonych stron bez cookie są przekierowywani do strony logowania, która weryfikuje ich i wydaje cookies. 4. PASSPORT - jest analogiczny trybu FORMS, tylko cookies są wydawane przez wewnętrzny serwis uwierzytelniania Microsoftu, PASSPORT. Tryby Uwierzytelniania mogą być ustalone w IIS na stronie Metody Uwierzytelniania. Większość witryn WWW domyślnie zezwala na anonimowy dostęp do swoich zasobów(tryb NONE). Oznacza to, że każdy, kto dysponuje dostępem do Internetu, może wejść na taką witrynę i przejrzeć umieszczone na niej strony WWW. Użytkownicy nie muszą być uwierzytelniani, ich tożsamość nie musi być sprawdzana, a każdy użytkownik dysponuje możliwością obejrzenia dowolnych plików znajdujących się na witrynie. Ta sytuacja jest bardzo zła dla realizacji systemów informatycznych z poufnej informacją, np. banki, giełdy, agencji rządowe. Tryby uwierzytelnienia są zrealizowane przez providerzy (providers) uwierzytelnienia. Providerzy to są moduły programowe zawierające kod służący do uwierzytelnienia żądań przesyłanych przez klienty WWW. Istnieją następne typy providerów: Provider dla wewnętrznego uwierzytelnienia Windows za dopomogą managera sieci lokalnej Windows NT (NTLM NT LAN Manager). Provider dla uwierzytelnienia za dopomogą formularza (forms). Provider dla identyfikacji po paszportu (passport). Działanie providerów jest kontrolowane za pośrednictwem plików konfiguracyjnych web.config w aplikacji ASP.NET. Ten plik zawiera sekcje do konfigurowania aplikacji. W tych sekcjach mogą być zadane różne parametry bezpieczeństwa, zwłaszcza: wyznaczony tryb uwierzytelniania, identyfikatory i hasła użytkowników, sposób szyfrowania haseł itp. 29

30 Przykład pliku web.config w którym jest zadany tryb uwierzytelniania Forms (za dopomogą formularzy) jest pokazany w listingu : <?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <authentication mode="forms"/> </system.web> </configuration> Klient Serwer Przegłądarka IIS ASP.NET.NET Framework Windows NT/2000/XP/... Rys.17 Ogólny schemat zabezpieczeń ASP.NET jest pokazany na rys. 17. Ten schemat wyznacza funkcji IIS przy uwierzytelnieniu klientów. Na tym schemacie pokazano, że IIS może bezpośrednio komunikować z systemem operacyjnym dla uwierzytelniania w trybie Windows lub przekierować proces uwierzytelniania do ASP.NET w innych trybach. Gdy klient przesyła żądanie dotyczące jakiejś strony ASP.NET, jest ono odbierane przez IIS. Po odebraniu żądania serwer IIS może uwierzytelnić użytkownika, bądź pozostawić przeprowadzenie uwierzytelnienia w gestii aplikacji ASP.NET. Jeśli to serwer będzie uwierzytelniał użytkownika, to jest on w stanie porównać jego dane uwierzytelniające bezpośrednio z informacjami, jakimi dysponuje system operacyjny. Uwierzytelnienie przez IIS nie jest wymagane. Przy ustaleniu opcji Enable anonymous access w zakładce Authentication methods IIS, serwer IIS będzie tylko przekazywał wszystkie odbierane żądania bezpośrednio do aplikacji ASP.NET. Każde żądanie klienta w tym przypadku wykorzysta konto na komputerze serwera IUSR_MACHINE, gdzie MACHINE oznaczy imię komputera serwera. Strony aplikacji ASP.NET będą odpowiedzialne za uwierzytelnianie oraz użytkownicy będą traktowane jako anonimowe. Dostęp anonimowy sprawia, że każdy użytkownik ma prawo pobrać dowolne zasoby znajdujące się w katalogu. Żeby zrealizować uwierzytelnianie za dopomogą IIS, trzeba skasować opcję Enable anonymous access w zakładce Authentication methods IIS. Uwierzytelnianie przez Windows. Windows Authentication Provider umożliwia uwierzytelnienie w oparciu o mechanizmy uwierzytelnienia dostępne w Internet Information Services (IIS). Wszystkie żądania od klienta do aplikacji ASP.NET zanim dotrą do samej aplikacji muszą przejść w pierwszej kolejności przez IIS. IIS zawsze przy każdym wspieranym sposobie uwierzytelnienia zakłada, że zestaw credentials zawartych w żądaniu może być zweryfikowany w oparciu o informację 30

31 zawartą w katalogu użytkowników Windows. Każdy uwierzytelniany użytkownik musi posiadać konto w katalogu Windows. Jeśli credentials nie odpowiadają istniejącemu i aktywnemu kontu użytkownika IIS odrzuca żądanie klienta. Z tego względu ten rodzaj uwierzytelnienia nie jest zalecany dla dużych rozwiązań integrujących różne technologie. IIS przekazuje do procesu hostującego(roboczego) ASP.NET instancję klasy WindowsIdentity reprezentującą uwierzytelnionego użytkownika (identity). Podstawową cechą uwierzytelniania przez Windows jest aktywne uczestnictwo IIS. Przy tym trybie uwierzytelnienia tożsamości wykorzystywane przez IIS są określane przez konta użytkowników systemu Windows. Aby wykorzystać ten tryb uwierzytelniania, trzeba ustalić wyznaczyć typ uwierzytelniania IIS oraz należy umieścić poniższy znacznik w pliku web.config: <authentication mode="windows"/> Serwer IIS używa trzech różnych typów uwierzytelniania systemu Windows.: Basic autentication uwierzytelnianie podstawowe Digest autentication for Windows domain servers uwierzytelnianie bazujące na skrótach. Integrated Windows Autentication zintegrowane uwierzytelnianie Windows. Typ uwierzytelniania może być ustalony przez odpowiednią opcję w zakładce Authentication methods IIS. Rozpatrzymy szczegółowo te typy uwierzytelniania. Uwierzytelnianie podstawowe (Basic autentication) - jest najprostszą metodą uwierzytelniania. Przy żądaniu klienta do aplikacji ASP.NET zostanie zrealizowany protokół uwierzytelniania, który sformuje okno dialogowe z dodatkowym formularzem do którego trzeba podać identyfikator i hasło użytkownika. Te dane będą przesyłane na serwer w postaci zwyczajnego tekstu oraz potem będą porównane z istniejącymi kontami użytkowników Windows. To nie jest bezpieczny sposób przeprowadzenia uwierzytelniania. Uwierzytelnianie bazujące na skrótach (Digest autentication for Windows domain servers) - działa podobnie jak uwierzytelnianie podstawowe z tym, że zarówno nazwa użytkownika, jak i hasło są szyfrowane przed wysłaniem. Opcja Digest autentication for Windows domain 31

32 servers w IIS może być dostępna wyłącznie wtedy, gdy serwer jest podłączony do domeny sieci Windows. Zintegrowane uwierzytelnianie Windows (Integrated Windows Autentication) nie potrzebuje okien dialogowych, w których są podane dane uwierzytelniające. Nie jest to konieczne, gdyś gdy tylko przeglądarka nawiąże kontakt z serwerem, przesyła do niego zaszyfrowaną informacje, które użytkownik podał przy logowaniu do systemu (to może być dostęp anonimowy lub przez konta Windows). Po otrzymaniu tych informacji IIS przetwarza je i sprawdza, czy dany użytkownik powinien uzyskać dostęp do żądanego zasobu. Zintegrowane uwierzytelnianie systemu Windows używa listów uwierzytelniających użytkowników, które zostały przedstawione w trakcie ich logowania do systemu Windows. Okno dialogowe, służące do pobierania listów uwierzytelniających, nie zostanie użytkownikowi wyświetlone, chyba że dane uwierzytelniające, przedstawione w trakcie logowania do systemu Windows, są nieodpowiednie w stosunku do żądanych zasobów. Zintegrowane uwierzytelnianie systemu Windows składa się z różnych typów uwierzytelniania: NT LAN Manager hasło / odzew oraz Kerberos. NTLM jest protokołem używanym w platformach Windows oraz domenach. W przeciwieństwie od protokołu Kerberos NTLM nie obsługuje przekazywanie uprawnień. Kerberos jest szybszym protokołem od NTLM, chociaż nie tak szybkim jak uwierzytelnianie podstawowe. Kerberos jest polecany dla wykorzystania w przypadkach, kiedy aplikacja przewiduje dużą ilość równoczesnych użytkowników lub przekazywanie uprawnień bezpieczeństwa do SQL Server. Zarówno uwierzytelnianie bazujące na skrótach, jak i zintegrowane uwierzytelnianie Windows wymagają, aby użytkownik korzystał się tylko z przeglądarki Microsoft IE. Uwierzytelnianie przez Windows jest rzadko wykorzystywane w WWW aplikacjach, dlatego że jest niezbędne ustalenie kont użytkowników na serwerze. W listingu Webwindows.config jest pokazany plik konfiguracyjny dla demonstracji trybu Windows. listing Webwindows.config <?xml version="1.0" encoding="utf-8"?> <!-- Dla strony loginwindows.aspx --> <!-- Ustal "dostep anonimowy" = false! --> <configuration> <system.web> <authentication mode="windows" /> </system.web> </configuration> W listingu loginwindows.aspx do tego pliku podany kod strony, która wydrukowuje konto użytkownika Windows oraz typ protokołu uwierzytelniania windows. Listing loginwindows.aspx : Public Class loginwindows Inherits System.Web.UI.Page... Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here Me.AuthUser.Text = User.Identity.Name Me.AuthType.Text = User.Identity.AuthenticationType End Sub End Class Dla ustalenia trybu uwierzytelniania Windows trzeba w serwerze IIS dla odpowiedniego katalogu wirtualnego (w tym przykładzie Authentication) ustalić (patrz rys.17a) : 32

33 Dostęp anonimowy = false Uwierzytelnienie podstawowe= true Rys.17a : Uwierzytelnianie za pośrednictwem formularza. W celu ochrony wybranych stron przed nieuprawnionym dostępem programista może posłużyć się mechanizmem uwierzytelnienia opartym o własną stronę logowania własny formularz (forms-based authentication). Podstawą forms-based authentication jest dostępny w HTTP mechanizm przekierowywania. Użytkownicy nieuwierzytelnieni przy próbie dostępu do chronionych zasobów są kierowani do specjalnie wyznaczonej strony zawierającej formularz umożliwiający wprowadzenie credentials, które następnie są przekazywane do aplikacji ASP.NET. W przypadku pomyślnego uwierzytelnienia aplikacja wystawia ciasteczko uwierzytelniające (authentication cookie), które jest kojarzone z sesją użytkownika, po czym użytkownik jest przekierowywany z powrotem do RETURNURL. Authentication cookie jest przekazywane do aplikacji w nagłówkach kolejnych żądań HTTP. Authentication cookie nie musi być utrwalane w przeglądarce. Technologia ASP.NET daje możliwość realizacji uwierzytelniania nie za pośrednictwem serwera IIS, lecz tworzonej aplikacji ASP.NET. W aplikacji ASP.NET musi być stworzony przez projektanta formularz (strona ASP.NET), który służy do podania informacji uwierzytelniających. Głównym elementem mechanizmu uwierzytelniania w tym przypadku jest cookie stworzony i skojarzony ze stroną użytkownika w razie skutecznego uwierzytelniania przez formularz. Mechanizm działania uwierzytelniania przez formularz jest pokazany na rys

34 Użytkownik zgłasza żądanie IIS Zezwala na przekazanie żądania Użytkownik uzyskuje prawo dostępu do zasobu Tak Czy jest dostępne cookie autoryzacyjne? Nie Przekierowanie do formularza logowania Pobranie danych uwierzytelniających Stworzenie cookie autoryzacyjnego Tak Czy jest uwierzytelniony? Nie Brak dostępu Rys.18 Przebieg procesu uwierzytelniania przy wykorzystaniu formularza zawiera następne czynności: 1. Klient żąda dostępu do chronionej strony. 2. Jeśli wraz z żądaniem nie zostało przesłane ważne cookie uwierzytelniające, to serwer przekierowuje przeglądarkę pod adres URL formularza do logowania. 3. Użytkownik podaje dane w formularzu, a następne wysyła go (dane są wysyłane na serwer metodą POST). 4. Jeśli dane uwierzytelniające są poprawne, to ASP.NET tworzy cookie uwierzytelniające i przesyła je do klienta. 5. Użytkownik uzyskuje prawo dostępu. 34

35 35

36 Po utworzeniu cookie uwierzytelniającego wszystkie żądania przesyłane przez danego użytkownika będą automatycznie uwierzytelniane aż do momentu zamknięcia przeglądarki i zakończenia sesji. Przykład pliku konfiguracyjnego web1.config, który wyznacza tryb uwierzytelnianie przez formularz jest pokazany w listingu web1.config. Listing web1.config. <!-- Dla strony login1.aspx --> <configuration> <system.web> <authentication mode="forms"> <forms name="authcookie" loginurl="login1.aspx" > </forms> </authentication> <authorization> <deny users="?"/> </authorization> </system.web> </configuration> W znaczniku <forms...> są wyznaczone imię cookie (name="authcookie") oraz URL formularza aplikacji (loginurl="login1.aspx"). W znaczniku <authorization> jest zabroniony anonimowy dostęp do aplikacji (<deny users="?"/>). Strona login1.aspx musi zrealizować uwierzytelnianie użytkownika oraz sformować cookie w razie prawidłowych danych uwierzytelniania. Przykład metody realizującej uwierzytelnianie na stronie login1.aspx jest pokazany w listingu Login1.aspx. Listing Login1.aspx. Private Sub btsubmit_click(byval sender As System.Object, ByVal e As System.EventArgs) Handles btsubmit.click If tbusername.text = "user" And _ tbpassword.text = "password" Then ' 1-parameter imie cookie, 2-parameter cookie usuwa sie po zamkniejciu explorera FormsAuthentication.SetAuthCookie("user", False) 'Response.redirect( Response.Querystring("ReturnUrl") ) Response.Redirect("account.aspx") Else lblmessage.text = "<font color=red>przykro mi, " & _ "nieprawidlowa nazwa uzytkownik lub haslo!</font><p>" End If End Sub Kod w listingu Login1.aspx analizuje podane przez użytkownika dane. W razie prawidłowych danych jest wykorzystana klasa statyczna System.Web.Security.FormsAuthentication. Metoda SetAuthCookie tej klasy formuje cookie z kluczem user oraz użytkownik zostaje przekierowany do strony ("account.aspx"). Metoda SetAuthCookie zawiera drugi parametr (true/false) który wyznacza czy musi być chroniony cookie po zamknięciu eksplorera. Przy wartości True drugiego parametru cookie będzie chroniony po zamknięciu przeglądarki i użytkownik nie musi przy ponownym uruchomianiu aplikacji rejestrować się. W listingu Login1.aspx uwierzytelnianie użytkownika realizuje się w wyrażeniu IF...Else...End If. ASP.NET ma możliwość realizować logikę uwierzytelniania automatyczne. Identyfikatory użytkowników i ich hasła muszą być w pliku web.config. ASP.NET sam sprawdzi odpowiedniość danych wpisanych przez użytkownika z danymi web.config. W listingu web2.config jest pokazany plik zawierający trzy konta użytkowników. Listing web2.config: <!-- Dla strony login2.aspx --> <configuration> <system.web> 36

37 <authentication mode="forms"> <forms name="authcookie" loginurl="login2.aspx" > <credentials passwordformat ="Clear"> <user name="user" password="password"/> <user name="user1" password="password1"/> <user name="user2" password="password2"/> </credentials> </forms> </authentication> <authorization> <deny users="?"/> </authorization> </system.web> </configuration> Sekcja <credentials> zawiera atrybuty użytkowników name oraz password. Atrybut passwordformat określa sposób szyfrowania danych uwierzytelniających przy ich przesyłaniu na serwer. Wartość Clear oznacza, że dani nie są szyfrowanie. Przykład metody realizującej uwierzytelnianie dla tego przypadku jest pokazany w listingu login2.aspx. Dla uwierzytelniania jest wykorzystana metoda Authenticate(tbUserName.Text,tbPassword.Text) klasy statycznej System.Web.Security.FormsAuthentication. Parametrami wejściowymi tej metody są dane z kontrolek TextBox odbierających identyfikator i hasło użytkownika. Listing login2.aspx: Private Sub btsubmit_click(byval sender As System.Object, ByVal e As System.EventArgs) Handles btsubmit.click If FormsAuthentication.Authenticate(tbUserName.Text, _ tbpassword.text) Then FormsAuthentication.SetAuthCookie(tbUserName.Text, False) Response.Redirect("account.aspx") Else lblmessage.text = "<font color=red>przykro mi, " & _ "nieprawidlowa nazwa uzytkownika lub haslo!</font><p>" End If End Sub Klasa System.Web.Security.FormsAuthentication zawiera jeszcze metodę FormsAuthentication.RedirectFromLoginPage(), która formuje cookie w ten samy sposób, że i metoda SetAuthCookie,lecz dodatkowo powoduje także przekierowanie przeglądarki użytkownika pod adres URL, którego początkowo dotyczyło żądanie. Jeśli w łańcuchu zapytania nie zostały zapisane informacje o żądanej stronie, to metoda ta przekieruje przeglądarkę użytkownika na stronę default.aspx. Nie można zatem o niej zapomnieć! Ta strona musi być w katalogu głównym. Przykład procedury realizującej uwierzytelnianie z wykorzystaniem tych metod jest pokazany w listingu login_3.aspx. Plik web.config w tym przypadku jest pokazany w web3.config. Listing login_3.aspx. Private Sub btsubmit_click(byval sender As System.Object, ByVal e As System.EventArgs) Handles btsubmit.click If FormsAuthentication.Authenticate(tbUserName.Text, _ tbpassword.text) Then FormsAuthentication.RedirectFromLoginPage(tbUserName.Text, False) Else lblmessage.text = "<font color=red>przykro mi, " & _ "nieprawidlowa nazwa uzytkownika lub haslo!</font><p>" End If End Sub Listing web3.config. <!-- Dla strony login_3.aspx --> 37

38 <configuration> <system.web> <authentication mode="forms"> <forms name="authcookie" loginurl="login3.aspx" > <credentials passwordformat ="Clear"> <user name="user" password="password"/> <user name="user1" password="password1"/> <user name="user2" password="password2"/> </credentials> </forms> </authentication> <authorization> <deny users="?"/> </authorization> </system.web> </configuration> Metoda FormsAuthentication.RedirectFromLoginPage, jest przydatna do przesyłania użytkowników na stronę, którą chcieli obejrzeć, jednak brakuje jej możliwości wykonania jakichkolwiek czynności po stworzeniu cookie uwierzytelniającego. To znaczy, ze po linii 5 kodu w listingu 5 będzie uruchamiana inna strona oraz żadna ewentualna instrukcja po linii 5 już nie będzie nigdy aktywna. Istnieje możliwość wygenerować cookie oraz pobrać adres strony, której początkowo dotyczyło żądanie bez przechodzenia do niej. Te przejście można zrealizować później po szeregu wyznaczonych czynności. W tym celu trzeba wykorzystać metodę FormsAuthentication.GetRedirectURL(). Na przykład : Dim strurl = FormsAuthentication.GetRedirectURL( user,false) Klasa FormsAuthentication udostępnia także inną metodę GetAuthCookie(). Tworzy ona obiekt klasy. Ten obiekt nie jest obiektem klasy cookie, lecz tylko zawiera kopię przyszłego cookie. Sam cookie może być utworzony bezpośrednio przez obiekt HttpCookie. Metoda GetAuthCookie() ma jednak tę zaletę, iż pozwala na wykonania jakichś czynności po utworzeniu kopię cookie autoryzacyjnego i przed jego przekazaniem do przeglądarki użytkownika. Na przykład można dodać do cookie dowolne dodatkowe informacje(termin ważności cookie itp.). W listingu login4.aspx jest pokazany przykład procedury realizującej uwierzytelnianie z wykorzystaniem metody GetAuthCookie(). W liniach 3-4 realizuje się uwierzytelnianie przez metode Authenticate(). W linii 5 został zdefiniowany obiekt klasy HttpCookie. W liniach 6-7 jest stworzony obiekt klasy HttpCookie który ma nazwisko identyfikatora użytkownika. W linii 8 dla przyszłego cookie jest ustalony termin ważności. W linii 9 jest stworzony sam cookie na komputerze użytkownika:response.cookies.add(cookie). W ciągu 2 minut ten cookie będzie ważny, to znaczy po zamknięciu przeglądarki i powtórnym ją uruchamianiu w ciągu tego terminu nie będzie potrzebne powtórne logowanie tego użytkownika. ASP.NET dla uwierzytelniania będzie pobierał dane użytkownika z pliku cookie na komputerze użytkownika. Listing login4.aspx. Private Sub btsubmit_click(byval sender As System.Object, ByVal e As System.EventArgs) Handles btsubmit.click If FormsAuthentication.Authenticate(tbUserName.Text, _ tbpassword.text) Then Dim cookie As HttpCookie cookie = FormsAuthentication.GetAuthCookie(tbUserName.Text, False) cookie.expires = DateTime.Now.AddMinutes(2) Response.Cookies.Add(cookie) lblmessage.text = "<font color=red>udalo sie!</font><p>" Else 38

39 lblmessage.text = "<font color=red>przykro mi, " & _ "nieprawidlowa nazwa uzytkownik lub haslo!</font><p>" End If End Sub Klasa FormAuthentification zawiera metodę SignOut, która pozwala na wylogowanie danego użytkownika. Metoda ta usuwa cookie autoryzacyjne, co sprawia, że przy ponownej próbie dostępu do chronionych zasobów użytkownik będziesię musiał ponownie zalogować. Uwierzytelnianie przy użyciu usługi Passport Passport-based authentication korzysta z Microsoft Passport scentralizowanej usługi uwierzytelnienia dostarczonej przez Microsoft umożliwiającej realizację single sign-on jednorazowego uwierzytelniania w ramach witryn korzystających z tej usługi. Celem usługi webowej (web service) Microsoft Passport jest dostarczenie jednego wspólnego mechanizmu uwierzytelnienia dla wszystkich witryn korzystających z usługi Passport. Usługa Microsoft Passport stanowi odpowiedź na problem tzw. rozmnażania się danych uwierzytelniających (credentials proliferation). Za pomocą jednego zestawu credentials użytkownik może uzyskać dostęp do wszystkich witryn zarejestrowanych w Microsoft Passport. Uwierzytelnienie w oparciu o Microsoft Passport wymaga, by: witryna umożliwiała korzystanie z tej usługi; osoby korzystające z aplikacji ASP.NET posiadały konta użytkowników w ramach usługi.net Passport. W momencie dostępu do zasobu wymagającego uwierzytelnienia strona, do której użytkownik chce się dostać wyszukuje ciastka (cookie) Microsoft Passport w nagłówku żądania HTTP. Podobnie jak ma to miejsce w przypadku forms-based authentication jeśli strona nie znajdzie ciasteczka Microsoft Passport w nagłówku żądania, użytkownik zostanie przekierowany do witryny.net Passport. Po pomyślnym uwierzytelnieniu użytkownik jest z powrotem przekierowywany do witryny chronionej przez Passport. Ten tryb uwierzytelniania działa podobnie do uwierzytelniania za pośrednictwem formularzy, z tą różnicą, iż żadnych możliwości funkcjonalnych nie trzeba implementować samodzielnie. Podstawą działania obu tych trybów są cookies przechowywanych na komputerach użytkowników i wykorzystanych przy uwierzytelnianiu. W razie uwierzytelniania w trybie Passport użytkownik jest kierowany do specjalnej strony logowania Passport, która sama przesyła prosty formularz dla uzupełniania danymi uwierzytelniania. Formularz ten sprawdza dane uwierzytelniające użytkownika, porównując je z danymi zgromadzonymi przez usługę Microsoft Passport i określa, czy są one poprawne. Proces Uwierzytelniania przy użyciu usługi Passport jest pokazany na rys

40 Przeglądarka Server IIS Usluga MS Passport Żądanie strony która jest uwierzytelniana przez Passport Czy jest cookie? NIE TAK Przekierowanie klienta do strony logowania Pobieranie identyfikatora i hasła z ekranu logowania Przesyłanie danych do Microsoftu Farma serwerów MS Passport Dostarczanie cookie do klienta TAK Klient ma Passport? NIE Dostęp przegłądarki do uwierzytelnianej strony Udostępnianie strony do klienta Dostęp do strony jest zabroniony Rys. 19 Uwierzytelnianie w tym przypadku nie jest bezpośrednio pod kontrolą aplikacji NET, lecz pod kontrolą usługi Microsoft. Anonymous Authentication Konfiguracja aplikacji ASP.NET umożliwia również całkowitą rezygnację z uwierzytelnienia (anonymous authentication), bądź korzystanie z własnego mechanizmu uwierzytelnienia dostosowanego do konkretnych potrzeb użytkownika (custom authentication). Przykładem własnego schematu uwierzytelnienia może być filtr wykorzystujący Internet Server Application Programming Interface (ISAPI). Nasz własny filtr realizowałby własny mechanizm uwierzytelnienia oraz przykładowo tworzył obiekt klasy GenericPrincipal. <configuration> <system.web> <authentication mode="none"/> </system.web> </configuration> Oczywiście konfiguracja określająca brak uwierzytelnienia nie przesądza, że nie będzie wykonywane uwierzytelnienie po stronie IIS tyle, że aplikacja ASP.NET nie będzie zainteresowana wykorzystaniem rezultatów tego uwierzytelnienia. Autoryzacja. Uwierzytelnianie (identyfikacja) jest procesem określenia tożsamości użytkownika na podstawie pewnych informacji. Celem autoryzacji jest wyznaczenie resursów (stron aplikacji) 40

41 do których ma dostęp uwierzytelniany klient. W technologii ASP.NET proces autoryzacji można wykonać na dwa sposoby: 1. Autoryzacja dostępu do plików 2. Autoryzacja dostępu do adresów URL. W przypadku pierwszej metody ASP.NET prowadzi interakcję z systemem operacyjnym w celu powiązania tożsamości użytkownika z informacjami zapisanymi na listach kontroli dostępu (Access Control List ACL). Gdy uwierzytelniony użytkownik spróbuje dostęp do jakiegoś pliku na serwerze WWW, system operacyjny sprawdzi odpowiednie listy kontroli dostępu, aby określić, czy dany użytkownik lub dana rola ma prawa konieczne do wyświetlenia zawartości tego pliku. Przy określaniu uprawnień na podstawie ACL, autoryzacja dostępu do plików współdziała z procesem personalizacji. Wadą tego sposobu są problemy z ustaleniem praw użytkowników w ACL w przypadku dużej ilości katalogów i plików aplikacji ASP.NET. Sposób autoryzacji za dopomogą adresów URL polega na odwzorowaniu tożsamości użytkownika na foldery znajdujące się w żądanych adresach URL. Przykłady autoryzacji byli wykorzystane wcześniej w listingach 2,4,6 plików web.config. W tych przykładach był zabroniony dostęp do wszystkich plików i katalogów użytkowniku anonimowemu. W znacznikach <allow>... </allow> oraz <deny> </deny> sekcji <authorization> </authorization> są podawane uprawnienia. Przykład pliku konfiguracyjnego z autoryzacją jest pokazany w web5.config. Listing web5.config. <!-- Dla plika login5.aspx --> <configuration> <system.web> <authentication mode="forms"> <forms name="authcookie" loginurl="login5.aspx" > <credentials passwordformat ="Clear"> <user name="user" password="password"/> <user name="user1" password="password1"/> <user name="user2" password="password2"/> <user name="user3" password="password3"/> </credentials> </forms> </authentication> </system.web> <location path="account.aspx"> <system.web> <authorization> <deny users="?"/> </authorization> </system.web> </location> <location path="folder2"> <system.web> <authorization> <allow users ="user3,user2" /> <deny users="*"/> </authorization> </system.web> </location> </configuration> W tym pliku dostęp do wszystkich resursów jest wzbroniony użytkownikom anonimowym oraz w sekcji <credentials>...</credentials> są wyznaczone konta użytkowników, które mają dostęp do wszystkich plików aplikacji oraz katalogów podrzędnych. Natomiast dostęp do podrzędnego katalogu folder2 jest udostępniony tylko użytkownikom user2 i user3. 41

42 Składnia pliku Web.config umożliwia: określenie ograniczeń w dostępie do zasobów (plików, katalogów) dla indywidualnych użytkowników, bądź też grup użytkowników (ról), jak również rodzajów żądań klienckich (GET lub POST); określenie, czy ograniczenia w dostępie do zasobów dotyczy całości aplikacji, czy też wybranych zasobów: stron (plików), lub podkatalogów aplikacji. W trakcie definicji uprawnień można posługiwać się symbolami wieloznacznymi (wildcards): "*" oznacza każdego użytkownika, bądź każdą grupę; "?" oznacza użytkownika anonimowego. Personalizacja. Personalizacja pozwala technologii ASP.NET na wykonywanie przy wykorzystaniu praw dostępu klienta, którego żądanie jest obsługiwane. Innymi słowy wszystkie procesy w systemie operacyjnym komputera są skojarzone z tożsamością klienta który został wcześniej uwierzytelniany. Kiedy ten klient nie ma uprawnień dostępu do wyznaczonych plików, to aplikacja ASP.NET nie zrealizuje operacji z tymi plikami. Domyślnie mechanizm personalizacji jest wyłączony. W tym przypadku procesy ASP.NET będą wykonywane przy użyciu tożsamości IIS. Schemat procesu personalizacji jest pokazany na rys. 20. Żądanie użytkownika IIS Czy jest uwierzytelniony? NIE Brak Dostępu do resursu ASP.NET TAK Personalizacja włączona? TAK Aplikacja ASP.NET przyjmuje tożsamość użytkownika NIE NIE Aplikacja ASP.NET przyjmuje tożsamość IIS Czy listy ACL zezwalają dostęp? Dostęp do resursu jest dozwolony TAK Rys.20 Włączanie personalizacji może być zrealizowane w następnym kodzie pliku web.config: 42

43 configuration> <system.web> <identity impersonate = true username= user password = psw /> </system.web> </configuration> W tym przykładzie wszystkie procesy ASP.NET będą z uprawnieniami użytkownika user/psw oraz informacje o użytkownikach uwierzytelnionych przez IIS są ignorowane. Możliwość ta jest bardzo przydatna w sytuacjach, gdy wszyscy użytkownicy mają mieć dokładnie te same uprawnienia. Reguły wyznaczenia uprawnień personalizacji są w następnej tabeli. Sposób zadania Dostęp anonimowy jest Dostęp anonimowy jest Personalizacji dozwolony wzbroniony impersonate = true IUSR_ComputerName Identyfikator oddalonego użytkownika impersonate = false Identyfikator procesu IIS Identyfikator procesu IIS jest wyznaczone konto user/psw w znacznikach <identity>...</identity > Wyznaczony w znacznikach <identity>...</identity > identyfikator Wyznaczony w znacznikach <identity>...</identity > identyfikator Decydującym w wyznaczeniu uprawnień przez plik web.config jest obecność parametrów username oraz password w znacznikach <identity>...</identity>. W przypadku, kiedy te pola maja wartości obecność pola impersonate = true będzie ustalona automatyczne. 43

44 Model dostawców w ASP.NET Dla realizacji połączeń w Internet jest wykorzystywany protokół http, który jest protokołem bezstanowym. To oznaczy, że serwer nie pamięta stan żadnego klienta, tylko realizuje polecenia GET/POST. Od klientów przychodzą żądania, a wysyłane są odpowiedzi. Ten protokół nie pozwoli odróżnić jednego komunikatu od innego. Serwer po prostu reaguje na przysyłanie do niego żądania. Dla realizacji trybu bezpołączeniowego w technologii ASP.NET trzeba mieć możliwość aplikacjom użytkowników na zapamiętywanie kontekstu pomiędzy żądaniami do serwera podczas całej sesji z aplikacją. Zapamiętywanie kontekstu oznacza zapisywanie stanu aplikacji w magazynie danych. W ASP.NET są kilka metod dla zapisywania stanów na serwerze, np. : stan aplikacji, stan sesji, obiekt Cache. Możliwe jest także zapisanie stanu po stronie klienta, bezpośrednio na komputerze klienta, np.: cookie, łańcuchy zapytań, ukryte pola, stan widoku. Wszystkie te metody mają ograniczenia skojarzone z czasem życia. W ASP.NET znajduje się mnóstwo podsystemów ( np. systemy zarządzania rolami i członkostwem), które przetrzymują stan użytkowników pomiędzy wieloma transakcjami żądanie-odpowiedź. Systemy te wymagają takiego sposobu zarządzania stanem, który nie musi być ograniczonym czasem życia obiektów. Dla przechowywania stanów są potrzebne zaawansowane mechanizmy, podobne mechanizmom baz danych. W ASP.NET zapisywanie stanów w magazynach danych w zaawansowanych trybach realizowane jest przez mechanizmy dostawców. Dostawca jest obiektem, który umożliwia programowy dostęp do magazynów danych, procesów i innych składników systemu. Dostawcę informacji np. o sesji, można wyznaczyć za dopomogą następnych trybów: InProc, StateServer, SQLServer. Tryb InProc jest domyślnym. W tym trybie generowane sesje przechowywane są w tym samym procesie, w którym działa proces roboczy ASP.NET (aspnet_wp.exe). Tryb ten jest najwydajniejszy spośród wszystkich dostępnych, ale w związku z tym, że sesje przechowywane są w tym samym procesie, za każdym razem, gdy niszczony jest proces roboczy, usuwane są także wszystkie sesje. Procesy robocze mogą być niszczone z wielu powodów, np. wskutek zmiany pliku Web.config, Global.asa lub ustawienia IIS, które 44

45 wymaga usunięcia procesu po upływie określonego czasu. Przykład konfiguracji w pliku Web.config w trybie InProc pokazany jest w listingu: <configuration> <system.web> <sessionstate mode= InProc > </sessionstate> </ system.web> </configuration> Tryb StateServer pozwala na przechowywanie stanu sesji poza procesem aspnet_wp.exe. Przykład konfiguracji w pliku Web.config w trybie StateServer pokazany jest w listingu: <configuration> <system.web> <sessionstate mode= StateServer stateconnectionstring= tcpip= :42424> </sessionstate> </ system.web> </configuration> W tym przypadku sesje będą przechowane w lokalnym serwerze WWW. Tryb SQLServer jest najbardziej niezawodnym sposobem przechowywania sesji. Przykład konfiguracji w pliku Web.config w trybie SQLServer pokazany jest w listingu: <configuration> <system.web> <sessionstate mode= SQLServer <allowcustomsqldatabase= true sqlconnectionstring= Data Source= ; database=mydatabase;integrated Security=SSPI > </sessionstate> </ system.web> </configuration> ASP.NET zawiera wiele systemów, które wymagają zapisywania oraz odzyskania stanów. To są np. między innymi następne systemy: członkostwo, zarządzanie rolami, nawigację strony, personalizację, monitorowanie stanu oraz zdarzenia sieciowe, personalizację Web parts, zabezpieczenie pliku konfiguracyjnego. Wymienione wyżej systemy nie wykorzystają zapisywanie stanu w trybie ulotnym, natomiast dla tych celów są niezbędne przechowywania stanów w bazach danych. Domyślnym dostawcą w ASP.NET jest baza danych aspnetdb w środowisku MSSQLServerExpress. Kiedy MSSQLServerExpress jest zainstalowany, to ta baza danych tworzy się w sposób automatyczny przy uruchomieniu w MS VisualStudio narzędzi administracyjne Website/ASP.NET Configuration lub przy tworzeniu kontrolek na stronach związanych z dostawcami. To są np. kontrolki grupy login. 45

46 Wykorzystanie MSSQLServerExpress dla realizacji funkcji dostawców nie jest konieczne. Baza danych aspnetdb może stworzona w dowolnym środowisku SQL Server. W tym celu może być wykorzystywane narzędzie systemowe aspnet_regsql.exe. Niżej, na rysunkach 1-6 jest są pokazane przykładowe kroki do tworzenia bazy dostawców w SQL Server. Rys.1 Rys.2. 46

47 Rys.3 Rys.4 47

48 Rys.5 Rys.6 Żeby wprowadzić zmiany w ścieżkach dostępu do bazy dostawców do innego źródła danych oprócz MSSQLServerExpress trzeba w ręczną zmodyfikować plik konfiguracyjny w sposób pokazany w listingu: <connectionstrings> <remove name="localsqlserver" /> <add name="localsqlserver" connectionstring="data Source=HP;Initial Catalog=aspnetdb;User ID=sa;Password=asdf" /> <!--inne connection stringi--> </connectionstrings> 48

49 Nie istnieje możliwości dokonać zmian w ścieżkach dostępu do bazy dostawców na poziomie narzędzie administracyjną Website/ASP.NET Configuration! Wstawianie użytkowników W celu dodania użytkowników do usługi członkowstwa należy ich zarejestrować w magazynie danych aspnetdb. Ten magazyn danych może być utworzony w środowisku MS SQL Server Express Edition lub MS SQL Server. W pierwszym przypadku plik aspnetdb.mdf jest automatyczne utworzony w katalogu App_Data witryny. Wstawianie użytkowników witryny do bazy aspnetdb można dokonać w dwa sposoby: przez kontrolkę WWW CreateUserWizard, przez kreator Web Site Administrative Tool (WAT). Korzystanie z kontrolki WWW CreateUserWizard Kontrolka WWW CreateUserWizard jest przeznaczona dla realizacji usług członkowstwa i pozwala wstawić dane użytkownika. Przykład użycia kontrolki na stronie jest pokazany w listingu: <body> <form id="form1" runat="server"> <div> </div> <asp:createuserwizard ID="CreateUserWizard1" runat="server"> <WizardSteps> <asp:createuserwizardstep runat="server" /> <asp:completewizardstep runat="server" /> </WizardSteps> </asp:createuserwizard> </form> </body> Wykorzystanie kontrolki po domyśleniu wymaga silnych haseł długości 7 symboli. Te wymagania można zmienić dodając do pliku Web.config aplikacji odpowiednią sekcją, pokazaną w listingu. Te ustalenia zamieniają ustalenia domyślne pliku machine.config: <membership> <providers> <clear/> <add name="aspnetsqlmembershipprovider" type="system.web.security.sqlmembershipprovider, System.Web, Version= , Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionstringname="localsqlserver" requiresquestionandanswer="false" requiresunique ="true" passwordformat="hashed" minrequiredpasswordlength="3" minrequirednonalphanumericcharacters="0" /> </providers> </membership> W tym listingu atrybut minrequiredpasswordlength="3" wymaga 3 litery dla hasła, natomiast atrybut minrequirednonalphanumericcharacters="0" nie wymaga specjalnych symboli w hasłach. 49

50 Tworzenie strony powitalnej Do strony powitalnej (Welcome.aspx) tzeba przeniejść konttrolkę LoginSatus. Ta kontrolka wyświetla status logowania poprzez wyświetlanie odnośnika. W przypadku gdy użytkownik został pomyślnie zalogowany do systemu, kontrolka wyświetla odnośnik umożliwiający wykonanie operacji wylogowania z niego. Użytkownicy niezalogowani w systemie posiadają odnośnik do strony logowania. Warto by zobaczyć, kto zalogował się do witryny, w tym celu trzeba przeciągnąć kontrolkę LoginView. Kontrolka LoginView ma dwa widoki: AnonimousTemplate oraz LoggedInTemplate. To, który z tych szablonów będzie wyświetlany, zależy od faktu, czy użytkownik się zalogował. Szablon AnonimousTemplate jest przeznaczony dla użytkowników niezalogowanych. Kod strony Welcome.aspx jest pokazany w następnym listingu: Page Language="C#" AutoEventWireup="true" CodeFile="Welcome.aspx.cs" Inherits="Welcome" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " <html xmlns=" <head runat="server"> <title>untitled Page</title> <style type="text/css"> #form1 { height: 309px; } </style> </head> <body> <form id="form1" runat="server"> <div> </div> <asp:loginstatus ID="LoginStatus1" runat="server" /> <asp:loginview ID="LoginView1" runat="server"> <LoggedInTemplate> Witaj <br /> <asp:loginname ID="LoginName2" runat="server" /> <br /> <br /> <asp:hyperlink ID="HyperLink1" runat="server" NavigateUrl="~/ProfileInfo.aspx">Dodaj dane do profiu</asp:hyperlink> </LoggedInTemplate> <AnonymousTemplate> Nie jesteś zalogowany. Kliknij lącze Logowanie... </AnonymousTemplate> </asp:loginview> <asp:loginname ID="LoginName1" runat="server" /> </form> </body> </html> 50

51 Tworzenie strony logowania Do witryny WWW należy dodać następną stronę, o nazwie Login.aspx. Strona musi nosić dokładnie taką nazwę, ponieważ w przeciwnym wypadku inne kontrolki nie będą mogli jej wywołać. W listingu są pokazane kody strony Login.aspx z kontrolką Login. <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " <html xmlns=" <head runat="server"> <title>untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> </div> <asp:login ID="Login1" runat="server" BackColor="#F7F6F3" BorderColor="#E6E2D8" BorderPadding="4" BorderStyle="Solid" BorderWidth="1px" Font- Names="Verdana" Font-Size="0.8em" ForeColor="#333333"> <TextBoxStyle Font-Size="0.8em" /> <LoginButtonStyle BackColor="#FFFBFF" BorderColor="#CCCCCC" BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana" Font-Size="0.8em" ForeColor="#284775" /> <InstructionTextStyle Font-Italic="True" ForeColor="Black" /> <TitleTextStyle BackColor="#5D7B9D" Font-Bold="True" Font- Size="0.9em" ForeColor="White" /> </asp:login> </form> </body> </html> Konfigurowanie aplikacji ASP.NET Konfigurowanie aplikacji WWW zawiera ustalenie różnego rodzaju parametrów którzy wyznaczają sposoby kompilacji stron WWW, ich odwzorowania, dostępu do resursów aplikacji przez użytkowników. W ASP.NET zostało zrealizowane hierarchiczne konfigurowanie aplikacji WWW. Wszystkie parametry konfigurowania są wyznaczone w pliku XML web.config. Ten plik nie może być zmodyfikowany przez przeglądarkę użytkownika. Wszystkie zmiany w tym pliku mogą być dokonane tylko przez edytor tekstu na komputerze z ustalonym projektem aplikacji ASP.NET. Te zmiany będą automatyczne wyznaczone przy uruchomieniu aplikacji oraz nowe parametry konfiguracji będą aktualnymi. Przy instalacji.net Framework jest stworzony plik konfiguracji całego komputera który ma nazwisko machine.config. Ten plik jest rozmieszczony w katalogu C:\WINDOWS\Microsoft.Net\Framework\[wersja]\config. W tym pliku są ustalone domyślne ustawienia dla całego systemu ASP.NET. Wpisy wprowadzone w plikach web.config w katalogach głównych poszczególnych aplikacji WWW mogą przesłaniać ustawienia z katalogu głównego. Wpisy z plików web.config znajdujących się w podkatalogach aplikacji 51

52 mogą przesłaniać wpisy z plików zawartych w katalogach głównych. Plik web.config zawiera rozdziały wyznaczone odpowiednimi tagami. Lista tych tagów jest pokazana w tabeli. Tag Opis <appsettings> <authentication> <athorization> <browsercaps> <compilation> <customerrors> <globalization> <httphandlers> <httpmodules> <httpruntime> <identity> <macvhinekey> <pages> <processmodel> <securitytpolicy> <sessionstate> <trace> <webservices> Dostęp do baz danych za pomocą ADO.NET ADO.NET to jest nowa technologia dostępu do baz danych w środowisku.net, zawierająca odpowiednie klasy, którzy są przeznaczone do realizacji funkcji na bazach danych. Podstawowymi zmianami, jakie są wprowadzone w obiektach ADO.NET w stosunku do ADO, są następne: Zastosowanie języka XML do wymiany danych. Formaty plików XML są wykorzystane przy realizacji wszystkich operacji pomiędzy obiektami ADO.NET. Sposób współpracy obiektów ADO.NET z bazami danych. Obiekty ADO wymagały blokowania dostępu do zasobów bazy danych i stałego połączenia aplikacji z bazami danych. Obiekty ADO.NET korzystają się z odłączonych zbiorów danych (disconnected data sets) (za pomocą obiektu DataSet), co pozwala uniknąć długotrwałych połączeń i blokowania danych. W ten sposób aplikacje ADO.NET stają się skalowalne, ponieważ użytkownicy nie rywalizują o dostęp do baz danych. Funkcjonalna specjalizacja obiektów. W ADO był realizowany płaski model obiektowy, to oznaczy się że ta sama funkcja mogła być zrealizowana przez różne obiekty. Na przykład, obiekt Connection w ADO jest przeznaczony do połączenia z bazą danych, oraz ten obiekt można jednocześnie wykorzystać dla realizacji poleceń do baz danych, lub obiekt RecordSet jest przeznaczony dla przechowywania rezultatów poleceń do bazy danych, oraz ten obiekt może być wykorzystany do połączenia z bazą danych. W ADO.NET funkcji wszystkich obiektów są wyspecjalizowane oraz nie przeplatają się z sobą. Zmiany wprowadzone w technologii ADO.NET w stosunku do technologii ADO są pokazane w następnej tabeli. Tabela 52

53 Technologia ADO Przedstawienie danych: Obiekt Recordset, przypominający pojedynczą tabelę lub wynik kwerendy Dostęp do danych: Sekwencyjny dostęp do wierszy zapisanych w obiekcie RecordSet. Relacje pomiędzy wieloma tabelami: Dane z wielu tabel można połączyć w jednym obiekcie RecordSet za pomocą instrukcji SQL JOIN i UNION. Współdzielenie danych: Konieczne jest dokonanie konwersji typu danych na typ akceptowany przez systemodbiorcę, co obniża wydajność aplikacji. Skalowalność : Wynikiem walki o dostęp do źródła danych jest blokowanie dostępu do bazy danych oraz połączenia z bazą. Zapory ogniowe: Zapory mogą blokować wiele rodzajów zapytań. Technologia ADO.NET Obiekt DataSet, który może zawierać wiele tabel z wielu źródeł danych Umożliwia całkowicie niesekwencyjny dostęp do danych zapisanych w obiekcie DataSet za pomocą hierarchii kolekcji Do przechodzenia pomiędzy powiązanymi tabelami służą obiekty DataRelation. Korzysta się z XML, więc konwersje typów nie są konieczne. Nie występuje blokowanie dostępu do bazy danych ani długotrwałe aktywne połączenia, więc nie ma walki o dostęp do danych. Zapory są przezroczyste dla plików XML. Klasy ADO.NET są rozmieszczone w następnych przestrzeniach nazw: System.Data dostarcza podstawowych funkcji służących do dostępu do danych. Do tej przestrzeni nazw należą klasy ADO.NET: DataSet, DataTable, DataRow, DataView i inne. Przestrzeń nazw System.Data zawiera również zbiór SqlDbType, którego elementy reprezentują wbudowane typy danych SQL Server. System.Data.Common - zawiera klasy, których możliwości są wspólne dla wszystkich dostawców dostępu do danych.net. Najważniejszą klasą tej przestrzeni nazw jest abstrakcyjna klasa DataAdapter. Stanowy ona pomost pomiędzy obiektem DataSet a źródłem danych. Klasa ta jest dziedziczona przez inną klasę abstrakcyjną DbDataAdapter, która stanowi podstawę do implementacji klas adaptujących dla konkretnych dostawców (obecnie są to klasy OleDbAdapter i SqlDataAdapter). System.Data.OleDb najważniejszymi klasami tej przestrzeni są OleDbDataAdapter, OleDbCommand, OleDbDataReader i OleDbConnection. Te cztery klasy, we współpracy z klasą DataSet, udostępniają praktycznie wszystkie funkcje konieczne do współpracy ze źródłami danych opartymi na OLE DB. Do współpracy z SQL Server można zastosować OLE DB, ale dla lepszej wydajności są polecane stosowanie dostawcy SqlClient. System.Data.SqlClient - najważniejszymi klasami tej przestrzeni są SqlDataAdapter, SqlCommand, SqlDataReader i SqlConnection. Te klasy służą do współptacy z SQL Server. Podobnie jak odpowiednie klasy przestrzeni nazw System.Data.OleDb umożliwiają przeprowadzenie dowolnych operacji na bazach danych SQL Server. System.Data.SqlTypes zawiera struktury odpowiadające wbudowanym typom danych SQL Server. 53

54 DataSet Data Table Row Column Constraint DataRelation Dostawca ADO.NET DataAdapter DataReader Command Connection DataSource Rys.21 Schemat budowy ADO.NET jest pokazany na rys.21. Głównym magazynem danych w ASP.NET jest obiekt DataSet. DataSet zawiera pełny zestaw danych, łącznie z ograniczeniami (constraints), relacjami; może zawierać jednocześnie wiele tabel. DataSet to jest baza danych w odróżnieniu od obiektu RecordSet w technologii ASP. Obiekty DataReader (OleDbDataReader oraz SqlDataReader) implementują prostą, jednokierunkową metodę pobierania danych od bazy danych. Te obiekty przypominają kursory typu ForwardOnly w technologii ASP. Funkcjonowanie klas ADO.NET jest docelowo rozpatrywać w następnych grupach: 1. SqlConnection, SqlCommand, SqlDataReader 2. OleDbConnection, OleDbCommand, OleDbDataReader 3. SqlDataAdapter,OleDbDataAdapter,DataSet,DataTable,DataRelation,DataView Pierwsza grupa jest przeznaczona dla wykorzystania baz danych w MS SQL Server. Klasy SqlConnection oraz SqlCommand są podobne obiektom ADO Connection i Command, ale są przeznaczone dla komunikacji tylko z Microsoft SQL Server.. Klasa SqlDataReader jest podobna do kursora jednokierunkowego AdForvardOnly w ADO. Ta klasa także jest przeznaczona dla pracy tylko z Microsoft SQL Server. Dla połączenia z bazą oraz dla przesyłania danych klasy pierwszej grupy wykorzystają protokół TDS (Tabular Data Stream). To jest protokół niskopoziomowy opracowany przez firmę Microsoft dla własnych serwerów baz danych. Transmisja danych tu jest bardzo wydajna. Wszystkie inne bazy danych wykorzystają standard OLEDB lub ODBC. Klasy drugiej grupy realizują funkcji podobne klasom grupy pierwszej dla serwerów innych producentów, np. Sybase, Oracle, PostgreSql, MySql. Dla połączenia z baza danych te klasy potrzebują wykorzystania klas odpowiednich providerów OLEDB lub ODBC. Klasy trzeciej grupy mogą być wykorzystane dla stworzenia prezentacji całej bazy danych w pamięci RAM. Klasa DataSet może prezentować bazę danych w RAM. DataSet może 54

55 zawierać klasy DataTable którzy prezentują tabele w bazie danych. Klasy DataTable są stworzone i uzupełniane danymi za pomocą klasy SqlDataAdapter lub OleDbDataAdapter. Za dopomoga klasy DataRelation można ustalić różne relacji pomiędzy tabelami. Klasa DataView pozwoli sortować i filtrować dane w tabelach. Pierwsze dwie grupy wykorzystają stale połączenie z bazami danych. To znaczy, że obiekty klas DataReader tych grup mogą otrzymać tylko jeden rekord z bazy danych przy uruchomieniu metody Read() dopóty dopóki jest aktywne połączenie z bazą danych. Dla otrzymania innych rekordów trzeba stworzyć pętlę z tych odwołań Read(). Trzecia grupa pozwoli stworzyć kopię bazy danych bezpośrednio w pamięci RAM oraz odłączyć się od serwera bazy danych i pracować z baza w trybie autonomicznym. Aplikacja może pracować w tym przypadku z kopią bazy danych bez obciążenia głównego serwera bazy danych. Otwarcie połączenia z baza danych Przykład połączenia z baza danych Microsoft SQL Server jest pokazany w listingu SqlConnection.aspx. Listing SqlConnection.aspx. 1. <%@ Page CodeBehind="SqlConnection.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SqlConnection" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. myconnection = New SqlConnection( "server=localhost;database=pubs;uid=sa;pwd=" ) 7. myconnection.open() 8. %> 9. Connection Opened! W pierwszych liniach kodu są importowane przestrzeni nazw klas dla połączenia z serwerem SQL. W następnych liniach kodu został stworzony obiekt klasy SqlConnection. Dla inicjalizacji obiektu myconnection konstruktor klasy SqlConnection zawiera wiersz połączenia. W wierszu połaczenia są niezbędnie dani dla połaczenia z serwerem SQL: imię serwera, imię bazy danych, imię użytkownika(login), hasło. Przy wykorzystaniu klasy SqlConnection nie jest wyznaczony w wierszu połączenia parametr providera. Klasy w przestrzeni nazw System.Data.SqlClient nie wykorzystają providery OLEDB, ODBC. Wszystkie te klasy pracują z protokołem TDS. Wiersz połączenia oprócz tego nie może zawierać imię źródła danych w postaci DSN (data source name). DSN może być wykorzystany tylko razem z odpowiednimi klasami przestrzeni nazw System.Data.OleDb. Przykład otwarcia bazy danych Microsoft Access jest pokazany w listingu OleDbConnection.aspx. Listing. 1. <%@ Page CodeBehind="OleDbConnection.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.OleDbConnection" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.OleDb" %> 4. <% 5. Dim myconnection As OleDbConnection 6. myconnection = New OleDbConnection( "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA Source=c:\inetpub\iissamples\sdk\asp\database\authors.mdb" ) 7. myconnection.open() 55

56 8. %> 9. Connection Opened! Microsoft Access nie może wykorzystać protokół TDS dlatego w listingu OleDbConnection.aspx jest importowana przestrzeń System.Data.OleDb. Konstruktor klasy OleDbConnection zawiera wiersz połączenia do bazy danych authors.mdb. Wiersz połączenia zawiera parametr Provider. Ten parametr wyznacza imię providera dla dostępu do bazy danych Access. Dla otwarcia połączenia z bazą danych przez providery OLEDB oraz ODBC można wykorzystać DSN, np. : myconnection = New OleDbConnection( "DSN=myDSN" ) Dodawanie danych przy pomocy ADO.NET Dodawanie danych może być zrealizowane za dopomogą instrukcji SQL INSERT. Dla uruchomienia instrukcji SQL INSERT trzeba zrealizować następne kroki: 1. Stworzyć obiekt połączenia z bazą danych oraz otworzyć połączenie. 2. Stworzyć obiekt klasy SqlCommand lub OleDbCommand odpowiadający instrukcji INSERT. 3. Uruchomić instrukcję INSERT. Przykład dodawania danych do bazy danych MS SQL Server jest pokazany w listingu SQLINSERTcommand.aspx. Dodawanie realizuje się za dopomogą obiektu klasy SqlCommand, któremu jest przypisana instrukcja SQL Insert. Instrukcja INSERT zostanie uruchomiana za dopomogą metody ExecuteNonQuery(). Ta metoda wraca ilość rekordów które zostali wpisane do bazy danych. Listing SQLINSERTcommand.aspx. 1. <%@ Page CodeBehind="SQLINSERTcommand.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLINSERTcommand" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mycommand As SqlCommand 7. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=mydata" ) 8. myconnection.open() 9. mycommand = New SqlCommand( "Insert testtable ( col1 ) Values ( 'Hello' )", myconnection ) 10. mycommand.executenonquery() 11. myconnection.close() 12. %> 13. New Record Inserted! W listingu OleDbINSERTcommand.aspx jest przykład dodawania danych do bazy danych ACCESS. Listing OleDbINSERTcommand.aspx. 1. <%@ Page CodeBehind="OleDbINSERTcommand.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.OleDbINSERTcommand" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.OleDb" %> 4. <% 5. Dim myconnection As OleDbConnection 6. Dim mycommand As OleDbCommand 56

57 7. myconnection = New OleDbConnection( "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA Source=c:\inetpub\iissamples\sdk\asp\database\authors.mdb" ) 8. myconnection.open() 9. mycommand = New OleDbCommand( "Insert INTO Authors ( Author ) Values ( 'Simpson' )", myconnection ) 10. mycommand.executenonquery() 11. myconnection.close() 12. %> 13. New Record Inserted! Modyfikacja danych przy pomocy ADO.NET Modyfikacja danych może być zrealizowane za dopomogą instrukcji SQL UPDATE. Dla uruchomienia instrukcji SQL UPDATE trzeba zrealizować następne kroki: 1. Stworzyć obiekt połączenia z bazą danych oraz otworzyć połączenie. 2. Stworzyć obiekt klasy SqlCommand lub OleDbCommand odpowiadający instrukcji UPDATE. 3. Uruchomić instrukcję UPDATE. Przykład modyfikacji danych bazy danych MS SQL Server jest pokazany w listingu SQLUPDATEcommand.aspx. Modyfikacja realizuje się za dopomogą obiektu klasy SqlCommand, któremu jest przypisana instrukcja SQL UPDATE. Instrukcja Update zostanie uruchomiana za dopomogą metody ExecuteNonQuery(). Listing SQLUPDATEcommand.aspx. 1. <%@ Page CodeBehind="SQLUPDATEcommand.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLUPDATEcommand" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mycommand As SqlCommand 7. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=mydata" ) 8. myconnection.open() 9. mycommand = New SqlCommand( "UPDATE Authors SET LastName='Smith' WHERE LastName='Bennett'", myconnection ) 10. mycommand.executenonquery() 11. myconnection.close() 12. %> 13. Record Updated! Dla modyfikacji baz danych innego typu czym MS SQL Server trzeba wykorzystać klasy z przestrzeni nazw System.Data.OleDb. Przykład modyfikacji bazy danych Microsoft Access jest pokazany w listingu OleDbUPDATEcommand.aspx. Listing OleDbUPDATEcommand.aspx. 1. <%@ Page CodeBehind="OleDbUPDATEcommand.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.OleDbUPDATEcommand" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.OleDb" %> 4. <% 5. Dim myconnection As OleDbConnection 6. Dim mycommand As OleDbCommand 57

58 7. myconnection = New OleDbConnection 8. ( "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA 9. Source=c:\inetpub\iissamples\sdk\asp\database\authors.mdb" ) 10. myconnection.open() 11. mycommand = New OleDbCommand ( "UPDATE Authors SET Author='Bennett' 12. WHERE Author = 'Simpson'", myconnection ) 13. mycommand.executenonquery() 14. myconnection.close 15. %> 16. Record Updated! Usuwanie danych przy pomocy ADO.NET Usuwanie danych może być zrealizowane za dopomogą instrukcji SQL DELETE. Dla uruchomienia instrukcji SQL DELETE trzeba zrealizować następne kroki: 1. Stworzyć obiekt połączenia z bazą danych oraz otworzyć połączenie. 2. Stworzyć obiekt klasy SqlCommand lub OleDbCommand odpowiadający instrukcji DELETE. 3. Uruchomić instrukcję DELETE. Przykład usuwania danych bazy danych MS SQL Server jest pokazany w listingu SQLDELETEcommand.aspx. Usuwanie realizuje się za dopomogą obiektu klasy SqlCommand, któremu jest przypisana instrukcja SQL DELETE. Instrukcja DELETE zostanie uruchomiana za dopomogą metody ExecuteNonQuery(). Listing SQLDELETEcommand.aspx. 1. <%@ Page CodeBehind="SQLDELETEcommand.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLDELETEcommand" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mycommand As SqlCommand 7. myconnection = New SqlConnection ( "server=localhost;uid=sa;pwd=;database=mydata" ) 8. myconnection.open() 9. mycommand = New SqlCommand ( "DELETE testtable WHERE col1='fred'", myconnection ) 10. mycommand.executenonquery() 11. myconnection.close() 12. %> 13. Record Deleted! Dla usuwania rekordów baz danych innego typu czym MS SQL Server trzeba wykorzystać klasy z przestrzeni nazw System.Data.OleDb. Przykład usuwania rekordów z bazy danych Microsoft Access jest pokazany w listingu OleDbDELETEcommand.aspx. Listing OleDELETEcommand.aspx. 1. <%@ Page CodeBehind="OleDbDELETEcommand.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.OleDbDELETEcommand" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.OleDb" %> 4. <% 5. Dim myconnection As OleDbConnection 58

59 6. Dim mycommand As OleDbCommand 7. myconnection = New OleDbConnection( "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA Source=c:\inetpub\iissamples\sdk\asp\database\authors.mdb" ) 8. myconnection.open() 9. mycommand = New OleDbCommand( "DELETE FROM Authors WHERE Author = 'Simpson'", myconnection ) 10. mycommand.executenonquery() 11. myconnection.close() 12. %> 13. Record Deleted! Czytanie danych z bazy danych za pomocą ADO.NET oraz obiektów klasy DataReader Dla odczytania danych z bazy danych trzeba wykorzystać instrukcję SQL SELECT. Realizacja instrukcji SQL SELECT zawiera następne kroki: 1. Stworzyć obiekt połączenia z bazą danych oraz otworzyć połączenie. 2. Stworzyć obiekt klasy SqlCommand lub OleDbCommand odpowiadający instrukcji SELECT. 3. Uruchomić instrukcję, która tworzy obiekt DataReader. 4. Realizować pętlę dla odczytania zawartości obiektu DataReader. Obiekt DataReader to jest egzemplarz klasy SqlDataReader lub OleDbDataReader w zależności od typu bazy danych. Klasa DataReader to jest kursor jednokierunkowy bazy danych dla czytania naprzód (AddForwardOnly). DataReader może przekazać tylko jeden rekord bazy danych. Dla otrzymania następnego rekordu trzeba wykorzystać metodę Read() do póki nie będzie koniec rekordów. Przykład czytania danych jest pokazany w listingu SQLDataReader.aspx. Listing SQLDataReader.aspx. 1. <%@ Page CodeBehind="SQLDataReader.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLDataReader" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mycommand As SqlCommand 7. Dim mydatareader As SqlDataReader 8. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=secret;pwd=;database=pubs" ) 9. myconnection.open() 10. mycommand = New SqlCommand( "Select * from Authors", myconnection ) 11. mydatareader = mycommand.executereader() 12. While mydatareader.read() 13. Response.Write( mydatareader( "au_lname" )& "<br>") 14. 'Response.Write( "<br>" ) 15. End While 16. mydatareader.close() 17. myconnection.close() 18. %> 59

60 Wykorzystanie parametrów w instrukcjach SQL Dla przekazania poleceniom SQL konkretnych danych można wykorzystać kolekcje i klasy parametrów w instrukcjach SQL. Wartościom parametrów mogą być przypisane dane z formularzy lub z kodu programu. W listingu SQLParameters.aspx jest pokazany przykład wykorzystania parametrów z klasą SqlCommand. Listing SQLParameters.aspx. 1. <%@ Page CodeBehind="SQLParameters.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLParameters" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mycommand As SqlCommand 7. Dim FirstName As String = "Robert" 8. Dim LastName As String = "Johnson" 9. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=mydata" ) 10. myconnection.open() 11. mycommand = New SQLCommand( "Insert Authors ( FirstName, LastName ) )", myconnection ) 12. mycommand.parameters.add( New SqlParameter( "@FName", SqlDbType.Varchar, 30 )) 13. mycommand.parameters( "@FName" ).Value = FirstName 14. mycommand.parameters.add( New SqlParameter( "@LName", SqlDbType.Varchar, 30 )) 15. mycommand.parameters( "@LName" ).Value = LastName 16. mycommand.executenonquery() 17. myconnection.close() 18. %> 19. Record Inserted! W tym kodzie są stworzone dwa Te parametry wykorzystają się w instrukcji SQL INSERT dla rezerwowania konkretnych wartości zmiennych FirstName oraz LastName. Wykorzystanie zapamiętanych procedur. Zapamiętane procedury pozwalają wykorzystać ten samy kod SQL przez różne strony ASP.NET. Wykorzystanie procedur zwiększa wydajność serwera bazy danych. Listing SQLStoredProcedure.aspx zawiera przykład wykorzystania procedury do wpisania nowych rekordów do bazy danych. Listing SQLStoredProcedure.aspx. <%@ Page CodeBehind="SQLStoredProcedure.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLStoredProcedure" %> <%@ Import Namespace="System.Data" %> <%@ Import NameSpace="System.Data.SqlClient" %> <% Dim myconnection As SqlConnection Dim mycommand As SqlCommand Dim FirstName As String = "Robert" Dim LastName As String = "Johnson" myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=mydata" ) 60

61 myconnection.open() mycommand = New SqlCommand( "InsertAuthors", myconnection ) mycommand.commandtype = CommandType.StoredProcedure mycommand.parameters.add( New SqlParameter( "@FirstName", SqlDbType.Varchar, 30 )) mycommand.parameters( "@FirstName" ).Value = FirstName mycommand.parameters.add( New SqlParameter( "@LastName", SqlDbType.Varchar, 30 )) mycommand.parameters( "@LastName" ).Value = LastName mycommand.executenonquery() myconnection.close %> Record Inserted! Procedura została stworzona w bazie danych mydata w MS SQL Server za dopomogą następnego kodu: CREATE PROCEDURE InsertAuthors Varchar Varchar (50) ) AS Insert Authors (FirstName, LastName) Values W listingu SQLStoredProcedure.aspx procedura zawiera tylko parametry wejściowe. Procedury zapamiętane mogą mieć parametry wyjściowe oraz przypisywać tym parametrom odpowiednie wartości. Przykład procedury z parametrami wyjściowymi jest pokazany w następnym kodzie: CREATE PROCEDURE getlastname Varchar Varchar (50) Output ) AS From Authors Where FirstName is Null Return (0) Else Return (1) W listingu SQLInputOutput.aspx jest przykład kodu, który wykorzysta zapamiętaną procedurę. Listing SQLInputOutput.aspx. <%@ Page CodeBehind="SQLInputOutput.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLInputOutput" %> <%@ Import Namespace="System.Data" %> <%@ Import NameSpace="System.Data.SqlClient" %> <% Dim myconnection As SqlConnection Dim mycommand As SqlCommand 61

62 Dim myparam As SqlParameter myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=mydata" ) myconnection.open() mycommand = New SqlCommand( "getlastname", myconnection ) mycommand.commandtype = CommandType.StoredProcedure myparam = mycommand.parameters.add( New SqlParameter( "RETURN VALUE", SqlDbType.INT )) myparam.direction = ParameterDirection.ReturnValue myparam = mycommand.parameters.add( New SqlParameter( "@FName", SqlDbType.Varchar, 50 )) myparam.direction = ParameterDirection.Input myparam.value = "Robert" myparam = mycommand.parameters.add( New SqlParameter( "@LName", SqlDbType.Varchar, 50 )) myparam.direction = ParameterDirection.Output mycommand.executenonquery() If mycommand.parameters( "RETURN VALUE" ).Value Then Response.Write( "The last name is " & MyCommand.Parameters( "@LName" ).Value ) Else Response.Write( "No author found!" ) END If myconnection.close() %> Dostęp do danych przy wykorzystaniu obiektów klasy DataSet Przy wykorzystaniu obiektów klasy DataReader można otrzymać z bazy danych tylko jeden rekord w ciągu jednego polecenia. To oznaczy że każda metoda Read() powoduje odczytanie jednego rekordu z bazy danych. Dla odczytania całej bazy do pamięci RAM można wykorzystać obiekty klas trzeciej grupy ADO.NET. Główną klasą w tej grupie jest klasa DataSet. Klasa DataSet pozwoli otrzymać w RAM kopię całej bazy danych, dodać nowe tabele oraz ustalić związki pomiędzy tabelami. Klasa DataSet jest kontenerem dla klas DataTable oraz DataRelation. Klasa DataTable odpowiada tabeli w bazie danych. Klasa DataTable może być stworzona dla już istniejącej tabeli bazy lub dla tabeli nowej. Połączenie pomiędzy klasami DataTable można definiować przez klasę DateRelation, która odpowiada relacjom w bazie danych. Klasa DataView pozwoli filtrować oraz sortować rekordy klasy DataTable. Klasa DataView zawiera metody dla poszukiwania informacji wewnątrz klasy DataTable. Klasy SQLDataAdapter oraz OleDbDataAdapter mogą być wykorzystane dla stworzenia klasy DataTable z istniejącej tabeli bazy danych. W celu uzyskiwania dostępu do baz danych w trym przypadku można wyróżnić pięć etapów: 1. Utworzenie obiektu łączącego z bazą danych. 2. Otwarcie połączenia z baza danych. 3. Wypełnienie obiektu DataSet odpowiednimi danymi. 4. Skonfigurowanie obiektu DataView w celu wyświetlania danych. 5. Powiązanie kontrolki WWW (lub HTML) z obiektem DataView. 62

63 Przykład wykorzystania tych klas dla odwzorowania wszystkich rekordów tablicy jest pokazany w listingu SQLDataTable.aspx. Listing SQLDataTable.aspx. 1. <%@ Page CodeBehind="SQLDataTable.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLDataTable" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mydataadapter As SqlDataAdapter 7. Dim mydataset As DataSet 8. Dim myrow As DataRow 9. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=pubs" ) 10. mydataadapter = New SqlDataAdapter( "Select * From Authors", myconnection ) 11. mydataset = New DataSet() 12. mydataadapter.fill( mydataset, "Authors" ) 13. For each myrow in mydataset.tables( "Authors" ).Rows 14. Response.Write( myrow( "au_lname" )& "<br>" ) 15. Next 16. %> W liniach 2,3 są importowane przestrzeni nazw. W tym kodzie jest wykorzystana przestrzeń nazw System.Data.SqlClient, która zawiera tylko klasy dla połączenia z bazami danych MS SQL Server. W liniach 5-8 są deklarowane obiekty klas ADO.NET. W linii 9 został stworzony obiekt myconnection klasy Connection dla połączenia z bazą danych. W linii 10 jest stworzony obiekt mydataadapter klasy DataAdapter, który odwoła się do wcześnie stworzonego obiektu myconnection. W linii 11 jest stworzony obiekt mydataset klasy DataSet. W linii 12 metoda Fill() obiektu mydataadapter tworzy w obiekcie mydataset obiekt klasy DataTable, który odpowiada tabeli pt. "Authors" w bazie danych. Jednocześnie do stworzonej tabeli są pompowane dane z bazy danych. W listingu OleDbDataTable.aspx jest pokazany podobny kod do połączenia z bazą danych Access. W tym przypadku jest wykorzystana przestrzeń nazw System.Data.OleDb oraz odpowiedni provider bazy danych. Listing OleDbDataTable.aspx. <%@ Page CodeBehind="OleDbDataTable.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.OleDbDataTable" %> <%@ Import Namespace="System.Data" %> <%@ Import NameSpace="System.Data.OleDb" %> <% Dim myconnection As OleDbConnection Dim mydataadapter As OleDbDataAdapter Dim mydataset As DataSet Dim myrow As DataRow myconnection = New OleDbConnection( "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA Source=c:\inetpub\iissamples\sdk\asp\database\authors.mdb" ) mydataadapter = New OleDbDataAdapter( "Select * From Authors", myconnection ) mydataset = New DataSet() mydataadapter.fill( mydataset, "Authors" ) For each myrow in mydataset.tables( "Authors" ).Rows Response.Write( myrow( "Author" ) & "<br>") 63

64 Next %> Klasa DataTable zawiera właściwość Columns, która prezentuje kolekcję kolumn, oraz właściwość Rows, która prezentuje kolekcję wierszy. Do kolumn można odwołać się w dwa sposoby: 1. Przez nazwę kolumny w bazie danych 2. Przez indeks kolumny W listingu SQLShowTable.aspx jest pokazany przykład kodu, który odwzorowuje zawartość tabeli Authors bazy danych Pubs bez odwołania do nazw kolumn tabeli. Listing SQLShowTable.aspx. 1. <%@ Page CodeBehind="SQLShowTable.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLShowTable" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mydataadapter As SQLDataAdapter 7. Dim mydataset As DataSet 8. Dim mydatatable As DataTable 9. Dim RowCount As Integer 10. Dim ColCount As Integer 11. Dim i, k As Integer 12. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=pubs" ) 13. mydataadapter = New SQLDataAdapter( "Select * From Authors", myconnection ) 14. mydataset = New DataSet() 15. mydataadapter.fill( mydataset, "Authors" ) 16. RowCount = mydataset.tables( "Authors" ).Rows.Count 17. ColCount = mydataset.tables( "Authors" ).Columns.Count 18. Response.Write( "<table border=1>" ) 19. For i = 0 To RowCount Response.Write( "<tr>" ) 21. For k = 0 To ColCount Response.WRite( "<td>" ) 23. Response.Write( mydataset.tables( "Authors" ).Rows( i ).Item( k, DataRowVersion.Current ).tostring() ) 24. Response.Write( "</td>" ) 25. Next 26. Response.WRite( "</tr>" ) 27. Next 28. Response.Write( "</table>" ) 29. %> W linii 23 wartość kolumny k w wierszu i jest odczytana za dopomogą metody Item(). Do tej metody jest przekazana wartość DataRowVersion.Current która powoduje odczytanie aktualnej wartości kolumny k. Egzemplarze klasy DataTable mogą być stworzone w sposób programowy. Klasa DataTable może być kontenerem informacji tymczasowych, np. dla koszyka artykułów w sklepie internetowym. Przykład stworzenia obiektów klasy DataTable w sposób programowy jest pokazany w listingu builddatatable.aspx. Listing builddatatable.aspx. 64

65 1. Page CodeBehind="buildDataTable.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.buildDataTable" %> 2. Import Namespace="System.Data" %> 3. <% 4. Dim mydatatable as DataTable 5. Dim mycolumn as DataColumn 6. Dim myrow As DataRow 7. Dim i As Integer 8. Dim myrand As System.Random 9. Dim productid As Integer 10. ' Create a DataTable 11. mydatatable = new DataTable("ShoppingCart") 12. mydatatable.minimumcapacity = mydatatable.casesensitive = False 14. ' Add an AutoIncrement (Identity) Column 15. mycolumn = mydatatable.columns.add("id", System.Type.GetType("System.Int32") ) 16. mycolumn.autoincrement = TRUE 17. mycolumn.allowdbnull = false 18. ' Add an Integer Column 19. mycolumn = mydatatable.columns.add("userid", System.Type.GetType("System.Int32") ) 20. mycolumn.allowdbnull = false 21. ' Add an Integer Column 22. mycolumn = mydatatable.columns.add("productid", System.Type.GetType("System.Int32") ) 23. mycolumn.allowdbnull = false 24. ' Add a String Column 25. mycolumn = mydatatable.columns.add( "ProductName",System.Type.GetType("System.String") ) 26. mycolumn.allowdbnull = false 27. ' Add a Decimal Column 28. mycolumn = mydatatable.columns.add("productprice",system.type.gettype("system.decimal" ) ) 29. mycolumn.allowdbnull = false 30. ' Add Some Data 31. myrand = New Random 32. For i = 0 To productid = myrand.next( 5 ) 34. myrow = mydatatable.newrow() 35. myrow( "UserID" ) = myrand.next( 3 ) 36. myrow( "ProductID" ) = productid 37. myrow( "ProductName" ) = "Product " & productid.tostring() 38. myrow( "ProductPrice" ) = mydatatable.rows.add( myrow ) 40. Next 41. ' Display All the Rows 42. For each myrow in mydatatable.rows 65

66 43. Response.Write( "<hr>" ) 44. For each mycolumn in mydatatable.columns 45. Response.Write( myrow.item( mycolumn ).tostring() & " / " ) 46. Next 47. Next 48. %> W linii 11 jest stworzony obiekt "ShoppingCart" klasy DataTable. W linii 12 jest wyznaczona pojemność tego obiektu w 50 rekordów. W linii 13 jest ustalona wartość CaseSensitive, która pozwoli nie odróżniać małe oraz duże litery. W następnych liniach do klasy DataTable są dodane 5 kolumn. Kolumna pierwsza ma typ danych AutoIncrement. Następne 4 kolumny zawierają informację pro towary w koszyku klienta. Filtracja i sortowanie danych w klasie DataTable W ADO.NET obiekt DataSet jest odpowiedzialnym tylko za przechowywanie danych. Za prezentację danych jest odpowiedzialny obiekt DataView. Filtrować oraz sortować dane można za dopomogą następnych sposobów: Przez metodę Select() klasy DataTable Przy wykorzystaniu właściwości RowFilter oraz Sort klasy DataViev. Obiekt DataRow przedstawia wiersz danych zapisanych w obiekcie DataTable. Każdy obiekt DataRow zawiera właściwość RowState, która wskazuje stan bieżącego wiersza. Właściwość ta (DataRow.RowState) może mieć wartości: Detached, Unchanged, Added, Deleted oraz Modified. Opis tych konstant jest pokazany w tablice. Tabl. Właściwości atrybutu RowState Nazwa Wartość Opis stałej liczbowa Detached 1 Obiekt DataRow może być połączony tylko z jednym obiektem DataTable lub w ogóle nie być jeszcze połączonym z żadnym obiektem DataTable. W ostatnim przypadku status tego wiersza jest odłączony Detached. Unchanged 2 Ta wartość świadczy, że ten wiersz został wybrany ze źródła danych oraz nie został zmodyfikowany. Added 4 Ten Wiersz został dodany do DataTable. Przy uruchomianiu metody Update obiekt DataAdapter zrealizuje metodę InsertCommand. Deleted 8 Ten wierz został wybrany z bazy danych oraz potem został usunięty. Przy uruchomianiu metody Update obiekt DataAdapter zrealizuje metodę DeleteCommand. Modified 16 Ten wierz został wybrany z bazy danych oraz potem został zmodyfikowany. Przy uruchomianiu metody Update obiekt DataAdapter zrealizuje metodę UpdateCommand. Obiekt DataTable zawiera metodę Select() umożliwiającą filtrowanie i sortowanie danych zapisanych w danej tabeli. Metoda ta zwraca tablicę wierszy (obiektów DataRow). Wywołuje się ją w następujący sposób: NazwaTabeli.Select(wyrażenie filtru, porządek sortowania, DataRowViewState) Dla każdego parametru, który ma być pominięty, należy wpisać NOTHING. 66

67 Pierwszym parametrem metody Select() jest zawartość klauzuli WHERE z odpowiedniego polecenia SQL SELECT do bazy danych. Drugim parametrem może być porządek sortowania w słowie kluczowym SORT polecenia SQL SELECT. Trzeci parametr metody Select() ustali się wersję RowState. Obiekt DataTable zawiera trzy wersję każdego z wierszy: pierwotną (DataRowVersion.Original), aktualną(datarowversion.current) lub proponowaną (DataRowVersion.Proposed). Wersje te służą do określenia stanu wiersza (atrybut DataRow.RowState). Wersja pierwotna jest to stan wiersza po dodaniu po raz pierwszy do obiektu DataTable. To są takie same wartości jak w bazie danych. Wersja aktualna to wersja po wprowadzeniu zmian. Wersja proponowana może być wykorzystana w trybie edycji grupowej. W trybie edycji grupowej są wykorzystane metody BeginEdit oraz EndEdit lub CancelEdit klasy DataRow. Wszystkie zmiany muszą być zrealizowane w metodzie BeginEdit. Te zmiany są buforowane oraz składają wersję proponowaną. Zatwierdzenie grupowych zmian realizuje się wywołaniem metody EndEdit oraz rezygnacja ze wszystkich zmian przez metodę CancelEdit. Ten algorytm modyfikowania danych w DataSet jest pokazany na rys. niżej. Modyfikowanie wierszy w DATASET Żrodło danych DataSet Wersja pierwotna FillDataSet Wersja pierwotna DataRowsversion. Original modyfikowanie Lub Nowa Wersja pierwotna Aktualizacja Wersja aktualna DataRowsversion. Currentl Tryb edytowania wiersza Anuluj zmiany Potwierdż zmiany Wersja proponowana DataRowsversion. Proposed Rys

68 W listingu wydruk1001.asp.vb jest pokazany przykład odczytu z obiektu DataSet wszystkich aktualnych wierszy. Listing wydruk1001.asp.vb 1. Public Class wydruk Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. Dim objconn As New System.Data.OleDb.OleDbConnection _ 7. ("Provider=Microsoft.Jet.OLEDB.4.0;" & _ 8. "Data Source=C:\aspnet_bazy_test\banking.mdb") 9. Dim objcmd As New System.Data.OleDb.OleDbDataAdapter _ 10. ("select * from tblusers", objconn) 11. Dim ds As System.Data.DataSet = New DataSet 12. objcmd.fill(ds, "tblds") 13. Dim dtable As System.Data.DataTable = ds.tables("tblds") 14. Dim AktualneWiersze() As System.Data.DataRow = dtable.select(nothing, _ 15. Nothing, DataViewRowState.CurrentRows) 16. Dim I, J As Integer 17. Dim stroutput As String 18. For I = 0 To AktualneWiersze.Length For J = 0 To dtable.columns.count stroutput = stroutput & dtable.columns(j). _ 21. ColumnName & " = " & _ 22. AktualneWiersze(I)(J).ToString & "<br>" 23. Next 24. Next 25. Response.Write(strOutput) 26. End Sub 27. End Class W kodzie metody Page_Load deklaruje się obiekty OleDbConnection oraz OleDbDataAdapter (linie 6-10). Następne tworzony jest obiekt DataSet, który za pomocą metody Fill() jest wypełniany danymi(liniey 11-12). Dalej odczytywana jest jedyna tabela obiektu DataSet, która zapisuje się do zmiennej dtable (linia 13), aby ułatwić dostęp do danych. Metoda Select (linie 14-15) odczytuje wszystkie wiersze obiektu DataTable, które uległy zmianie (wierszy aktualne), i umieszcza je w tablicy. Do przechodzenia do kolejnych kolumn służy pętla For (linia 18); do przechodzenia do kolejnych kolumn danego wiersza służy kolejna pętla For (linia 19). Odczytywane są nazwy pól oraz ich zawartość, które po konwersji na typ string wyświetlane są za pomocą metody Response.Write (linia 25). Inny przykład wykorzystania metody Select() jest pokazany w listingu SQLSelectFilter.aspx. Listing SQLSelectFilter.aspx. 68

69 1. Page CodeBehind="SQLSelectFilter.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLSelectFilter" %> 2. Import Namespace="System.Data" %> 3. Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mydataadapter As SqlDataAdapter 7. Dim mydataset As DataSet 8. Dim mydatatable As DataTable 9. Dim myrow As DataRow 10. Dim selectrows() As DataRow 11. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=pubs" ) 12. mydataadapter = New SqlDataAdapter( "Select * From Titles", myconnection ) 13. mydataset = New DataSet() 14. mydataadapter.fill( mydataset, "Titles" ) 15. selectrows = mydataset.tables( "Titles" ).Select( "type='popular_comp'", "title DESC", DataViewRowState.CurrentRows ) 16. For each myrow in selectrows 17. Response.Write( myrow.item( "title" )& "<br>" ) 18. Next 19. %> Metoda Select() obiektu klasy DataTable jest wykorzystana w linii 15 kodu. Metoda select tworzy obiekt klasy DataRow, który zawiera kolekcję odfiltrowanych wierszy. Warunki filtracji są przekazane w parametrach metody Select(). W listingu SQLDataViewFilter.aspx jest pokazany przykład wykorzystania właściwości RowFilter oraz Sort klasy DataView. Listing SQLDataViewFilter.aspx. 1. <%@ Page CodeBehind="SQLDataViewFilter.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLDataViewFilter" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mydataadapter As SqlDataAdapter 7. Dim mydataset As DataSet 8. Dim mydatatable As DataTable 9. Dim mydataview As DataView 10. Dim myrow As DataRowView 11. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=pubs" ) 12. mydataadapter = New SqlDataAdapter( "Select * From Titles", myconnection ) 13. mydataset = New DataSet() 14. mydataadapter.fill( mydataset, "Titles" ) 15. mydataview = mydataset.tables( "Titles" ).DefaultView 16. mydataview.rowfilter = "type='popular_comp'" 17. mydataview.sort = "title DESC" 18. For each myrow in mydataview 19. Response.Write( myrow( "title" )&"<br>" ) 20. Next 69

70 21. %> Obiekt mydataview klasy DataView tworzy się w linii 15 za dopomogą wywołania właściwości DefaultView. W liniach 15 oraz 16 właściwościom obiektu mydataview są przypisane odpowiednie wartości dla filtracji oraz sortowania. Wykorzystanie klas DataRelation W obiekcie DataSet mogą być wiele obiektów DataTable. Wykorzystając obiekty DataRelation można ustalić relacji pomiędzy kolumnami DataTable. W listingu SQLDataRelation.aspx jest pokazany przykład stworzenia relacji pomiędzy dwoma tabelami. W tym kodzie są wyznaczone relacje pomiędzy tabelą główną oraz tabelą podrzędną. Każdemu rekordu tabeli głównej odpowiadają jeden lub wiele rekordów tabeli podrzędnej. Listing SQLDataRelation.aspx. 1. <%@ Page CodeBehind="SQLDataRelation.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLDataRelation" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mydataadapter As SqlDataAdapter 7. Dim mydataset As DataSet 8. Dim mydatatable As DataTable 9. Dim Publisher As DataRow 10. Dim Title As DataRow 11. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=pubs" ) 12. mydataset = New DataSet() 13. mydataadapter = New SQLDataAdapter( "Select * From Publishers", myconnection ) 14. mydataadapter.fill( mydataset, "Publishers" ) 15. mydataadapter.selectcommand = New SqlCommand( "Select * From Titles", myconnection ) 16. mydataadapter.fill( mydataset, "Titles" ) 17. mydataset.relations.add( "PubTitles", mydataset.tables( "Publishers" ).Columns( "pub_id" ), mydataset.tables( "Titles" ).Columns( "pub_id" ) ) 18. For Each Publisher in mydataset.tables( "Publishers" ).Rows 19. Response.Write( "<p>" & Publisher( "pub_name" ) & ":" ) 20. For Each Title In Publisher.GetChildRows( "PubTitles" ) 21. Response.Write("<li>" & Title( "title" ) ) 22. Next 23. Next 24. %> W liniach 5-10 są zadeklarowane zmienne dla obiektów. W linii 11 jest stworzony obiekt klasy SqlConnection. W linii 12 jest stworzony obiekt DataSet. W linii 13 jest stworzony obiekt klasy SqlDataAdapter, który zawiera polecenie select oraz odwołanie do obiektu SqlConnection. W linii 14 za dopomogą metody Fill() jest stworzony obiekt DataTable w obiekcie DataSet. W liniach 15,16 jest wykorzystany ten samy obiekt DataAdapter dla stworzenia nowego obiektu DataTable. W linii 17 są ustalone relacje pomiędzy tabelami w DataSet. W liniach są wywołane wszystkie rekordy tabeli podrzędnej dla każdego rekordu tabeli głównej. Dla wywołania rekordów tabeli podrzędnej jest wykorzystana metoda GetChildRows() klasy DataRow. Ta metoda ma jeden parametr imię tabeli podrzędnej. 70

71 Struktura klas obiektu DataAdapter Klasa DataAdapter zawiera kolekcję czterech egzemplarzy instrukcji - klas obiektów Command: SelectCommand, InsertCommand, UpdateCommand, DeleteCommand. Struktura kolekcji oraz relacje pomiędzy obiektami są pokazane na rys. Przy wykorzystaniu klasy SqlDataAdapter instrukcji są klasami SqlCommand. Przy wykorzystaniu OleDbDataAdapter instrukcji są klasami OleDbCommand. Za dopomogą tych instrukcji klasa DataAdapter może być wykorzystana do wpisywania, modyfikacji oraz usuwania danych w bazie danych. DataSet DataAdapter SelectCommand Update Insert Delete DataReader Command Command Command Command Connection DataBase Rys. 22 W listingu SqlDataAdapterUpdate.aspx jest pokazany przykład modyfikacji danych. Listing SqlDataAdapterUpdate.aspx. 1. <%@ Page CodeBehind="SQLDataAdapterUpdate.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="Adonetwyklad.SQLDataAdapterUpdate" %> 2. <%@ Import Namespace="System.Data" %> 3. <%@ Import NameSpace="System.Data.SqlClient" %> 4. <% 5. Dim myconnection As SqlConnection 6. Dim mydataadapter As SqlDataAdapter 7. Dim mybuilder As SqlCommandBuilder 8. Dim mydataset As DataSet 9. Dim mydatatable As DataTable 10. Dim Author As DataRow 11. ' Create the DataSet and DataAdapter 12. myconnection = New SqlConnection( "server=localhost;uid=sa;pwd=;database=pubs" ) 13. mydataset = New DataSet() 14. mydataadapter = New SqlDataAdapter( "Select * From Authors", myconnection ) 15. mydataadapter.fill( mydataset, "Authors" ) 16. ' Change value of first row 71

72 17. mydataset.tables( "Authors" ).Rows( 0 ).Item( "au_fname" ) = "Jane" 18. ' Update the Database Table 19. mybuilder = New SqlCommandBuilder( mydataadapter ) 20. mydataadapter.update( mydataset, "Authors" ) 21. ' Display the Records 22. For Each Author in mydataset.tables( "Authors" ).Rows 23. Response.Write( "<p>" & Author( "au_fname" ) & " " & Author( "au_lname" ) ) 24. Next 25. %> W linii 19 jest stworzony obiekt klasy SqlCommandBuilder. Konstruktoru obiektu SqlCommandBuilder jest przekazany obiekt DataAdapter. Obiekt SqlCommandBuilder tworzy automatyczne klasy command dla instrukcji Update, Insert, Delete. To oznaczy, że niema sensu w sposób jawny tworzyć klasy Command dla tych instrukcji. Wykorzystanie transakcji w ADO.NET Transakcja to jest grupa operacji z których wszystkie muszą być wykonane prawidłowo lub żadna z nich nie zostanie zrealizowana. Działanie transakcji polega na wymuszeniu wykonania wielu zmian w bazie danych w całości. Oznacza to, że albo zostaną dokonane wszystkie zmiany, albo nie zostanie wykonana żadna z nich. Jeśli na przykład w witrynie obsługującej sklep elektroniczny znajduje się procedura, która umożliwia użytkownikowi dodanie pewnej ilości produktów do koszyka zakupów, to równocześnie inna procedura powinna odjąć daną ilość produktów ze stanu. Obydwie operacji powinny być zgrupowane razem- trzeba uniknąć sytuacji, w której towar został umieszczony w koszyku i nie został zdjęty ze stanu magazynowego lub odwrotnie. ADO.NET dostarcza trzech metod, które działając wspólnie umożliwiają stosowanie transakcji. Pierwsza z nich jest metoda BeginTransaction() obiektu Connection. Jest ona stosowana do utworzenia instancji obiektu Transaction, na przykład: Dim trans As SqlTransaction = conn.begintransaction(). Kolejne dwie metody należą do obiektu Transaction. Przed ich zastosowaniem należy zastosować obiekt Command do określenia operacji należących do transakcji. Aby to zrobić, trzeba przypisać właściwości Transaction obiektu Command instancję stworzonego właśnie obiektu Transaction: cmd.transaction = trans. Po tym już można wykonać oparte na transakcjach operacje na tabelach bazy danych zdefiniowanych w obiekcie. Uruchomienie metody ExecuteNonQuery()obiektu Command spowoduje realizację polecenia SQL w trybie transakcyjnym. Metoda Commit() obiektu Transaction spowoduje zatwierdzenie wszystkich operacji wykonywanych przez obiekty Command, jeśli wszystkie zakończyły się sukcesem: trans.commit(). Z drugiej strony, jeśli wystąpił wyjątek (co oznacza, że któraś operacja nie powiodła się), metoda RollBack() obiektu Transaction cofnie wszystkie operacje wykonane przed wystąpieniem błędu: trans.rollback(). Przykład realizacji transakcji jest pokazany w listingu wydruk1204.aspx (strona prezentacji.aspx) oraz w listingu wydruk1204.aspx.vb (kod klasy pośredniej). Listing wydruk1204.aspx. 1. <%@ Page Language="vb" CodeBehind="wydruk1204.aspx.vb" AutoEventWireup="false" Inherits="Adonetwyklad.wydruk1204" %> 2. <HTML> 3. <body> 4. <form runat="server"> 72

73 5. <asp:label id="label1" runat="server" > 6. </asp:label> 7. </form> 8. </body> 9. </HTML> Listing wydruk1204.aspx.vb 1. Public Class wydruk Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. 'deklarujemy polaczenie' 7. Dim Conn As New System.Data.OleDb.OleDbConnection("Provider=" & _ 8. "Microsoft.Jet.OLEDB.4.0;" & _ 9. "Data Source=C:\aspnet_bazy_test\banking.mdb") 10. Dim objtrans As System.Data.OleDb.OleDbTransaction 11. Dim objcmd As System.Data.OleDb.OleDbCommand = New _ 12. System.Data.OleDb.OleDbCommand _ 13. ("DELETE FROM tblusers WHERE UserID=72", Conn) 14. Conn.Open() 15. objtrans = Conn.BeginTransaction() 16. objcmd.transaction = objtrans 17. Try 18. objcmd.executenonquery() 19. objcmd.commandtext = "INSERT INTO tblusers " & _ 20. "(FirstName, LastName, Address, City, State, " & _ 21. "Zip, Phone) VALUES " & _ 22. "('Jose', 'Santiago', '34 Lake Drive', " & _ 23. "'Yolktown', 'MA', '02515', ' ')" 24. objcmd.executenonquery() 25. objtrans.commit() 26. Label1.Text = "Obie operacje zostaly wykonane poprawnie." 27. Catch ex As System.Data.OleDb.OleDbException 28. objtrans.rollback() 29. Label1.Text = ex.message & "<p>" & _ 30. "Zadna operacja nie zostala wykonana." 31. Finally 32. objcmd.connection.close() 33. End Try 34. End Sub 35. End Class 73

74 Aktualizacja źródeł danych w DOTNET Po przeprowadzeniu niezbędnych operacji po modyfikacji danych na obiektach DataSet lub DataTable może wyniknąć konieczność w aktualizacji całej bazy danych. W procesie aktualizacji mogą być konflikty przy modyfikacji oddzielnych rekordów tabel bazy danych. Konflikty te są powodowane następnymi ewentualnymi przyczynami: dwa lub więcej użytkowników chcą jednocześnie modyfikować ten samy wiersz w tabeli bazy danych, użytkownik chce modyfikować wiersz, który został już usunięty przez innego użytkownika, użytkownik chce usunąć wiersz do którego inny użytkownik wprowadził odwołanie przez klucz obcy w innym rekordzie innej tabeli, dwa lub więcej użytkownicy chcą wpisać do tej samej tabeli nowe wierszy z tymi samymi kluczami pierwotnymi, oraz inne, skojarzone z koniecznością konkurencyjnego dostępu do informacyjnych resursów -bazy danych, tabel, wierszy tabel. Model obiektowy ADONET zawiera decyzji pozwalające uniknąć wymienione wyżej kolizji. Wszystkie konflikty w bazach danych trzeba rozwiązywać za dopomogą mechanizmów blokowania informacyjnych resursów. Blokowania pozwalają chronić integralność i poprawność danych w trybie równoległego dostępu przez wiele użytkowników. W ADO.NET są dwa typy blokad: blokowanie pesymistyczne (współbieżność pesymistyczna) oraz blokowanie optymistyczne(współbieżność optymistyczna). W celu zrozumienia treści tego blokowania rozpatrzymy istniejące mechanizmy ADO oraz ADONET przeznaczone są do realizacji uporządkowania dostępu do danych przez wiele użytkowników. Głównymi z podobnych mechanizmów są kursory. Kursor jest wskaźnikiem do określonego wiersza w zbiorze wynikowym. Innymi słowy, jest to narzędzie poruszania się w zbiorze wynikowym i pracy nad określonym wierszem wskazywanym przez wskaźnik kursora. Kursor nieco jest podobny tablice danych, ale on nie może w dowolny sposób sortować dani, bo odwzorowuje tylko dani wyznaczone w zapytaniu SQL do bazy danych na moment uruchamiania tego zapytania. W technologii ADO zbiór wynikowy jest skojarzony z obiektem klasy Recordset. Natomiast w ADONET zbiór wynikowy może być skojarzony z klasami DataReader lub DataTable. ADO ma rozbudowaną obsługę kursorów. Natomiast możliwości ADO.NET są dość ograniczone, co oznacza, że nie ma tam obsługi kursorów po stronie serwera. Wynika to z bezpołączeniowej architektury ADO.NET oraz jego niezależności od źródła danych. Klasa DataTable zawiera interfejs pozwalający indeksować zawartość klas DataRow, dlatego ADONET realizuje możliwość uzyskania dostępu do dowolnego wiersza bez przenoszenia kursora. Wystarczy zdefiniować rozpoczynający się od zera indeks żądanego wiersza i dane znajdujące się w nim są dostępne bez konieczności sekwencyjnego dostępu. W wielu źródłach dokumentacji DOTNET pojęcie Kursor jest omijane, ale, te pojęcie najbardziej odpowiada procesom współpracy aplikacji z bazami danych. Kursory dzielą się według ich cech: położenia i typu. Ze względu na położenie są dwie grupy kursorów: kursory strony klienta i kursory strony serwera. Kursory strony klienta ( lub kursory lokalne), są używane do poruszania się wewnątrz zbioru wynikowego położonego lokalne lub po stronie klienta. Oznacza to, że wszystkie wiersze wybrane kwerendą i kolejne muszą być przesłane do klienta. Zależnie od liczby wierszy może to być kosztowne w sensie obciążenia sieci i przestrzeni po stronie klienta. Przestrzeń może 74

75 oznaczać pamięć RAM lub dyskową. ADO.NET korzysta tylko się z kursorów strony klienta (poza klasą DataReader). Kursory strony serwera, są używane do poruszania się wewnątrz zbioru wynikowego zdalnie lub po stronie serwera. ADO.NET nie obsługuje kursorów po stronie serwera (wyjątkiem jest klasa DataReader), natomiast ADO popiera tę możliwość. Powodem może być fakt, że wiele źródeł danych różni się sposobem implementacji i trudno jest udostępnić kursory strony serwera w taki sposób, aby nie były widoczne komplikacji wynikające z obsługi różnych źródeł danych. Ze względu na typy kursorów można wymienić następne: kursory jednokierunkowe, przewiane tylko do przodu, kursory statyczne, kursory dynamiczne, kursory kluczowe. Kursory jednokierunkowe są najmniej kosztowne, pozwalają przesuwać się wewnątrz zbioru wynikowego tylko po jednym wiersz na raz. Żeby zrealizować powrót do początku kursora trzeba go zamknąć i otworzyć ponownie, aby przenieść wskaźnik do pierwszego wiersza. Domyślnie kursor przewiany tylko do przodu jest dynamiczny. Oznacza, że wiersz wskazywany przez kursor jest odczytywany ze źródła danych, dzięki czemu zostaną uwzględnione zmiany dokonane w tym samym wierszu już po wygenerowaniu zbioru wynikowego. Nie dzieje się tak jednak w przypadku klasy DataRead w ADO.NET. Zmiany w podległych wierszach otwartego obiektu DataReader nie są widoczne. Ten typ kursora jest jedynym używanym przez klasę DataReader ADO.NET. W ADO ten typ jest jednym z czterech typów kursorów używanych przez klasę Recordset. Kursory statyczne zawierają dani zbioru wynikowego w postaci statycznej, to oznaczy się że zawartość zbioru wynikowego nie zmieni się po jego otwarciu. Zmiany w zbiorze wynikowym, wprowadzone po jego otwarciu, nie są od razu widoczne, chociaż zmiany dokonane przez sam kursor statyczny mogą być odczytywane i odzwierciedlone w zbiorze wynikowym. W odróżnieniu od kursorów przewijanych tylko do przodu, kursor statyczny może przesuwać się zarówno do przodu, jak i do tyłu. W ADO.NET ten typ kursorów realizuje się w obiekcie DataSet. W ADO ten typ jest jednym z czterech typów kursorów używanych przez klasę Recordset. Kursory dynamiczne są bardzo dobre do obsługi współbieżności, ponieważ wykrywają wszystkie zmiany w zbiorze wynikowym dokonane po otwarciu kursora. Kursor dynamiczny może przesuwać się do przodu i do tyłu. Jest to najbardziej wymagający z opisanych typów kursorów i jego użycie może okazać się kosztowne, tam, gdzie można go zastąpić innym kursorem. W ADO.NET ten typ kursorów nie jest wykorzystany. W ADO ten typ jest jednym z czterech typów kursorów używanych przez klasę Recordset. Kursory kluczowe łączą funkcje unikatowe kursora statycznego i dynamicznego. Wykrywany są zmiany wartości w kolumnach danych. Dane wstawione przez kursor zostaną dołączone do zbioru wynikowego, ale dane wstawione przez inne kursory będą widoczne dopiero po zamknięciu i ponownym otwarciu kursora. W ADO.NET ten typ kursorów nie jest wykorzystany. W ADO ten typ jest jednym z czterech typów kursorów używanych przez klasę Recordset. Przystępując do uaktualnienia bazy danych przez kursory trzeba ustalić tryb blokowania bazy danych. W klasycznym ADO to jest właściwość LockType obiektu Recordset. Blokowanie jest konieczne, gdyż w tej samej chwili z bazy danych może korzystać większa ilość osób. Są cztery sposoby blokowania danych które mogą być zrealizowane w klasycznym ADO: 1. Tylko dla odczytu (właściwość Recordset adlockreadonly) rekordy są dostępne wyłącznie do odczytu i nie można ich modyfikować. Nie można także dodawać nowych rekordów. Jest to domyślny sposób blokowania. 75

76 2. Pesymistyczny (właściwość Recordset adlockpessimistic) rekordy są blokowane w momencie rozpoczynania edycji w kursorze. Ma to na celu uniknięcie sytuacji, w której wartości pól rekordu zmieniają się w trakcie jego edycji(czyli w czasie pomiędzy rozpoczęciem wpisywania wartości, a wywołaniem metody Update). 3. Optymistyczny (właściwość Recordset adlockoptimistic) rekordy są blokowane wyłącznie w czasie wykonywania metody Update. 4. Optymistyczny grupowy (właściwość Recordset adlockbatchoptimistic) rekordy nie są blokowane aż do momentu wykonywania aktualizacji grupowej. Ten sposób blokowania powinien być używany w przypadku korzystania z kursorów przechowywanych po stronie klienta i odłączonych zbiorów danych. Model obiektowy ADO.NET nie zawiera możliwości bezpośredniego tworzenia wymienionych czterech typów kursorów oraz wyznaczenia tych czterech sposobów blokowania. Ale blokowanie istnieje i w technologii DOTNET. Przystępując do aktualizowania źródła danych w celu wprowadzenia zmian z obiektów ADO.NET, DataSet i DataTable, trzeba znać aktualny stan źródła danych. Jest to ważne, ponieważ dane znajdujące się w obiekcie DataSet lub DataTable mogą być nieaktualnymi, czyli od momentu pobrania ich ze źródła danych mogły zostać zmienione przez innego użytkownika. To stanowi poważny problem w przypadku architektury bezpołączeniowej ADO.NET, ponieważ nie ma standardowego sposobu blokowania wierszy źródła danych na czas edycji obiektu DataSet. W klasycznym ADO można w zależności od źródła danych określić różne typy i poziomy blokowania, ponieważ ADO ma architekturę połączeniową. ADO.NET natomiast korzysta się funkcji blokowania optymistycznego po domyśleniu, oraz mogą być zrealizowane blokowania resursów informatycznych bazy danych przez blokowanie pesymistyczne. Blokowanie pesymistyczne. Blokowanie pesymistyczne (lub współbieżność pesymistyczna) jest typem blokowania obejmującego część tabeli w źródle danych podczas żądania danych. Ten sposób blokowania zapobiega wprowadzeniu zmian w źródle danych przez innych klientów w czasie trwania blokady. Blokada jest zazwyczaj zakładana podczas pobierania danych i zdejmowana po zakończeniu połączenia ze źródłem danych lub po zwolnieniu pobranych danych. Blokowanie pesymistyczne może być dobrym wyjściem w środowiskach o dużym natężeniu danych, co oznacza częste zmiany danych dokonywane przez dużą liczbę klientów. Jeśli jednak jeden klient blokuje dane dłużej, spowoduje to wystąpienie problemów u innych klientów, próbujących uzyskać dostęp i zaktualizować te same dane. W ADO.NET blokowanie pesymistyczne można osiągnąć za pomocą transakcji, zwłaszcza przy ustaleniu właściwości IsolationLevel. W listingu LockDataTransaction.aspx.vb jest pokazany przykład wykorzystania transakcji dla realizacji blokowania pesymistycznego. Listing LockDataTransaction.aspx.vb 1. Partial Class LockDataTransaction 2. Inherits System.Web.UI.Page 3. Const str_connection As String = "server=localhost;database=northwind;uid=sa;pwd=" 4. Const Str_Sql_User_Select As String = "select * from customers" 5. Dim cnnlocked, cnnunlocked As System.Data.SqlClient.SqlConnection 6. Dim dadlocked, dadunlocked As System.Data.SqlClient.SqlDataAdapter 7. Dim tranorthwind As System.Data.SqlClient.SqlTransaction 8. Dim cmdselectusers As System.Data.SqlClient.SqlCommand 9. Dim dstlocked As New System.Data.DataSet("Locked DataSet") 10. Dim dstunlocked As New System.Data.DataSet("UnLocked DataSet") 11. Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 12. 'Tworzymy instancje połączenia 76

77 13. Me.cnnLocked = New System.Data.SqlClient.SqlConnection(str_connection) 14. Me.cnnLocked.Open() 15. Me.cnnUnlocked = New System.Data.SqlClient.SqlConnection(str_connection) 16. Me.cnnUnlocked.Open() 17. 'Rozpoczynamy transakcje 18. Me.traNorthwind = Me.cnnLocked.BeginTransaction(System.Data.IsolationLevel.Serializable ) 19. 'Skonfigurujemy polecenie 20. Me.cmdselectUsers = New System.Data.SqlClient.SqlCommand(Str_Sql_User_Select, Me.cnnLocked, Me.traNorthwind) 21. 'tworzymy instancje adapterow 22. Me.dadLocked = New System.Data.SqlClient.SqlDataAdapter(Str_Sql_User_Select, Me.cnnLocked) 23. Me.dadLocked.SelectCommand = Me.cmdselectUsers 24. Me.dadUnlocked = New System.Data.SqlClient.SqlDataAdapter(Str_Sql_User_Select, Me.cnnUnlocked) 25. 'tworzymy instancje konstruktorow polecen 26. Dim cmbuser1 As New System.Data.SqlClient.SqlCommandBuilder(Me.dadLocked) 27. Dim cmbuser2 As New System.Data.SqlClient.SqlCommandBuilder(Me.dadUnlocked) 28. 'Wypelniamy zbiory danych 29. Me.dadLocked.Fill(Me.dstLocked, "Customers") 30. Me.dadUnlocked.Fill(Me.dstUnLocked, "Customers") 31. 'Aktualizujemy istniejący wiersz w blokowanym obiekcie DataSet 32. Me.dstLocked.Tables("Customers").Rows(1)("city") = "Koszalin" 33. 'Aktualizujemy istniejący wiersz w odblokowanym obiekcie DataSet 34. dstunlocked.tables("customers").rows(2)("city") = "Slupsk" 35. Try 36. Me.dadLocked.Update(Me.dstLocked, "customers") 37. 'Aktualizujemy odblokowane żrodlo danych 38. Me.dadUnlocked.Update(Me.dstUnLocked, "customers") 39. 'Wykonujemy transakcje 40. Me.traNorthwind.Commit() 41. Me.Label1.Text = "Wszystko OK!" 42. Catch obje As System.Data.SqlClient.SqlException 43. 'Cofamy transakcję 44. Me.traNorthwind.Rollback() 45. Me.Label1.Text = obje.message 46. Finally 47. 'Zamykamy 48. Me.cnnLocked.Close() 49. Me.cnnUnlocked.Close() 50. End Try 51. End Sub 52. End Class Strona LockDataTransaction.aspx zawiera kontrolkę Label dla wyświetlania komunikatu. Kod w listingu LockDataTransaction.aspx.vb deklaruje i wykorzystuje dwa obiekty SqlDataAdapter, dwa obiekty SqlConnection, dwa obiekty SqlCommandBuilder, jeden obiekt SqlCommand i jeden obiekt SqlTransaction. Kod strony realizuje połączenie do tego samego źródła danych w bazie danych Northwind oraz tabeli Customers, dwóch obiektów 77

78 DataSet: dstlocked oraz dstunlocked. Jeden z tych obiektów - dstlocked - realizuje zmiany w bazie danych przez mechanizm transakcji, drugi, dstunlocked - próbuje zrealizować aktualizację bez transakcji, przez zwykłą metodę Update obiektu DataAdapter. Transakcja tranorthwind została deklarowana w linii 7 oraz ustalona z właściwością IsolationLevel.Serializable w linii 18. Realizacja transakcji w środowisku ADO.NET zawiera następną kolejność czynności: 1. Otworzenie połączenia z bazą danych za dopomogą metody Open() obiektu Connection (linia 14). 2. Uruchomienie metody BeginnTransaction() obiektu Connection(Linia 18). Ta metoda tworzy obiekt transakcji. Parametrem wejściowym konstruktora transakcji może być poziom izolacji (linia 18).Wszystkie polecenia do baz danych przez obiekt transakcji będą zawierali konieczność fiksacji (Commit) lub odwołania (Rollback).Wszystkie zmiany w bazie danych bez wykorzystania transakcji są wprowadzone natychmiast. 3. Do właściwości Transaction obiektu klasy Command musi być dodany stworzony w kroku 2 obiekt Transaction oraz do właściwości Connection - obiekt Connection (linia 20). Parametrami wejściowymi konstruktora obiektu Command mogą być polecenie SQL, obiekt connection oraz obiekt Transaction. Ten samy element transakcji może być dodany do wszystkich obiektów klasy Command którzy będą zrealizowane w tej samej transakcji. 4. Stworzenie obiektu klasy CommandBuilder z wyznaczeniem obiektu klasy DataAdapter w konstruktorze klasy CommandBuilder(). Obiekt klasy CommandBuilder tworzy obiekty klas InsertCommand, DeleteCommand, UpdateCommand (linia 26). 5. Uruchomienie transakcji (linia 36), zatwierdzenie (linia 40) lub odwołanie (linia 44). Poziom izolacji Serializable jest sposobem blokowania Pesymistyczny. Ten sposób blokuje wszystkie rekordy w bazie danych zgodnie z poleceniem SQL : select * from customers. Żadne polecenie do bazy danych nie będzie zrealizowane dopóki transakcja nie będzie zatwierdzona (Commit) lub skasowana(rollback). Blokada Serializable założona na źródło danych spowoduje wystąpienie wyjątku przekroczenia czasu operacji po wywołaniu operacji Update() na obiekcie adaptera danych dadunlocked. To oznaczy, że wprowadzenie zmian z drugiego obiektu DataSet, dstunlocked nie zostanie zrealizowane w czasie trwania transakcji, oraz będzie sformowany komunikat: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated. Po tym komunikacie zostanie odwołana i sama transakcja, oraz żadna zmiana nie zostanie zrealizowana w bazie Northwind. Blokada ta nie zapobiegnie odczytowi danych przez innych klientów, nie dopuści jedynie do ich aktualizowania i usuwania. Blokowanie pesymistyczne jest sprzeczne z głównej filozofią ADO.NET, która polega w następnym: Podłączenie do bazy danych musi trwać tylko na period wywołania źródłowych danych oraz wprowadzenia zmian danych aktualizowanych. Wykorzystanie poziomów izolacji transakcji powoduje ograniczenie dostępu do danych na period obrabiania tych danych przez transakcje. Wykorzystanie transakcji blokuje połączenie z bazą i nie pozwoli wykorzystać pulę obiektów Connection. Realizacja blokowania pesymistycznego może przebiegać w sposób inny, bez wykorzystania transakcji. Wszystkie polecenia w bazach danych mogą być zrealizowane na poziomie baz danych, wykorzystując obiekt klasy. Dla uporządkowania dostępu do danych w bazie danych można stworzyć kursor bazy danych. Typy możliwych kursorów zostali już rozpatrzone. 78

79 Różne SZBD zawierają różne typy tych kursorów. Stworzyć kursor można na poziomie aplikacji przez instrukcję SQL, CREATE CURSOR w obiekcie DbCommand. Po stworzeniu kursora można wykorzystać instrukcji sterowania kursorem. Blokowanie optymistyczne Blokowanie optymistyczne (lub współbieżność optymistyczna) nie realizuje nakładanie jakikolwiek blokad bezpośrednio do źródła danych. Ten sposób blokowania pozwoli wyeliminować sytuację, kiedy te same dane mogą być zmodyfikowane w źródle danych przez dowolnego innego klienta z odpowiednimi uprawnieniami. Rozważmy przykład. Pobieramy dane ze źródła danych do obiektu DataSet. W czasie, gdy ich używamy, te same dane są zmodyfikowane w źródle danych przez innego użytkownika. Następne zwracamy do źródła zmodyfikowane dane i skutecznie nadpisujemy zmiany dokonane w czasie pomiędzy pobraniem a aktualizacją. W tej kolizji wygrywa ostatni klient. Blokowanie optymistyczne może wykorzystać możliwości chronienia różnych wersji danych w obiektach DataTable, zwłaszcza wrsji : Original, Current, oraz Proposed. Przy zmianie w źródle danych dowolnej wartości kolumny przez innego użytkownika, wartość tego pola w obiekcie DataTable wersji Original będzie już innej. To oznaczy, że warunkiem możliwości dokonania zmian w źródle danych musi być porównanie wartości pól wersji Original z wartością tego pola w samym źródle. To oznaczy, że dla realizacji polecenia SQL, UPDATE trzeba nie tylko wykorzystać klucz pierwotny w klauzuli WHERE, natomiast dodać wszystkie pierwotne wartości pól rekordu, który będzie aktualizowany. Kiedy to porównanie nie jest skuteczne, to w ADO.NET wynika zdarzenie DBConcurrencyException. Przykład demonstracji blokowania optymistycznego jest pokazany w listingu Concurrency.sapx.vb. Listing Concurrency.sapx.vb. 1. Partial Class Concurrency 2. Inherits System.Web.UI.Page 3. Const str_connection As String = "server=localhost;database=northwind;uid=sa;pwd=" 4. Const str_sql_user_select As String = "select * from customers" 5. Dim cnnuser1, cnnuser2 As System.Data.SqlClient.SqlConnection 6. Dim daduser1, daduser2 As System.Data.SqlClient.SqlDataAdapter 7. Dim dstuser1 As New DataSet("User1_DataSet") 8. Dim dstuser2 As New DataSet("User2_Dataset") 9. Dim cmbuser1 As System.Data.SqlClient.SqlCommandBuilder 10. Dim cmbuser2 As System.Data.SqlClient.SqlCommandBuilder 11. Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 12. 'Tworzymy instancje polaczen i otwieramy je 13. Me.cnnUser1 = New System.Data.SqlClient.SqlConnection(str_connection) 14. Me.cnnUser1.Open() 15. Me.cnnUser2 = New System.Data.SqlClient.SqlConnection(str_connection) 16. Me.cnnUser2.Open() 17. 'Tworzymy instancje i inicjalizujemy adaptery danych 18. daduser1 = New System.Data.SqlClient.SqlDataAdapter(str_sql_user_select, cnnuser1) 19. daduser2 = New System.Data.SqlClient.SqlDataAdapter(str_sql_user_select, cnnuser2) 20. cmbuser1 = New System.Data.SqlClient.SqlCommandBuilder(dadUser1) 21. cmbuser2 = New System.Data.SqlClient.SqlCommandBuilder(dadUser2) 79

80 22. daduser2.updatecommand = Me.cmbUser2.GetUpdateCommand 23. 'Wypelniamy zbiory danych 24. daduser1.fill(dstuser1, "customers") 25. daduser2.fill(dstuser2, "customers") 26. 'Aktualizujemy wiersz w pierwszym obiekcie DataSet 27. dstuser1.tables("customers").rows(0)("city") = "Warszawa" 28. 'Aktualizujemy żrodło danych z pierwszego obiektu DataSet 29. Me.dadUser1.Update(dstUser1, "Customers") 30. 'Aktualizujemy wiersz w drugiem obiekcie DataSet 31. dstuser2.tables("customers").rows(0)("address") = "Pilsudskiego 2" 32. Try 33. 'Aktualizujemy żrodło danych z drugiego obiektu DataSet 34. Me.dadUser2.Update(dstUser2, "Customers") 35. Catch obje As DBConcurrencyException 36. Me.Label1.Text = "komunikat zdarzenia DBConcurrencyException: " & obje.message 37. Me.Label2.Text = "Update Command: " & daduser2.updatecommand.commandtext 38. Finally 39. cnnuser1.close() 40. cnnuser2.close() 41. End Try 42. End Sub 43. End Class W listingu są definiowane (linie 18-19) dwa obiekty adaptera danych, które wypelniają dwa obiekty DataSet (linie 24-25). W obiektach DataSet wprowadzone zmiany w tym samym wierszu różnych kolumn tabeli Customers. Pierwsza zmiana przez adapter daduser1 zostanie wprowadzona do żrodła danych (linia 29). Druga zmiana powoduje zdarzenie DBConcurrencyException. Wadą tego sposobu blokowania jest niemożliwość sprawdzić pola danych typu BLOB, którzy mogą zawierać setki megabajtów. W tym przypadku mechanizm generowania poleceń SQL w obiekcie SqlCommandBuilder ignoruje te pole. Innym podejściem dla realizacji blokowania optymistycznego jest stworzenie w tabelach dodatkowych kolumn znaczników czasowych Timestamp. Wartość tej kolumny zmienia się przy każdej realizacji dowolnej operacji DML. W tym przypadku klauzula WHERE może zawierać dwa parametry : identyfikator rekordu oraz wartość kolumny TimeStamp z wersii ORIGINAL. Użycie XML Standard XML realizuje dostęp aplikacjom do danych na podstawie deskryptorów opisu tych danych w pliku. Przy tym nie są ważne kwestii fizycznego rozlokowania tych danych w pliku. Format XML może być wykorzystany na różnych platformach komputerowych, oraz jest przezroczystym dla zapór ogniowych i innych systemów bezpieczeństwa komputerów. Przestrzeń nazw System.Xml zawiera większą część klas.net dla pracy z językiem XML. Głównymi z tych klas są następne: XmlAttribute XmlNamedNodeMap XmlTextWriter XmlDocument XmlNodeList XmlValidatingReader XmlElement XmlNodeReader XPathDocument XmlNode XmlTextReader XslTransform 80

81 Czytanie danych XML Dla odczytania zawartości dokumentów XML może być wykorzystana klasa XmlTextReader. Ta klasa jest podobna klasie OleDbDataReader lub SqlDataReader w sensie realizacji jednokierunkowego odczytu informacji od początku do końca dokumentu. Przykład strony dla odczytania zawartości pliku XML jest pokazany w listingu XMLReader.aspx(VB). Listing XMLReader.aspx(VB). Witryna XML.(Chris Payne) 1. Imports System.Xml 2. Namespace XML 3. Partial Class XMLReader 4. Inherits System.Web.UI.Page 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. Dim reader As XmlTextReader 7. Try 8. reader = New XmlTextReader(Server.MapPath("books.xml")) 9. While reader.read() 10. Response.Write("<b>" & reader.name & "</b> " & _ 11. reader.value & "<br>") 12. End While 13. Catch ex As Exception 14. Response.Write("Blad dostepu do pliku XML!") 15. Finally 16. reader.close() End Try 17. End Sub 18. End Class 19. End Namespace Uruchomienie tego pliku wyświetla wszystkie znaczniki zapisane w pliku books.xml nie tylko znaczniki otwierające, lecz także zamykające. Ta informacja nie zawsze jest potrzebna. Aby wyeliminować zbyteczną informację trzeba wykorzystać właściwość NodeType klasy XmlTextReader. Przykład wykorzystania tej wlaściwości jest pokazany w listingu XMLReader2.aspx(VB).Listing XMLReader2.aspx(VB). Witryna XML. (Chris Payne) 1. Imports System.Xml 2. Namespace XML 3. Partial Class XMLReader2 4. Inherits System.Web.UI.Page 5. Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 6. Dim reader As XMLTextReader 7. Dim i As Integer 8. 'Dim curprice As Decimal 9. Try 10. reader = New XMLTextReader(Server.MapPath("books.xml")) 11. While reader.read() 12. Select Case reader.nodetype 13. Case XMLNodeType.Element 14. If reader.hasattributes Then 15. For i = 0 To reader.attributecount Response.Write(reader.GetAttribute(i) _ 17. & " ") 18. Next 19. Response.Write("<br>") 20. End If 21. Case XMLNodeType.Text 22. Response.Write(reader.Value & "<br>") 23. End Select 81

82 24. End While 25. Catch ex As Exception 26. Response.Write("Błąd dostępu do pliku XML!") 27. Finally 28. reader.close() 29. End Try 30. End Sub 31. End Class 32. End Namespace W wierszu 12 została wstawiona instrukcja select, która przed wyświetleniem jakichkolwiek informacji sprawdza typ aktualnie przetwarzanego węzła. Pierwszy blok CASE, w wierszu 13, jest wykonywany gdy właściwość NodeType ma wartość Element. Jeśli węzeł ma jakiekolwiek atrybuty(reader.hasattributes=true), są one kolejno pobierane oraz wyświetlane, a do określenia ich wartości używana jest metoda GetAttribute(). Jeśli węzeł jest zwyczajnym fragmentem tekstu oraz nie zawiera atrybutów, jest on wyświetlany w wierszu 22. Zapis danych XML Zapisywanie danych do pliku XML może być zrealizowane za dopomogą obiektów klasy XmlTextReader. Przykład wykorzystania tej klasy jest pokazany w listingu XMLWriter.aspx(VB).Listing XMLWriter.aspx(VB). Witryna XML. (Chris Payne). 1. Imports System.Xml 2. Namespace XML 3. Partial Class XMLWriter 4. Inherits System.Web.UI.Page 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. Dim writer As XMLTextWriter 7. Try 8. writer = New XMLTextWriter(Server.MapPath _ 9. ("books2.xml"), Nothing) 10. writer.writestartdocument() 11. writer.formatting = Formatting.Indented 12. writer.indentation = writer.writestartelement("bookstore") 14. writer.writestartelement("book") 15. writer.writeattributestring("genre", "history") 16. writer.writeattributestring("style", "hardcover") 17. writer.writeelementstring("title", "Połtawa 1709") 18. writer.writestartelement("author") 19. writer.writeelementstring("first-name", _ 20. "Władisław A.") 21. writer.writeelementstring("last-name", _ 22. "Serczyk") 23. writer.writeendelement() 24. writer.writeelementstring("price", _ 25. "19.99") 26. writer.writeendelement() 27. writer.writeendelement() 28. writer.flush() 29. Catch ex As Exception 30. Response.Write("Błąd dostępu do pliku XML!") 31. Finally 32. writer.close() 33. Response.Write("Zakończono generację pliku") 34. End Try 35. End Sub 82

83 36. End Class 37. End Namespace Obiekt Writer jest deklarowany w linii oraz stworzony w linii 8-9. Pierwszym argumentem przekazywanym w wywołaniu konstruktora jest nazwa tworzonego pliku XML, a drugim - sposób kodowania (domyśłnie kod UTF-8). W wierszu 10 zapisywany jest znacznik deklaracjixml : <?xml version="1.0"?>. W wierszach 11. i 12. definiowany jest sposób, w jaki ma być zapisywany generowany kod XML. Wiersz 11 definiuje stosowanie wcięcia, a wiersz 12 że pojedyncze wcięcie musi mieć 3 znaki odstępu. Generacja danych rozpoczyna się w wierszu 13. W tym wierszu jest zgenerowany znacznik otwierający <bookstore>. Natomiast w wierszu 28 jest wygenerowany znacznik zamykający </bookstore>. Walidacja plików XML Walidacja danych XML jest możliwa na podstawie schematu dokumentu(xdr-xml Data Reduced) lub definicją typu dokumentu (DTD Document Type Definition). Dla walidacji jest wykorzystywana klasa XmlValidatingReader. W walidacji uczestniczy klasa XmlTextReader, która realizuje szybki dostęp do danych dokumentu XML w kierunku od początku do końca bez keszowania tych danych. Jednak klasa XmlTextReader nie zawiera metod do walidacji, dlatego XmlValidatingReader działa wspólnie z klasą XmlTextReader. Przykład wykorzystania tych klas dla walidacji dokumentów XML jest pokazany w listingu XmlVaidate.aspx(VB). 1. Imports System.Xml 2. Imports System.Xml.Schema 3. Namespace XML 4. Partial Class XMLValidate 5. Inherits System.Web.UI.Page 6. Private reader As XMLTextReader 7. Private validator As XMLValidatingReader 8. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As 9. System.EventArgs) Handles MyBase.Load 10. Try 11. reader = New XmlTextReader(Server.MapPath("books2.xml")) 12. validator = New XMLValidatingReader(reader) 13. validator.validationtype = ValidationType.XDR 14. AddHandler validator.validationeventhandler, New _ 15. ValidationEventHandler(AddressOf ShowError) 16. While validator.read() 17. End While 18. Catch ex As Exception 19. Response.Write("Błąd dostępu do pliku XML!") 20. Finally 21. reader.close() 22. End Try 23. End Sub 24. Sub ShowError(ByVal obj As Object, ByVal e As ValidationEventArgs) 25. Response.Write("<font color=""red"">" & e.message & _ 26. "<br>") 27. If (reader.linenumber > 0) Then 28. Response.Write("Line: " & reader.linenumber & _ 29. " Position: " & reader.lineposition & _ 30. "</font><p>") 31. End If 32. End Sub 33. End Class 83

84 34. End Namespace Związki pomiędzy obiektami klas DataSet oraz Xml XML w środowisku DOTNET jest ściśle związany z ADO.Net. Dane wewnątrz obiektów DataSet są przechowywane w formacie XML. Oznacza to, że zawartość obiektów DataSet jest przechowywana w pamięci komputera jako dane XML, a nie reprezentowana w inny model danych. A zatem, na tych danych można wykorzystać klasy służące do obsługi XML. Klasa XmlDataDocument jest dla XML tym, czym DataSet jest dla ADO.NET. Obiekty obu tych klas są do siebie podobny i każdy z nich można skonwertować na drugi. Dzięki temu klasy te stanowią pomost pomiędzy ADO.NET oraz XML. Gdy obiekt XmlDataDocument zostanie ładowany środowisko DOTNET automatycznie tworzy obiekt DataSet, który można pobrać za pośrednictwem właściwości o tej samej nazwie. Kolumny tego obiektu oraz ich typy określane są na podstawie schematu XML. Jeśli żaden schemat nie zostanie podany, to środowisko DOTNET samodzielnie określi strukturę danych. Dzięki temu można modyfikować dane w dowolny sposób. Na przykład można otworzyć plik XML przy wykorzystaniu klas XML, a następnie przenieść je do obiektu DataSet i powiązać elementami kontrolek WWW. Można także pobrać informacje przechowywane w bazie danych przy użyciu DataSet i zapisać w formacie XML. Modyfikacje wprowadzane w obiektach XmlDataDocument mogą, lecz nie muszą powodować zmian w obiektach DataSet. Jeśli nowe dane odpowiadają polom obiektu DataSet, to zostanie do niego dodany nowy wiersz. Wzajemne związki pomiędzy obiektami klas XmlDataDocument oraz DataSet są pokazane na rys. Plik XML Baza Danych XmlTextreader DataAdapter XmlDataDocument DataSet Walidacja XML, Transformacja kodu XML,itp. Nnnnz Wiązanie danych Rys. Wzajemne związki pomiędzy obiektami klas XmlDataDocument oraz DataSet Przykład wykorzystania klas DataSet oraz XmlDataDocument jest pokazany w listingu XmlDataSet.aspx(VB). 1.Imports System.Xml 2.Namespace XML 3. Partial Class XMLDataset 4. Inherits System.Web.UI.Page 5. Private i, j As Integer 6. Private stroutput As String = "" 84

85 7. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 8. Dim xmldoc As New XMLDataDocument() 9. Try 10. xmldoc.dataset.readxml(server.mappath("books3.xml")) 'select data view and bind to server control 11. DataGrid1.DataSource = xmldoc.dataset 12. DataGrid1.DataMember = xmldoc.dataset.tables(0). _ 13. TableName 14. DataGrid2.DataSource = xmldoc.dataset 15. DataGrid2.DataMember = xmldoc.dataset.tables(1). _ 16. TableName 17. DataGrid1.DataBind() 18. DataGrid2.DataBind() 19. For i = 0 To xmldoc.dataset.tables.count stroutput += "TableName = """ & _ 21. xmldoc.dataset.tables(i).tablename & """<br>" 22. stroutput += " " & "Columns count " & _ 23. "= " & xmldoc.dataset.tables(i).columns.count. _ 24. ToString() & "<br>" 25. For j = 0 To xmldoc.dataset.tables(i).columns.count stroutput += " " & _ 27. "ColumnName = """ & xmldoc.dataset. _ 28. Tables(i).Columns(j).ColumnName & """, " & _ 29. "type = " & xmldoc.dataset.tables(i). _ 30 Columns(j).DataType.ToString() & "<br>" 31. Next 32. Next 33. stroutput += "<p>" 34. Catch ex As Exception 35. stroutput = "Error accessing XML file" 36. End Try 37. output.text = stroutput 38. End Sub 39. End Class 40. End Namespace W linii 8 został stworzony obiekt klasy XmlDataDocument. Ten obiekt nie wczytuje sam bezpośrednio dane. Dane są pobierane za pośrednictwem metody ReadXml właściwości DataSet (wiersz10). Ta metoda tworzy relacyjną reprezentację pobieranych informacji. W liniach oraz są wykorzystana włożona pętla for do pobierania nazw tabeli i kolumn oraz typy danych reprezentowane przez każdą kolumnę. W liniach jest pokazany sposób na wiązanie danych z kontrolkami DataGrid. Wykorzystanie obiektowego modelu dokumentu XML dla czytania danych Obiektowy model dokumentu XML (DOM) jest specyfikacją zawierającą klasy dla odwzorowania oraz dla manipulowania zawartością dokumentu w trybie nie strumieniowym. W tym trybie dokument XML jest skojarzony z klasami i kolekcjami klas zgodnie ze strukturą tego dokumentu. Z całym dokumentem jest skojarzona klasa XmlDocument. Ta klasa jest przeznaczona dla otwierania dokumentu. Podstawowe możliwości funkcjonalne opisane przez XML DOM udostępnia klasa XmlNode która jest klasą potomną XmlDocument. Klasa XmlNode reprezentuje pojedynczy element należący do drzewa dokumentu XML i może zostać wykorzystana do przejścia do węzłów podrzędnych oraz do węzła nadrzędnego, jak również do edycji i usuwania informacji. Z klasą XmlNode są skojarzone kolekcje obiektów klas XmlElement czy XmlAttribute. Przy wykorzystaniu klas 85

86 DOM Programista może mieć dostęp do wszystkich węzłów, elementów oraz atrybutów dokumentu, a nie tylko do oddzielnych znaczników w trybie strumieniowym przez klasy XmlTextReader lub XmlTextWriter. Model obiektowy DOM wykorzysta dla odczytania oraz zapisywania informacji do pliku XML klasy XMLTextReader oraz XmlTextWriter w sposób przezroczysty dla programisty. Współdziałanie tych klas jest pokazane na rys. W3C XML DOM XML Document XML Node XmlTextRead er XmlTextWrit er Dane XML Rys. Współdziałanie klas służących do obsługi danych XML. Przykład wykorzystania modelu DOM jest pokazany w listingu XMLDOMRead.aspx(VB) 1. Imports System.Xml 2. Namespace XML 3. Partial Class XMLDOMRead 4. Inherits System.Web.UI.Page 5. Private i As Integer 6. Private stroutput As String = "" Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 9. Dim xmldoc As New XmlDocument() Try 12. xmldoc.load(server.mappath("books.xml")) 13. ShowTree(xmldoc.DocumentElement) Catch ex As Exception 16. stroutput = "Błąd dostępu do pliku XML!" 17. End Try output.text = stroutput 20. End Sub 21. Sub ShowTree(ByVal node As XmlNode) 22. Dim attrnode As XmlNode 23. Dim map As XmlNamedNodeMap If Not (node.haschildnodes) Then 26. stroutput += " <b>" & _ 27. node.name & "</b> <" & _ 28. node.value & "><br>" & vbcrlf 29. Else 30. stroutput += "<b>" & node.name & "</b>" 31. If node.nodetype = XmlNodeType.Element Then 32. map = node.attributes 86

87 33. For Each attrnode In map 34. stroutput += " <b>" & _ 35. attrnode.name & "</b> <" & _ 36. attrnode.value & "> " & vbcrlf 37. Next 38. End If 39. stroutput += "<br>" 40. End If If node.haschildnodes Then 43. node = node.firstchild 44. While Not IsNothing(node) 45. ShowTree(node) 46. node = node.nextsibling 47. End While 48. End If 49. End Sub 50. End Class 51. End Namespace W wierszu 9 tworzony jest obiekt klasy XmlDocument. W wierszu 12 są do niego wczytywane informacje z pliku XML. Procedura ShowTree (linie 21-49) analizuje wszystkie węzły tego pliku i wyświetla informacje o nich. Procedura ShowTree wykorzysta rekursję w linii 45. Modyfikacja danych w obiektowym modelu dokumentów XML Obiekt XmlDocument udostępnia sporo metod służących do tworzenia i modyfikacji dokumentów XML. Przykład tworzenia nowego elementu w dokumencie XML jest pokazany w listingu XMLDOMWrite.aspx(VB). 1. Imports System.Xml 2. Namespace XML 3. Partial Class XMLDOMWrite 4. Inherits System.Web.UI.Page 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here 6. Dim xmldoc As New XMLDocument() 7. Dim stroutput As String = "" 8. Try 9. xmldoc.load(server.mappath("books3.xml")) 10. Dim elebook As XmlElement = _ 11. xmldoc.createelement("book") 12. Dim attstyle As XmlAttribute = _ 13. xmldoc.createattribute _ 14. ("style") elebook.setattributenode(attstyle) 17. elebook.setattribute("style", "hardback") Dim root As XmlElement = xmldoc.item("bookstore") 20. root.appendchild(elebook) xmldoc.save(server.mappath("books3.xml")) Catch ex As Exception 25. stroutput = "Błąd dostępu do danych XML!" 26. End Try output.text = "Poprawnie dopisano dane do plik XML" 29. End Sub 87

88 30. End Class 31. End Namespace W linii 6 został zadeklarowany obiekt klasy XMLDocument. W linii 9 stworzona zostala instancja tego obiektu na bazie pliku boks3.xml. W liniach jest stworzony nowy element ("book"). W liniach do zostal stworzony nowy atrybut ("style"). W linii 16 ten atrybut został dodany do elementu book. W linii 17 ustalona wartość ("hardback") nowego atrybutu. W liniach nowy element został dodany do dokumentu. W linii 22 dokument został zapisany do pliku. Wiązanie danych Wiązanie danych umożliwia kontrolowanie danych. Prawie każdy typ danych może być powiązany z dowolnym obiektem sterującym lub atrybutem tego obiektu. Daje to całkowitą kontrolę nad sposobem przekazywania danych z magazynu danych do strony i z powrotem. Dane można wiązać ze stroną ASP.NET w następne sposoby: 1. Użycie atrybutu DataSource danego obiektu sterującego 2. Za pomocą wyrażenia wiążącego dane. Pierwszy sposób jest wykorzystany w kontrolkach zawierające właściwość DataSource do której może być przypisany obiekt danych DataReader lub obiekt DataView klasy DataSet. Klasy tych kontrolek zawierają metodę DataBind(). Sposób drugi jest wykorzystany w kontrolkach nie zawierających właściwość DataSource. Składnia wyrażenia wiążącego dane w tym przypadku jest następująca: <%# atrybut lub kolekcja %> Chociaż składnia ta bardzo przypomina bloki wykonywania kodu tradycyjnej technologii ASP, tak nie jest. Bloki wykonywania kodu są zawsze przetwarzane w trakcie wykonywania kodu strony. Wyrażenia wiążące dane są przetwarzane tylko za pomocą metody DataBind(). Jeśli metoda będzie wywoływana na poziomie kodu strony, to wtedy przetworzone będą wszystkie wyrażenia wiążące dane, zawarte w kodzie. Metodę tę wywołuję się w procedurze zdarzenia Page_Load(). Metodę DataBind() można wywoływać również dla każdego z obiektów sterujących z osobna, co daje większą kontrolę nad sposobami korzystania z danych w konkretnej aplikacji. Konieczność wiązania danych do obiektów sterujących wynika w przypadkach komplikowanych operacji manipulowania danymi otrzymanymi z bazy danych w celu ich prezentacji, np. dla odwzorowania listy rozwianej w kontrolkach, realizacji skrolingu, sortowania oraz edytowania danych. Przykład wiązania danych pomiędzy kontrolką Label oraz kontrolką ListBox jest pokazany w listingu Wydruk0906.asp. Listing Wydruk0906.asp. 1. <script Language="VB" runat="server"> 2. sub Index_Changed(obj as Object, e as EventArgs) 3. DataBind() 4. end sub 5. </script> 6. <html><body> 7. <form runat="server"> 8. <asp:listbox runat="server" id="lbkolory" 9. width="150" 10. AutoPostBack=true 11. rows="3" 88

89 12. SelectionMode="Single" 13. OnSelectedIndexChanged="Index_Changed" > 14. <asp:listitem value=" 1">Red</asp:Listitem> 15. <asp:listitem value=" 2">Blue</asp:Listitem> 16. <asp:listitem value=" 3">Green</asp:Listitem> 17. <asp:listitem value=" 4">Yellow</asp:Listitem> 18. </asp:listbox><p> 19. <asp:label id="lblkomunikat" runat="server" 20. Text='<%# lbkolory.selecteditem.text %>' /> 21. </form> 22. </body></html> W liniach 8-18 została zdefiniowana kontrolka ListBox. W liniach są wyznaczone wartości pól ListItem tej kontrolki. Z kontrolką ListBox jest skojarzone zdarzenie Index_Changed które zdefiniowane jest w liniach 2-4. Realizacja tego zdarzenia powoduje uruchomienie metody DataBind () dla całej strony. Kontrolka Label jest zdefiniowana w liniach Kontrolka Label może wykorzystać tylko drugi sposób wiązania danych. Z polem Text tej kontrolki w linii 20 została powiązana wartość wybranego pola w kontrolce ListBox. Wyrażenie w linii 20 może być bezpośrednio wpisane w kodzie strony aspx lub wyznaczone w designerze VSNET. W ostatnim przypadku trzeba odtworzyć okno właściwości kontrolki Label, klikniejć pole DataBinding, wpisać wyrażenie do okna Custom binding expression. Bardzo ważnymi kontrolkami służącymi do przetwarzania struktur listowych (list controls) są obiekty sterujące: Repeater, DataList oraz DataGrid. Obiekty te automatycznie przechodzą kolejno do poszczególnych elementów kolekcji danych. Te obiekty działają jako kontener dla innych obiektów sterujących, które faktycznie wyświetlają dane ( np. kontrolka Label). Wymienione wyżej obiekty mają duże możliwości w stworzeniu interfejsu użytkownika. Kontrolka która prezentuje dani musi mieć właściwość DataSource. Do tej właściwości może być przypisany identyfikator obiektu klasy DataReader lub obiektu DataView. Ostateczne wiązanie danych pomiędzy kontrolką oraz źródłem danych odbędzie się po wywołaniu metody DataBind().Na rys. 23 są pokazane główne składnie procesu wiązania danych kontrolek serwerowych zawierających właściwość DataSource oraz metodę DataBind(). 89

90 Kontrolka serwerowa DataSource Żrodlo danych DataBind() Cache Controls Bufor strony Rys. 23 Wiązanie danych z kontrolką Repeater oraz obiektem DataReader Kontrolka Repeater jest jedną z podstawowych kontrolek służących do wyświetlania danych. W przeciwieństwa do kontrolek DataList i DataGrid nie zawiera żadnych stylów ani właściwości formatowania. Jeśli jest potrzeba formatować dane w tej kontrolce, to można użyć do tego celu znaczniki HTML. W ogóle kontrolka Repeater jest kontenerem, służącym do przetwarzania kolejnych pozycji listy danych. Sposób wyświetlania danych nie jest wcześniej zdefiniowany układ wyświetlania danych może być określony za pomocą szablonów (template controls). Dzięki temu interfejs można dostosować do konkretnej aplikacji. Szablony to są obiekty sterujące, umożliwiające stosowanie języka HTML oraz innych obiektów do sterowania wyświetlaniem danych w kontrolkach. W technologii.net są trzy kontrolki sterujące które pozwalają wykorzystać szablony: Repeater, DataList oraz DataGrid. W przypadku kontrolki Repeater, można stosować następujące szablony: ItemTemplate Szablon ten jest konieczny dla kontrolki Repeater. W wyniku działania tego szablonu każdy wiersz danych wyświetlany jest oddzielnie. AlternatingItemTemplate szablon taki sam jak ItemTemplate, ale przetwarzany jest oddzielie dla każdego wiersza danych. Umożliwia to określanie ustawień stylu dla poszczególnych wierszy. HeaderTemplate oraz FooterTemplate szablony te przetwarzają kod HTML bezpośrednio przed i po wyświetleniu wszystkich wierszy danych. 90

91 SeparatorTemplate szablony te przedstawiają elementy znajdujące się pomiędzy poszczególnymi wierszami danych. Zdarzenia kontrolki Repeater: Zdarzenie Opis ItemCommand Zdarzenie zgłaszane, gdy kliknięty zostanie przycisk znajdujący w kontrolce Repeater ItemCreated ItemdataBound Zdarzenie zgłaszane, gdy tworzony jest element kontrolki Repeater Zdarzenie zgłaszane, po przeprowadzeniu wiązania danych elementu kontrolki Repeater, ale przed wyświetleniem go na stronie Przykład wiązania danych z elementem Repeater jest pokazany w listingu SqlRepeaterSimple.aspx. Listing SqlRepeaterSimple.aspx. 1. <%@ Page CodeBehind="SqlRepeaterSimple.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlRepeaterSimple" %> 2. <HTML> 3. <HEAD> 4. <title>titles</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:repeater id="myrepeater" Runat="Server"> 9. <ItemTemplate> 10. <hr> 11. <%# Container.DataItem( "title" ) %> 12. <blockquote> 13. <%# Container.DataItem( "notes" ) %> 14. </blockquote> 15. </ItemTemplate> 16. </asp:repeater> 17. </form> 18. </body> 19. </HTML> W tym kodzie w liniach 8-16 jest deklarowana kontrolka Repeater. Wewnątrz deskryptora <asp:repeater > jest wyznaczony deskryptor <ItemTemplate>. Ten deskryptor wyznacza sposób prezentacji każdego rekordu w elemencie Repeater. Wyrażenia dla wiązania danych są wyznaczone w liniach 11 oraz 13. Wyrażenie Container.DataItem( "title" ) odwoła się bezpośrednio do obiektu Repeater oraz do elementu "title" tablicy. Klasa pośrednia dla tego pliku jest pokazana w listingu SqlRepeaterSimple.aspx.vb. Wiązanie danych jest wyznaczone w liniach 14, 15. Kod w linii 14 realizuje powiązanie obiektu SqlDataReader z kontrolką Repeater. Kod w linii 15 ląduje dane od DataReader do kontrolki Repeater. Listing SqlRepeaterSimple.aspx.vb. 1. Imports System.Data.SqlClient 2. Imports System.Data 3. Public Class SqlRepeaterSimple 4. Inherits System.Web.UI.Page 5. #Region " Web Form Designer Generated Code " 91

92 6. #End Region 7. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 8. 'Put user code to initialize the page here 9. Dim myconnection As SqlConnection 10. Dim mycommand As SqlCommand 11. myconnection = New SqlConnection("Server=Localhost;uid=sa;pwd=;Database=Pubs") 12. mycommand = New SqlCommand("Select title, notes From Titles", myconnection) 13. myconnection.open() 14. myrepeater.datasource = mycommand.executereader() 15. myrepeater.databind() 16. myconnection.close() 17. End Sub 18. End Class Przy odwzorowaniu danych może być sytuacja, kiedy pola w bazie danych mogą zawierać wartości NULL. W tych przypadkach można wykorzystać wiązanie z funkcją, która formuje na stronie rezultaty, kiedy ta wartość nie jet NULL. Przykład wiązania z funkcją jest pokazany w listingach SqlRepeaterFixNulls.aspx oraz SqlRepeaterFixNulls.aspx.vb. W listingu SqlRepeaterFixNulls.aspx w sekcji <body> </body> zostało zdefiniowane wiązanie z funkcją fixnulls. Funkcja fixnulls został zdefiniowana w listingu SqlRepeaterFixNulls.aspx. Listing SqlRepeaterFixNulls.aspx. 1. <%@ Page CodeBehind="SqlRepeaterFixNulls.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlRepeaterFixNulls" %> 2. <HTML> 3. <HEAD> 4. <title>titles</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:repeater id="myrepeater" Runat="Server"> 9. <HeaderTemplate> 10. <table border="1" cellspacing="0" cellpadding="5"> 11. </HeaderTemplate> 12. <ItemTemplate> 13. <tr> 14. <td><%# fixnulls( Container.DataItem 15. ( "title" ).ToString() ) %></td> 16. <td><%# fixnulls( Container.DataItem 17. ( "notes" ).ToString() ) %></td> 18. </tr> 19. </ItemTemplate> 20. <AlternatingItemTemplate> 21. <tr bgcolor="lightyellow"> 22. <td><%# fixnulls( Container.DataItem 23. ( "title" ).ToString() ) %></td> 24. <td><%# fixnulls( Container.DataItem 92

93 25. ( "notes" ).ToString() ) %></td> 26. </tr> 27. </AlternatingItemTemplate> 28. <FooterTemplate> 29. </table> 30. </FooterTemplate> 31. </asp:repeater> 32. </form> 33. </body> 34. </HTML> Listing SqlRepeaterFixNulls.aspx.vb 1. Imports System.Data.SqlClient 2. Imports System.Data 3. Public Class SqlRepeaterFixNulls 4. Inherits System.Web.UI.Page 5. Function fixnulls(byval thestring As String) As String 6. If thestring = "" Then fixnulls = "[NULL]" 7. Else fixnulls = thestring 8. End If 9. End Function 10. #Region 11. #End Region 12. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here 13. Dim myconnection As SqlConnection 14. Dim mycommand As SqlCommand 15. myconnection = New SqlConnection("Server=Localhost;uid=sa;pwd=;Database=Pubs") 16. mycommand = New SqlCommand("Select title, notes From Titles", myconnection) 17. myconnection.open() 18. myrepeater.datasource = mycommand.executereader() 19. myrepeater.databind() 20. myconnection.close() 21. End Sub 22. End Class Wykorzystanie kontrolki REPEATER oraz obiektu DataReader dla formowania listy wypunktowanej. Niżej jest pokazany przykład kodu dla wypunktowania rekordów na stronie internetowej. Każdy rekord bazy danych wypunktuje się w oddzielnym wierszu tabeli. Listng SqlrepeaterIndex.aspx 1. <%@ Page CodeBehind="SqlRepeaterIndex.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlRepeaterIndex" %> 2. <HTML> 3. <HEAD> 4. <title>titles</title> 5. </HEAD> 6. <body> 93

94 7. <form Runat="Server"> 8. <asp:repeater id="myrepeater" Runat="Server"> 9. <HeaderTemplate> 10. <table border="1" cellspacing="0" cellpadding="5"> 11. </HeaderTemplate> 12. <ItemTemplate> 13. <tr> 14. <td><%# Container.ItemIndex + 1 %></td> 15. <td><%# Container.DataItem( "title" ) %></td> 16. <td><%# Container.DataItem( "notes" ) %></td> 17. </tr> 18. </ItemTemplate> 19. <AlternatingItemTemplate> 20. <tr bgcolor="yellow"> 21. <td><%# Container.ItemIndex + 1 %></td> 22. <td><%# Container.DataItem( "title" ) %></td> 23. <td><%# Container.DataItem( "notes" ) %></td> 24. </tr> 25. </AlternatingItemTemplate> 26. <FooterTemplate> 27. </table> 28. </FooterTemplate> 29. </asp:repeater> 30. </form> 31. </body> 32. </HTML> Dla odwzorowania numeru pozycji rekordu jest wykorzystana właściwość ItemIndex każdego elementu klasy Repeater Item. W listingu SqlrepeaterIndex.aspx.vb jest pokazany kod klasy pośredniej. W liniach 12,13 zrealizowane zostało powiązanie kontrolki Repeater z obiektem DataReader. Listing SqlrepeaterIndex.aspx.vb 1. Public Class SqlRepeaterIndex 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. Dim myconnection As System.Data.SqlClient.SqlConnection 7. Dim mycommand As System.Data.SqlClient.SqlCommand 8. myconnection = New System.Data.SqlClient.SqlConnection _ 9. ("Server=Localhost;uid=sa;pwd=;Database=Pubs") 10. mycommand = New System.Data.SqlClient.SqlCommand("Select title, notes From Titles", myconnection) 11. myconnection.open() 12. myrepeater.datasource = mycommand.executereader() 13. myrepeater.databind() 14. myconnection.close() 15. End Sub 16. End Class 94

95 Wiązanie danych z kontrolką DropDownList Kontrolka DropDownList zawiera właściwość DataSource która musi być ustalona do wywołania metody DataBind(). Przykład wykorzystania tej kontrolki jest pokazany w listingu SqlDropDownList.aspx. Listing SqlDropDownList.aspx. 1. <%@ Page CodeBehind="SqlDropDownList.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDropDownList" %> 2. <HTML> 3. <HEAD> 4. <title>categories</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. Please select a category: 9. <br> 10. <asp:dropdownlist id="category" Runat="Server"> 11. </asp:dropdownlist> 12. <asp:button id="button1" Runat="server" Text="Select!"> 13. </asp:button> 14. <p>current Category: 15. <asp:label id="currentcat" Runat="Server"> 16. </asp:label> 17. </form> 18. </P> 19. </body> 20. </HTML> Kod klasy programowej jest pokazany w listingu SqlDropDownList.aspx.vb. Listing SqlDropDownList.aspx.vb. 1. Public Class SqlDropDownList 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. 'Put user code to initialize the page here 7. Dim myconnection As System.Data.SqlClient.SqlConnection 8. Dim mycommand As System.Data.SqlClient.SqlCommand 9. If Not IsPostBack Then 10. myconnection = New System.Data.SqlClient.SqlConnection ("Server Localhost; uid=sa; pwd=; Database = Northwind" ) 11. mycommand = New System.Data.SqlClient.SqlCommand ("Select CategoryName From Categories", myconnection) 12. myconnection.open() 13. category.datasource = mycommand.executereader() 14. category.datatextfield = "CategoryName" 15. category.databind() 16. myconnection.close() 17. End If 18. End Sub 95

96 19. Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click 20. currentcat.text = category.selecteditem.text 21. End Sub 22. End Class Wykorzystanie kontrolki DataList Kontrolka DataList jest bardzo podobna do kontrolki Repeater, ale umożliwia użytkownikom pracę interaktywną i modyfikowanie danych. Kontrolkę trzeba stosować razem z szablonami do wyświetlania poszczególnych pozycji w postaci listy, tak samo jak w przypadku Repeater. W przypadku DataList można stosować dodatkowo dwa szablony: SelectedItemTemplate szablon ten zawiera dodatkowe elementy, które pojawią wtedy, kiedy użytkownik wybierze któraś z pozycji wyświetlanych przez DataList. Typowym zastosowaniem może być zmiana stylu wyświetlania wiersza po jego wybraniu. EditItemTemplate Szablon ten określa sposób wyświetlania wybranej pozycji w trybie edytowania. Kontrolka DataList zawiera następne zdarzenia: OnItemCommand to zdarzenie może być inicjowane przez inny element sterujący (kontrolkę), który jest zawarty w szablonie ItemTemplate kontrolki DataList. Element sterujący musi być rozmieszczony w szablonie ItemTemplate oraz również musi mieć możliwość generacji zdarzeń. Zdarzenie powodowane tym elementem nie może być zdarzeniem OnEditCommand, OnUpdateCommand, OnDeleteComand, OnCancelCommand. OnEditCommand - to zdarzenie może być inicjowane przez inny element sterujący (kontrolkę), który jest zawarty w kontrolce DataList. Właściwość CommandName tego elementu musi mieć wartość Edit. OnUpdateCommand - to zdarzenie może być inicjowane przez inny element sterujący (kontrolkę), który jest zawarty w kontrolce DataList. Właściwość CommandName tego elementu musi mieć wartość Update. OnDeleteCommand - to zdarzenie może być inicjowane przez inny element sterujący (kontrolkę), który jest zawarty w kontrolce DataList. Właściwość CommandName tego elementu musi mieć wartość Delete. OnCancelCommand - to zdarzenie może być inicjowane przez inny element sterujący (kontrolkę), który jest zawarty w kontrolce DataList. Właściwość CommandName tego elementu musi mieć wartość Cancel. W listingu Wydruk0910.aspx są pokazane kody HTML strony z kontrolką DataList. Nie wolno zapominać o umieszczeniu obiektu DataList pomiędzy znacznikami <form>. W listingu Wydruk0910.aspx.vb jest pokazany kod klasy programowej. Listing Wydruk0910.aspx 1. <%@ Page Language="vb" Debug="true" CodeBehind="wydruk0910.aspx.vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.wydruk0910" %> 2. <HTML> 3. <body> 4. <form runat="server"> 5. <asp:datalist id="datalist1" runat="server" SelectedItemStyle- BackColor = "#cccc99" repeatlayout="table" repeatdirection="horizontal" 6. OnItemCommand="DataList1_ItemCommand" DataKeyField="UserID"> 7. <ItemTemplate> 8. <asp:linkbutton id="button1" runat="server" 96

97 9. Text='<%# Container.DataItem("FirstName") & " " & _ 10. Container.DataItem("LastName") %>' 11. CommandName="Select"/> 12. </asp:linkbutton> 13. </ItemTemplate> 14. <SelectedItemTemplate> 15. <%# Container.DataItem("FirstName") & " " & _ 16. Container.DataItem("LastName") %> 17. <br> 18. Telefon: 19. <%# Container.DataItem("Phone") %> 20. <br> 21. </SelectedItemTemplate> 22. </asp:datalist> 23. </form> 24. </body> 25. </HTML> W liniach 5-22 jest wyznaczona kontrolka DataList z identyfikatorem DataList1. W linii 5 jest wyznaczony tryb prezentacji repeatlayout="table" oraz sposób rozmieszczenia rekordów repeatdirection="horizontal". W linii 6 jest wyznaczony klucz sortowania rekordów DataKeyField="UserID" oraz wyznaczone zdarzenie OnItemCommand. Program dla tego zdarzenia ma nazwę DataList1_ItemCommand. Zdarzenie jest powodowane przez kontrolkę LinkButton, która jest rozmieszczona w szablonie ItemTemplate w liniach W tym szablonie są wyznaczone pola rekordów FirstName oraz LastName, które będą wyświetlane w normalnym trybie. W szablonie <SelectedItemTemplate> są wyznaczone pola rekordów, którzy będą wyświetlane po klikniejciu LinkButton. Listing Wydruk0910.aspx.vb 1. Imports System.Data.OleDb 2. Imports System.Data 3. Public Class wydruk Inherits System.Web.UI.Page 5. #Region " Web Form Designer Generated Code " 6. #End Region 7. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 8. Dim MojePolaczenie As New OleDbConnection _ 9. ("Provider=Microsoft.Jet.OLEDB.4.0;" & _ 10. "Data Source=C:\aspnet_bazy_test\banking.mdb") 'otwarcie polaczenia 11. Dim MojePolecenie As New OleDbDataAdapter _ 12. ("select * from tblusers", MojePolaczenie) 'wypelnienie obiektu DataSet 13. Dim ds As DataSet = New DataSet 14. MojePolecenie.Fill(ds, "tbl") 'wybor widoku danych i zwiazanie z obiektem sterujacym 15. DataList1.DataSource = ds.tables("tbl").defaultview 16. DataBind() 17. End Sub 18. Sub DataList1_ItemCommand(ByVal obj As Object, ByVal e As DataListCommandEventArgs) 19. DataList1.SelectedIndex = e.item.itemindex 20. DataList1.DataBind() 21. End Sub 97

98 22. End Class Edytowanie wyświetlanych pozycji w kontrolce DataList Kontrolka DataList umożliwia również edytowanie wyświetlanych pozycji. W Listingu SqlDataListEdit.aspx są pokazane definicje kontrolki DataList oraz szablonów. W Listingu SqlDataListEdit.aspx.vb są pokazany kody klasy programowej, którzy są wykorzystane dla realizacji niezbędnych zdarzeń w celu edycji wyświetlanych danych. W szablonie ItemTemplate dla kontrolki LinkButton w linii 16 jest wyznaczona właściwość CommandName = Edit. W tym przypadku przy klikniejciu dowolnego linku kontrolki ListButton będzie wywołane zdarzenie OnEditCommand. Z tym zdarzeniem jest skojarzona procedura editauthor (patrz linie 12 kodu SqlDataListEdit.aspx). Procedura editauthor (patrz linie kodu SqlDataListEdit.aspx.vb) przywłaszcza indeks wybranego autora właściwości EditItemIndex kontrolki DataList. Kolejne wywołanie kontrolki DataList na ekran monitora powoduje wykorzystanie dla tego rekordu już szablonu EditItemTemplate, a nie zwyczajnego szablony ItemTemplate. Szablon EditItemTemplate zawiera 3 kontrolki TextBox dla nazwiska, imię oraz telefonu autora. Ten szablon zawiera oraz 3 przyciski: Upddate, Delete, Cancel. Kiedy użytkownik naciśnie Update będzie wywołane zdarzenie OnUpdateCommand oraz procedurę updateauthor (patrz linie kodu SqlDataListEdit.aspx.vb). Procedura updateauthor modyfikuje informację pro autora w bazie danych. W tym celu jest wykorzystany objekt mycommand klasy SQLCommand (linia 57). Dla obiektu mycommand są @phone w liniach Wartość, która została wpisana przez użytkownika do kontrolki TextBox, z identyfikatorem Lastname zostanie przepisana do w sposób następny: mycommand.parameters("@lastname").value = CType(e.Item.FindControl("lastname"), TextBox).Text Metoda systemowa Ctype() jest wykorzystana, żeby powiązać obiekt e z obiektem typu TextBox. Kompilator.NET nie może zrealizować pożnie wiązanie obiektów i danych, dlatego on musi wiedzieć, że obiekt, który powodował zdarzenie jest obiektem typu TextBox i zawiera właściwość Text. Obiekt, który powodował zdarzenie jest wyznaczony za dopomogą metody FindControl(). Listing SqlDataListEdit.aspx. 2. <%@ Page CodeBehind="SqlDataListEdit.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataListEdit" %> 3. <HTML> 4. <HEAD> 5. <title>edit Authors</title> 6. </HEAD> 7. <body> 8. <form Runat="Server"> 9. <asp:datalist id="mydatalist" cellpadding="10" cellspacing="0" 10. gridlines="both" RepeatColumns="3" RepeatDirection="Horizontal" 11. DataKeyField="au_id" 12. OnEditCommand="editAuthor" OnDeleteCommand="deleteAuthor" OnUpdateCommand="updateAuthor" 13. OnCancelCommand="cancelEdit" 14. Runat="Server"> 15. <ItemTemplate> 16. <asp:linkbutton Text="Edit" CommandName="edit" Runat="Server" /> 17. <%# Container.DataItem( "au_lname" )%> 98

99 18. </ItemTemplate> 19. <EditItemTemplate> 20. <b>last Name:</b> 21. <br> 22. <asp:textbox id="lastname" 23. text='<%# Container.DataItem( "au_lname" ) %>' 24. Runat="Server"/> 25. <p> 26. <b>first Name:</b> 27. <br> 28. <asp:textbox id="firstname" 29. text='<%# Container.DataItem( "au_fname" ) %>' 30. Runat="Server"/> 31. <p> 32. <b>phone:</b> 33. <br> 34. <asp:textbox id="phone" 35. text='<%# Container.DataItem( "phone" ) %>' Runat="Server"/> 36. <p> 37. <asp:button Text="Update" CommandName="update" 38. Runat="Server" /> 39. <asp:button Text="Delete" CommandName="delete" 40. Runat="Server" /> 41. <asp:button Text="Cancel" CommandName="cancel" 42. Runat="Server" /> 43. </EditItemTemplate> 44. </asp:datalist> 45. </form> 46. </body> 47. </HTML> Listing SqlDataListEdit.aspx.vb. 1. Imports System.Data 2. Imports System.Data.SqlClient 3. Public Class SqlDataListEdit Inherits System.Web.UI.Page 4. #Region " Web Form Designer Generated Code " 5. #End Region 6. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here 7. If Not IsPostBack Then 8. BindData() 9. End If 10. End Sub 11. Sub BindData() 12. Dim myconnection As SqlConnection 13. Dim mycommand As SQLCommand 14. myconnection = New SqlConnection("Server=Localhost;uid=sa;pwd=;Database=Pubs") 15. mycommand = New SqlCommand("Select au_id, au_lname, au_fname, phone from Authors order by au_lname", myconnection) 16. myconnection.open() 17. mydatalist.datasource = mycommand.executereader() 18. mydatalist.databind() 19. myconnection.close() 99

100 20. End Sub 21. Sub editauthor(byval s As Object, ByVal e As DataListCommandEventArgs) 22. mydatalist.edititemindex = e.item.itemindex 23. BindData() 24. End Sub 25. Sub canceledit(byval s As Object, ByVal e As DataListCommandEventArgs) 26. mydatalist.edititemindex = BindData() 28. End Sub 29. Sub deleteauthor(byval s As Object, ByVal e As DataListCommandEventArgs) 30. Dim myconnection As SqlConnection 31. Dim mycommand As SqlCommand 32. Dim sqlstring As String 33. myconnection = New 34. SqlConnection("Server=Localhost;uid=sa;pwd=;Database=Pubs") 35. sqlstring = "Delete Authors Where au_id=@authorid" 36. mycommand = New SqlCommand(sqlString, myconnection) 37. mycommand.parameters.add(new SQLParameter("@authorID", 38. SqlDbType.VarChar, 11)) 39. mycommand.parameters("@authorid").value = 40. mydatalist.datakeys.item(e.item.itemindex) 41. myconnection.open() 42. mycommand.executenonquery() 43. mydatalist.databind() 44. myconnection.close() 45. mydatalist.edititemindex = BindData() 47. End Sub 48. Sub updateauthor(byval s As Object, ByVal e As DataListCommandEventArgs) 49. Dim myconnection As SQLConnection 50. Dim mycommand As SQLCommand 51. Dim sqlstring As String 52. myconnection = New 53. SqlConnection("Server=Localhost;uid=sa;pwd=;Database=Pubs") 54. sqlstring = "Update Authors Set au_lname=@lastname, 55. au_fname=@firstname, phone=@phone" _ 56. & " Where au_id=@authorid" 57. mycommand = New SQLCommand(sqlString, myconnection) 58. mycommand.parameters.add(new SQLParameter("@lastname", 59. SqlDbType.VarChar, 40)) 60. mycommand.parameters("@lastname").value = 61. CType(e.Item.FindControl("lastname"), TextBox).Text 62. mycommand.parameters.add(new SQLParameter("@firstname", 63. SqlDbType.VarChar, 20)) 64. mycommand.parameters("@firstname").value = 65. CType(e.Item.FindControl("firstname"), TextBox).Text 66. mycommand.parameters.add(new SQLParameter("@phone", 67. SqlDbType.Char, 12)) 68. mycommand.parameters("@phone").value = 69. CType(e.Item.FindControl("phone"), TextBox).Text 70. mycommand.parameters.add(new SQLParameter("@authorID", 71. SqlDbType.VarChar, 11)) 72. mycommand.parameters("@authorid").value = 100

101 73. mydatalist.datakeys.item(e.item.itemindex) 74. myconnection.open() 75. mycommand.executenonquery() 76. mydatalist.databind() 77. myconnection.close() 78. mydatalist.edititemindex = BindData() 80. End Sub End Class Przykład stworzenia aplikacji z kontrolką DataList w środowisku MS Visual Studio. W tym przykładzie będą wykorzystane narzędzie MS Visual Studio dla stworzenia strony internetowej. Projektant nie musi wpisywać samodzielnie wszystkie potrzebne linii kodu. Strona musi odwołać się do bazy danych MS SQL Server 2000 oraz wyświetlić z bazy danych Pub, tabeli Authors nazwiska autorów. Po klikniejciu dowolnego autora w tym mieście musi być wyświetlona dodatkowa informacja z bazy danych (np. telefon autora). Stworzenie aplikacji w Visual Studio zawiera następne 26 kroków: 1. Przenieść kontrolkę DataList do panelu projektu strony Rys. 24 Rys Przenieść kontrolkę SqlDataAdapter do panelu projektu. Będzie wyświetlane okno Rys. 25, które jest przeznaczone dla konfigurowania kontrolki i stworzenia innych kontrolek. Kliknij Next. 101

102 Rys Wizard konfigurowania proponuje w oknie rys.26 wyznaczyć sposób połączenia z bazą danych. Można wyznaczyć już istniejące połączenie. Wybierz New Connection. Rys

103 4. W następnym oknie rys.27 ustal parametry łącza z bazą danych. Rys Kliknij Testuj Połączenie, a potem OK (rys.28). Rys

104 6.Kliknij Next (Rys.29) Rys Ustal dostęp do bazy danych za dopomogą polecenia SQL (Rys.30). Rys

105 8. Kiedy nie chcesz (lub nie możesz!) samodzielnie wpisywać kod SQL uruchom Query Builder (rys.31). Wybierz niezbędne tabeli do konstruowania polecenia SQL i zamknij okno Add Table. Rys W oknie Query Builder (Rys.32)wyznacz niezbędne pola dla polecenia SQL. Kliknij Ok. 105

106 10. Kliknij Next. Rys

107 11. Kliknij Finish (rys.34) Rys.33 Rys Dla stworzenia obiektu DataSet odtwórz okno Propeties obiektu SqlDataAdapter (rys.35). Kliknij link Generacja DataSet 107

108 Rys Popatrz właściwości nowego obiektu DataSet (rys.36). Została stworzona klasa DataSet2 w projekcie aplikacji. Na stronie implementacja tej klasy ma imię DataSet21. To nie jest koniecznie, można ustalić dowolne imię dla obiektu DataSet. 108

109 Rys Dla obiektu DataList uruchom Properties-> Property Builder (rys.37). Ustal właściwości Data key field, Direction, Layout, DataSource. Rys

110 16. Ustal przez menu kontekstowe tryb edycji Item Template (Rys 38). Rys Przenieś kontrolkę LinkButton w pole Item Template (Rys.39) Rys Uruchom okno właściwości kontrolki LinkButton oraz kliknij przycisk... w polu DataBinds (rys. 40) 110

111 Rys W oknie DataBindings (Rys.41) ustal Bindable Properties = Text, oraz Custom binding expression. W oknie Custom binding expression wpisz kod: DataBinder.Eval(Container, "DataItem.au_id", "{0}") +" "+ DataBinder.Eval(Container,"DataItem.au_lname","{0}") Kliknij OK. Rys

112 20. Przejdź do edycji pola SelectedItemTemplate (rys.42). W sposób analogiczny ustal kontrolkę LinkButton w pole SelectedItemTemplate. Rys Uruchom okno Label1 DataBindings (Rys.43). W pole Custom binding expression wpisz kod: DataBinder.Eval(Container, "DataItem.au_id", "{0}")+" " +DataBinder.Eval(Container, "DataItem.au_lname", "{0}")+" " +"<br>phone:"+databinder.eval(container, "DataItem.phone", "{0}")+"<br>" Kliknji Ok. Rys Wpisz dwie linie kodu do procedury Page_Load: 112

113 Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here Me.SqlDataAdapter1.Fill(Me.DataSet31) Me.DataList1.DataBind() End Sub 26. Wpisz dwie linie kodu do procedury DataList1_ItemCommand1: Private Sub DataList1_ItemCommand1(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) Handles DataList1.ItemCommand DataList1.SelectedIndex = e.item.itemindex DataList1.DataBind() End Sub Wykorzystanie kontrolki DataGrid. Kontrolka DataGrid ma podobne zastosowanie, jak kontrolki DataList i Repeater, ale ma jeszcze więcej funkcji. DataGid może być używany w trybach prezentacji danych kontrolki Repeater lub edycji danych kontrolki DataList. DataGrid zawiera dodatkowe możliwości które są nieobecne w kontrolkach DataList oraz Repeater. DataGrid pozwoli zrealizować sortowanie i stronicowanie prezentowanych danych. Za pomocą DataGrid dane wyświetlane są w postaci siatki. Domyślne kontrolka DataGrid tworzy kolumnę dla każdego pola z odwzorowanego magazynu danych. Programista może jednak określić, które pola mają być wyświetlane, jak również sposób ich przedstawienia. Można zdefiniować następujące rodzaje kolumn: Bound column (kolumny związane) w tym przypadku należy określić. Które kolumny i w jakiej kolejności mają być wyświetlone, oraz podać styl wyświetlania. Jest to domyślny sposób wyświetlania kolumn przez kontrolkę DataGrid. Button column (kolumny przycisków) w tym przypadku dla wszystkich pozycji wierszy siatki wyświetlane są przyciski, którym przypisane są odpowiednie funkcje. Edit Command column (kolumny z poleceniami edycyjnymi) umożliwiają edytowanie danej pozycji. Zamieniają wszystkie kolumny ograniczone na pola modyfikowane. Hyperlink column - wyświetlają dane w postaci hiperlinków. Templated column (szablony kolumn) tak samo jak w przypadku kontrolki Repeater i DataList, można okreslić sposób wyświetlania kolumn, dostosowany do konkretnych potrzeb. Przykład wykorzystania DataGrid dla odwzorowania wierszy i kolumn tabeli bazy danych w sposób domyślny jest pokazany w listingu SqlDataGrid.aspx. Listing SqlDataGrid.aspx. 1. <%@ Page CodeBehind="SqlDataGrid.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGrid" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:datagrid id="mydatagrid" Runat="Server" /> 9. </form> 10. </body> 11. </HTML> Kod klasy programowej jest pokazany w listingu SqlDataGrid.aspx.vb. Listing SqlDataGrid.aspx.vb. 113

114 1. Public Class SqlDataGrid 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. Dim myconnection As System.Data.SqlClient.SqlConnection 7. Dim mycommand As System.Data.SqlClient.SqlCommand 8. myconnection = New System.Data.SqlClient.SqlConnection "Server=Localhost;uid=sa;pwd=;Database=Northwind") 9. mycommand = New System.Data.SqlClient.SqlCommand ("Select * from Products", myconnection) 10. myconnection.open() 11. mydatagrid.datasource = mycommand.executereader() 12. mydatagrid.databind() 13. myconnection.close() 14. End Sub 15. End Class Wykorzystanie kontrolki DataGrid w tych listingach jest podobnym trybu kontrolki Repeater oraz nie wykorzysta zaawansowanych możliwości prezentacji danych. Odwzorowanie kolumn w kontrolce DataGrid Przy prezentacji danych w kontrolce DataGrid jest możliwość wyeliminować oddzielnie kolumny i w ten sposób sterować procesem odwzorowania. Kontrolka DataGrid ma możliwość definicji kolumn które trzeba odwzorować. W tym celu trzeba przypisać właściwości AutoGenerateColumns = false oraz wyznaczyć kolumny do prezentacji. Kod listingu SqlDataGridBoundCols.aspx zawiera deklarację kontrolki DataGrid oraz je obiektów kolumn. Listing SqlDataGridBoundCols.aspx. 1. <%@ Page CodeBehind="SqlDataGridBoundCols.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGridBoundCols" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:datagrid id="mydatagrid" AutoGenerateColumns="False" 9. Runat="Server"> 10. <Columns> 11. <asp:boundcolumn HeaderText="Product Name" 12. DataField="ProductName" /> 13. <asp:boundcolumn HeaderText="Price" 14. DataField="UnitPrice" DataFormatString="{0:c}" /> 15. </Columns> 16. </asp:datagrid> 17. </form> 18. </body> 19. </HTML> Listing SqlDataGridBoundCols.aspx.vb zawiera kod klasy pośredniej. Listing SqlDataGridBoundCols.aspx.vb. 1. Public Class SqlDataGridBoundCols 2. Inherits System.Web.UI.Page 114

115 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. Dim myconnection As System.Data.SqlClient.SqlConnection 7. Dim mycommand As System.Data.SqlClient.SqlCommand 8. myconnection = New System.Data.SqlClient.SqlConnection 9. ("Server=Localhost;uid=sa;pwd=;Database=Northwind") 10. mycommand = New System.Data.SqlClient.SqlCommand 11. myconnection.open() 12. mydatagrid.datasource = mycommand.executereader() 13. mydatagrid.databind() 14. myconnection.close() 15. End Sub 16. End Class W linii 12 do właściwości DataSource obiektu DataGrid został przypisany obiekt DataRead. Dane przez obiekt DataRead zostaną odczytane z bazy danych. Kolumny do wyświetlania zostali zdefiniowane w liniach listingu SqlDataGridBoundCols.aspx. Wykorzystując właściwość Visible każdej kolumny kontrolki DataGrid można robić widocznymi lub niewidocznymi odpowiednie kolumny. W listingu SqlDataGridVisible.aspx jest pokazany przykład strony zawierającej obiekt DataGrid oraz dwa przyciski: Show Details oraz Hide Details. Przy pierwszym uruchomieniu strony zostaną niewidoczne kolumny UnitPrice oraz QuantityPerUnit z tabeli bazy danych Northwind. Przy klikniejciu Show Details te kolumny będą widoczne. Listing SqlDataGridVisible.aspx. 1. <%@ Page CodeBehind="SqlDataGridVisible.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGridVisible" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:button Text="Show Details" Runat="server" id="show" /> 9. <asp:button Text="Hide Details" Runat="server" id="hide" /> 10. <asp:datagrid id="mydatagrid" AutoGenerateColumns= 11. "False" Runat="Server"> 12. <Columns> 13. <asp:boundcolumn HeaderText="Product Name" 14. DataField="ProductName" /> 15. <asp:boundcolumn HeaderText="Price" 16. DataField="UnitPrice" DataFormatString="{0:c}" 17. Visible="False" /> 18. <asp:boundcolumn HeaderText="Quantity Per Unit" 19. DataField="QuantityPerUnit" Visible="False" /> 20. </Columns> 21. </asp:datagrid> 22. </form> 23. </body> 115

116 24. </HTML> Kod klasy programowej jest pokazany w listingu SqlDataGridVisible.aspx.vb. Listing SqlDataGridVisible.aspx.vb. 1. Public Class SqlDataGridVisible 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. If Not IsPostBack Then 7. Me.BindData() 8. End If 9. End Sub 10. Sub BindData() 11. Dim myconnection As System.Data.SqlClient.SqlConnection 12. Dim mycommand As System.Data.SqlClient.SqlCommand 13. myconnection = New System.Data.SqlClient.SqlConnection _ 14. ("Server=Localhost;uid=sa;pwd=;Database=Northwind") 15. mycommand = New System.Data.SqlClient.SqlCommand _ 16. ("Select * from Products", myconnection) 17. myconnection.open() 18. mydatagrid.datasource = mycommand.executereader() 19. mydatagrid.databind() 20. myconnection.close() 21. End Sub 22. Private Sub Show_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Show.Click 23. Dim colcounter As Integer 24. For colcounter = 1 To mydatagrid.columns.count mydatagrid.columns(colcounter).visible = True 26. Next 27. End Sub 28. Private Sub Hide_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Hide.Click 29. Dim colcounter As Integer 30. For colcounter = 1 To mydatagrid.columns.count mydatagrid.columns(colcounter).visible = False 32. Next 33. End Sub 34. End Class Kod klasy pośrednie zawiera metody obrabiania zdarzeń Show_Click oraz Hide_Click. W tych metodach za dopomogą pętli For...Next ustali się właściwość Visible wszystkich kolumn oprócz kolumny z indeksem 0. Edytowanie danych w kontrolce DataGrid Kontrolka DataGrid pozwala na edycję oddzielnych rekordów. Żeby udostępnić rekord do edytowania trzeba przypisać właściwości EditItem kontrolki DataGrid indeks odpowiedniego rekordu który chcemy edytować. W tym przypadku tekst tego rekordu w kontrolce DataGrid będzie odwzorowany przez obiekt sterujący TextBox, który będzie automatyczne wdrożony do wszystkich możliwych pól edycji tego rekordu. Przykład wykorzystania DataGrid do edycji rekordów tabeli Products bazy danych Northwind jest pokazany w listingu SqlDataGridEdit.aspx. Listing SqlDataGridEdit.aspx. 116

117 1. Page CodeBehind="SqlDataGridEdit.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGridEdit" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:datagrid id="mydatagrid" Runat="Server" DataKeyField="ProductID" 9. AutoGenerateColumns="False" cellpadding="3"> 10. <Columns> 11. <asp:editcommandcolumn EditText="Edit" CancelText="Cancel" 12. UpdateText="Update" /> 13. <asp:boundcolumn HeaderText="Product ID" 14. DataField="ProductID" ReadOnly="True" /> 15. <asp:boundcolumn HeaderText="Product Name" 16. DataField="ProductName" /> 17. <asp:boundcolumn HeaderText="Price" 18. DataField="UnitPrice" DataFormatString="{0:c}" /> 19. </Columns> 20. </asp:datagrid> 21. </form> 22. </body> 23. </HTML> W liniach 11,12 kodu SqlDataGridEdit.aspx została zdefiniowana kolumna EditCommandColumn która automatyczne formuje kontrolkę LinkButton dla operacji edycji. Kontrolka LinkButton może być zamieniona na zwykłą Button (PushButton) przez ustalenie właściwości Button Type kolekcji Column. Kiedy rekord do edycji jeszcze nie został wybrany, kolumna EditCommandColumn formuje na ekranie przeglądarki element LinkButton z tekstem "Edit". Po kliknięciu na ten przycisk kolumna EditCommandColumn formuje kontrolki LinkButton Update oraz Cancel. Kod klasy pośredniej jest pokazany w Listingu SqlDataGridEdit.aspx.vb. Kiedy po modyfikacji danych użytkownik kliknji Update będzie uruchomiana procedura mydatagrid_updatecommand()która odpowiada zdarzeniu UpdateCommand kontrolki DataGrid. Dla ustalenia nowych wartości kolumn ProductName oraz UnitPrice są wykorzystane linie kodu W liniach 33, 34 zostali zadeklarowane obiekty klas SqlConnection oraz SqlCommand. W liniach 36,37 są wyznaczone parametry połączenia z bazą danych Northwind. W liniach jest wyznaczona instrukcja SQL Update z parametrami do bazy danych. W liniach wyznaczone są obiekt SqlCommand oraz go parametry. Po zakończeniu procedury trzeba skasować indeks rekordu aktualnej edycji, dlatego w linii 61 mamy kod: mydatagrid.edititemindex = -1 Listing SqlDataGridEdit.aspx.vb. 1. Public Class SqlDataGridEdit 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 117

118 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. If Not IsPostBack Then 7. BindData() 8. End If 9. End Sub 10. Sub BindData() 11. Dim myconnection As System.Data.SqlClient.SqlConnection 12. Dim mycommand As System.Data.SqlClient.SqlCommand 13. myconnection = New System.Data.SqlClient.SqlConnection _ 14. ("Server=Localhost;uid=sa;pwd=;Database=Northwind") 15. mycommand = New System.Data.SqlClient.SqlCommand( _ 16. "Select * from Products", myconnection) 17. myconnection.open() 18. mydatagrid.datasource = mycommand.executereader() 19. mydatagrid.databind() 20. myconnection.close() 21. End Sub 22. Private Sub mydatagrid_editcommand(byval source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles mydatagrid.editcommand 23. mydatagrid.edititemindex = e.item.itemindex 24. BindData() 25. End Sub 26. Private Sub mydatagrid_updatecommand(byval source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles mydatagrid.updatecommand 27. ' Get New Values 28. Dim productname As TextBox 29. productname = e.item.cells(2).controls(0) 30. Dim unitprice As TextBox 31. unitprice = e.item.cells(3).controls(0) 32. ' Update Database 33. Dim myconnection As System.Data.SqlClient.SqlConnection 34. Dim mycommand As System.Data.SqlClient.SqlCommand 35. Dim sqlstring As String 36. myconnection = New System.Data.SqlClient.SqlConnection _ 37. ("Server=Localhost;uid=sa;pwd=;Database=Northwind") 38. sqlstring = "Update Products Set ProductName = " & _ 39. "@productname, UnitPrice=@unitPrice Where _ 40. ProductID=@productID" 41. mycommand = New System.Data.SqlClient.SqlCommand _ 42. (sqlstring, myconnection) 43. mycommand.parameters.add ( _ 44. New System.Data.SqlClient.SqlParameter("@ProductName", _ 45. SqlDbType.NVarChar, 80)) 46. mycommand.parameters("@productname").value = _ 47. productname.text 48. mycommand.parameters.add( _ 49. New System.Data.SqlClient.SqlParameter("@unitprice", _ 50. SqlDbType.Money)) 51. mycommand.parameters("@unitprice").value = _ 52. CType(unitPrice.Text, Decimal) 53. mycommand.parameters.add( _ 54. New System.Data.SqlClient.SqlParameter("@productID", _ 55. SqlDbType.Int)) 56. mycommand.parameters("@productid").value = _ 57. mydatagrid.datakeys.item(e.item.itemindex) 118

119 58. myconnection.open() 59. mycommand.executenonquery() 60. myconnection.close() 61. mydatagrid.edititemindex = BindData() 63. End Sub 64. Private Sub mydatagrid_cancelcommand(byval source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles mydatagrid.cancelcommand 65. mydatagrid.edititemindex = BindData() 67. End Sub 68. End Class Wykorzystanie szablonów w kontrolce DataGrid Wykorzystanie szablonów pozwała oprócz bezpośredniego wyświetlania powiązanych danych zrealizować szereg czynności po sprawdzeniu odwzorowanych danych oraz po formowaniu wyglądu prezentowanej strony. W poprzednim przykładzie nie było możliwości walidować wprowadzone dane. Np. zamiast do pola UnitPrice można byłoby wpisać niekompatybilny typ danych. Szablony pozwalają zdefiniować kontrolki walidatorów danych oraz jakiekolwiek inny typy kontrolek.net FRAMEWORK do kontroli oraz prezentacji odpowiednich kolumn DataGrid. W listingu SqlDataGridEditTemplate.aspx jest pokazany kod umożliwiający modyfikowania danych poprzedniego przykładu z wykorzystaniem szablonów. Listing SqlDataGridEditTemplate.aspx. 1. <%@ Page CodeBehind="SqlDataGridEditTemplate.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGridEditTemplate" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:datagrid id="mydatagrid" cellpadding="3" 9. AutoGenerateColumns="False" DataKeyField="ProductID" 10. Runat="Server"> 11. <Columns> 12. <asp:editcommandcolumn EditText="Edit" CancelText="Cancel" 13. UpdateText="Update" /> 14. <asp:templatecolumn> 15. <ItemTemplate> 16. <%# Container.DataItem( "ProductID" )%> 17. </ItemTemplate> 18. </asp:templatecolumn> 19. <asp:templatecolumn> 20. <ItemTemplate> 21. <%# Container.DataItem( "ProductName" )%> 22. </ItemTemplate> 23. <EditItemTemplate> 24. <asp:textbox id="productname" 25. Text='<%# Container.DataItem( "ProductName" )%>' 119

120 26. Runat="Server"/> 27. <asp:requiredfieldvalidator 28. ControlToValidate="ProductName" 29. Display="Dynamic" Runat="Server"> 30. You must enter a product name! 31. </asp:requiredfieldvalidator> 32. </EditItemTemplate> 33. </asp:templatecolumn> 34. <asp:templatecolumn> 35. <ItemTemplate> 36. <%# String.Format( "{0:c}", 37. Container.DataItem( "UnitPrice" ) ) %> 38. </ItemTemplate> 39. <EditItemTemplate> 40. <asp:textbox id="unitprice" 41. Text='<%# Container.DataItem( "UnitPrice" )%>' 42. Runat="Server"/> 43. <asp:requiredfieldvalidator ControlToValidate="UnitPrice" 44. Display="Dynamic" Runat="Server"> 45. You must enter a unit price! 46. </asp:requiredfieldvalidator> 47. <asp:comparevalidator ControlToValidate="UnitPrice" 48. Display="Dynamic" Type="Currency" 49. Operator="DataTypeCheck" 50. Runat="Server"> 51. The unit price must be a money amount! 52. </asp:comparevalidator> 53. </EditItemTemplate> 54. </asp:templatecolumn> 55. </Columns> 56. </asp:datagrid> 57. </form> 58. </body> 59. </HTML> W tym listingu została wykorzystana klasa TemplateColumn lecz nie BoundColumn jako w poprzednim przykładzie. Klasa BoundColumn może być przekształcona do klasy TemplateColumn w środowisku VSNet. Klasa TemplateColumn może zawierać szablon ItemTemplate oraz szablon EditTemplate. Szablon EditTemplate odwzorowuje rekord kontrolki DataGrid przy wybieraniu tego rekordu do edycji. W liniach jest wyznaczony szablon EditTemplate do edycji pola ProductName. Dla odwzorowania danych z pola ProductName jest wyznaczona kontrolka TextBox w liniach Kontrola wprowadzonych danych realizuje się przez walidator typu RequiredFieldValidator, który został zdefiniowany w liniach W sposób podobny jest wyznaczony szablon do edycji pola UnitPrice w liniach W listingu SqlDataGridEditTemplate.aspx.vb jest pokazany kod klasy pośredniej tej strony. Listing SqlDataGridEditTemplate.aspx.vb. 1. Public Class SqlDataGridEditTemplate 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 120

121 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. If Not IsPostBack Then 7. BindData() 8. End If 9. End Sub 10. Sub BindData() 11. Dim myconnection As System.Data.SqlClient.SqlConnection 12. Dim mycommand As System.Data.SqlClient.SqlCommand 13. myconnection = New 14. System.Data.SqlClient.SqlConnection _ 15. ("Server=Localhost;uid=sa;pwd=;Database=Northwind") 16. mycommand = New System.Data.SqlClient.SqlCommand _ 17. ("Select * from Products", _ 18. myconnection) 19. myconnection.open() 20. mydatagrid.datasource = mycommand.executereader() 21. mydatagrid.databind() 22. myconnection.close() 23. End Sub 24. Private Sub mydatagrid_editcommand(byval source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles mydatagrid.editcommand 25. mydatagrid.edititemindex = e.item.itemindex 26. BindData() 27. End Sub 28. Private Sub mydatagrid_updatecommand(byval source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles mydatagrid.updatecommand 29. If IsValid Then 30. ' Get New Values 31. Dim productname As TextBox 32. productname = e.item.findcontrol("productname") 33. Dim unitprice As TextBox 34. unitprice = e.item.findcontrol("unitprice") 35. ' Update Database 36. Dim myconnection As System.Data.SqlClient.SqlConnection 37. Dim mycommand As System.Data.SqlClient.SqlCommand 38. Dim sqlstring As String 39. myconnection = New System.Data.SqlClient.SqlConnection 40. ("Server=Localhost;uid=sa;pwd=;Database=Northwind") 41. sqlstring = "Update Products Set ProductName=@productName, "_& 42. "UnitPrice=@unitPrice Where ProductID=@productID" 43. mycommand = New System.Data.SqlClient.SqlCommand(sqlString, myconnection) 44. mycommand.parameters.add( _ 45. New System.Data.SqlClient.SqlParameter("@ProductName", SqlDbType.NVarChar, 80)) 46. mycommand.parameters("@productname").value = _ 47. productname.text 48. mycommand.parameters.add( _ 49. New System.Data.SqlClient.SqlParameter("@unitprice", SqlDbType.Money)) 50. mycommand.parameters("@unitprice").value = _ 51. CType(unitPrice.Text, Decimal) 52. mycommand.parameters.add( _ 121

122 53. New SqlDbType.Int)) 54. = _ 55. mydatagrid.datakeys.item(e.item.itemindex) 56. myconnection.open() 57. mycommand.executenonquery() 58. myconnection.close() 59. mydatagrid.edititemindex = BindData() 61. End If 62. End Sub 63. Private Sub mydatagrid_cancelcommand(byval source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles mydatagrid.cancelcommand 64. mydatagrid.edititemindex = BindData() 66. End Sub 67. End Class Ten kod jest podobny do kodu poprzedniego przykładu. Sortowanie danych w kontrolce DataGrid Kontrolka DataGrid zawiera właściwość AllowSorting która pozwała na sortowanie po kolumnach. Kiedy AllowSorting = true oraz AutoGenerateColumns = true, DataGrid wyświetla automatyczne wszystkie możliwe sortowania kolumn w postaci przycisków LinkButton. Kliknięjcie przyciska powoduje zdarzenie klasy SortCommand oraz wywołanie pocedury mydatagrid_sortcommand (). W listingu SqlDataGridSort.aspx jest pokazany kod strony aspx z definicją obiektu DataGrid. Listing SqlDataGridSort.aspx 1. <%@ Page CodeBehind="SqlDataGridSort.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGridSort" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:datagrid id="mydatagrid" AllowSorting="True" cellpadding="3" 9. Runat="Server" /> 10. </form> 11. </body> 12. </HTML> W listingu SqlDataGridSort.aspx.vb jest pokazany kod klasy pośredniej, zawierającej logikę połączenia z bazą danych oraz opracowania zdarzeń. Listing SqlDataGridSort.aspx.vb. 1. Public Class SqlDataGridSort 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Dim sortfield As String = "ProductID" 6. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 7. If Not IsPostBack Then 8. BindData() 9. End If 122

123 10. End Sub 11. Sub BindData() 12. Dim myconnection As System.Data.SqlClient.SqlConnection 13. Dim mycommand As System.Data.SqlClient.SqlCommand 14. Dim sqlstring As String 15. ' Get Records From Database 16. myconnection = New System.Data.SqlClient.SqlConnection _ 17. ("Server=Localhost;uid=sa;pwd=;Database=Northwind") 18. sqlstring = "Select * from Products Order By " & sortfield 19. mycommand = New System.Data.SqlClient.SqlCommand _ 20. (sqlstring, myconnection) 21. myconnection.open() 22. mydatagrid.datasource = mycommand.executereader() 23. mydatagrid.databind() 24. myconnection.close() 25. End Sub 26. Private Sub mydatagrid_sortcommand(byval source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles mydatagrid.sortcommand 27. sortfield = e.sortexpression 28. BindData() 29. End Sub 30. End Class Strona listingu SqlDataGridSort.aspx formuje element DataGrid z tytułami kolumn w postaci linków. Przy klikniejciu na odpowiedni link dane będą posortowane po tej kolumnie. Każde klikniejcie powoduje zdarzenie SortCommand. Procedura obrabiania zdarzenia mydatagrid_sortcommand() zawiera linie 27 kodu która przypisuje zmiennej sortfild (zadeklarowanej w linii 5) tekstową nazwę kolumny. Ta nazwa będzie przekazana przez parametr zdarzenia e.sortexpression. Zmienna sortfild wykorzysta się w metodzie BindData() (linia 18) dla realizacji polecenia SQL obiektu DataReader. W przypadkach, kiedy kolumny nie są wygenerowane automatyczne (AutoGenerateColumns = false) dla sortowania oddzielnych kolumn może być wykorzystana właściwość SortExpression klasy BoundColumn. W ten sposób można wyznaczyć które z kolumn mogą być posortowane oraz które nie. Ten przykład jest pokazany w listingu SqlDataGridSotrCustom.aspx. Dla definicji kolumn w kontrolce DataGrid zostali wykorzystane obiekty klas BoundColumn w liniach Procedura obrabiania zdarzeń SortCommand jest wyznaczona w linii 9. Listing SqlDataGridSotrCustom.aspx. 1. <%@ Page CodeBehind="SqlDataGridSortCustom.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGridSortCustom" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:datagrid id="mydatagrid" AutoGenerateColumns="False" 9. AllowSorting="True" onsortcommand="sortgrid" 10. cellpadding="3" Runat="Server"> 11. <Columns> 12. <asp:boundcolumn HeaderText="Product ID" 13. DataField="ProductID" /> 123

124 14. <asp:boundcolumn HeaderText="Product Name" 15. DataField="ProductName" SortExpression="ProductName" /> 16. <asp:boundcolumn HeaderText="Price" DataField="UnitPrice" 17. DataFormatString="{0:c}" SortExpression="UnitPrice" /> 18. </Columns> 19. </asp:datagrid> 20. </form> 21. </body> 22. </HTML> Kod klasy programowej jest pokazany w SqlDataGridSotrCustom.aspx.vb.listingu Listing SqlDataGridSotrCustom.aspx.vb. 1. Public Class SqlDataGridSortCustom 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Dim sortfield As String = "ProductID" 6. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As 7. System.EventArgs) Handles MyBase.Load 8. If Not IsPostBack Then 9. BindData() 10. End If 11. End Sub 12. Sub BindData() 13. Dim myconnection As System.Data.SqlClient.SqlConnection 14. Dim mycommand As System.Data.SqlClient.SqlCommand 15. Dim sqlstring As String 16. myconnection = New _ 17. System.Data.SqlClient.SqlConnection("Server=Localhost; 18. uid=sa;pwd=;database=northwind") 19. sqlstring = "Select * from Products Order By " & sortfield 20. mycommand = New System.Data.SqlClient.SqlCommand _ 21. (sqlstring, myconnection) 22. myconnection.open() 23. mydatagrid.datasource = mycommand.executereader() 24. mydatagrid.databind() 25. myconnection.close() 26. End Sub 27. Sub SortGrid(ByVal s As Object, ByVal e As 28. DataGridSortCommandEventArgs) 29. sortfield = e.sortexpression 30. BindData() 31. End Sub 32. End Class Podział na strony wyświetlanych danych w obiekcie DataGrid Kontrolka DataGrid ma możliwość podzielenia na strony wyświetlanych danych, jeśli nie zmieszczą się na jednej. Kiedy ustawiony jest podział na strony, wynik przetwarzania jest rozdzielany na zadeklarowaną liczbę stron, a użytkownik może przechodzić pomiędzy stronami za pomocą przycisków. Numer strony, która ma być wyświetlana aktualnie, jest określony przez wartość atrybutu CurrenPageIndex obiektu DataGrid. Kiedy użytkownik kliknie przycisk, aby przejść do kolejnej strony, cały zestaw danych jest tworzony ponownie i proces podziału na strony rozpoczyna się kolejny raz. Podział na strony uaktywniany jest przez nadania atrybutowi AllowPaging = True, oraz określenie za pomocą atrybutu PageSize 124

125 liczbę rekordów, które maja być wyświetlone na jednej stronie. Na stronie właściwości DataGrid Paging Properties w VSNET można określić styl przycisków do przechodzenia pomiędzy stronami. Tu można zdefiniować ilość wyświetlanych rekordów na stronie, zadeklarować wyświetlanie nazw przycisków lub numerów stron. Dla obsługiwania procesów przejścia pomiędzy stronami musi być opracowana metoda obrabiania zdarzenia związana z uruchamianiem przycisków przejścia. Istnieją ograniczenia do wykorzystania wbudowanych możliwości DataGrid stosowne przeglądania po stronach: Nie jest możliwym wykorzystania tej możliwości przy wiązaniu z obiektami klasy DataReader. Te ograniczenie wypływa z konieczności obecności wszystkich odwzorowanych rekordów w pamięci podręczną, a obiekt DataReader ma tylko jeden aktualny rekord. Nie można ograniczyć ilość stron w pamięci podręcznej ViewState wszystkie rekordy muszą być uaktualnione. W listingu SqlDataGridPaging.aspx jest pokazany przykład wykorzystania DataGrid dla podziału na strony. Listing SqlDataGridPaging.aspx. 1. <%@ Page CodeBehind="SqlDataGridPaging.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGridPaging" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 7. <form Runat="Server"> 8. <asp:datagrid id="mydatagrid" AutoGenerateColumns="False" 9. AllowPaging="True" cellpadding="3" Runat="Server"> 10. <Columns> 11. <asp:boundcolumn DataField="ProductID" 12. HeaderText="ProductID"> 13. </asp:boundcolumn> 14. <asp:boundcolumn DataField="ProductName" 15. HeaderText="Product Name"> 16. </asp:boundcolumn> 17. <asp:boundcolumn DataField="UnitPrice" 18. HeaderText="Price" DataFormatString="{0:c}"> 19. </asp:boundcolumn> 20. </Columns> 21. </asp:datagrid> 22. </form> 23. </body> 24. </HTML> Kod klasy programowej jest pokazany w listingu SqlDataGridPaging.aspx.vb. Listing SqlDataGridPaging.aspx.vb. 1. Public Class SqlDataGridPaging 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 125

126 6. If Not IsPostBack Then 7. BindData() 8. End If 9. End Sub 10. Sub BindData() 11. Dim myconnection As System.Data.SqlClient.SqlConnection 12. Dim myadapter As System.Data.SqlClient.SqlDataAdapter 13. Dim sqlstring As String 14. Dim mydataset As DataSet 15. ' Get Records From Database 16. myconnection = New _ 17. System.Data.SqlClient.SqlConnection _ 18. ("Server=Localhost;uid=sa;pwd=;Database=Northwind") 19. sqlstring = "Select * from Products" 20. myadapter = New System.Data.SqlClient.SqlDataAdapter _ 21. (sqlstring, myconnection) 22. mydataset = New DataSet 23. myadapter.fill(mydataset, "Products") 24. mydatagrid.datasource = mydataset 25. mydatagrid.databind() 26. End Sub 27. Private Sub mydatagrid_pageindexchanged(byval source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles mydatagrid.pageindexchanged 28. mydatagrid.currentpageindex = e.newpageindex 29. BindData() 30. End Sub 31. End Class Procedura obrabiania zdarzenia PageIndexChanged jest wyznaczona w liniach kodu. Ta procedura modyfikuje właściwość CurrentPageIndex kontrolki DataGrid oraz realizuje ponowne wiązanie ze źródłem danych (obiektem DataSet). Wyżej było omówione, że wykorzystanie wewnętrznych możliwości DataGrid dla podziału na strony napotyka się na ograniczenia związane z koniecznością obecności wszystkich rekordów w pamięci podręcznej (ViewState). To oznaczy się, że nawet w przypadku, kiedy użytkownik potrzebuje tylko jedną stronę obiekt DataGrid musi zawierać rekordy wszystkich stron w pamięci podręcznej. W tym przypadku dla oszczędzenia resursów RAM można stworzyć własne oprogramowanie dla sterowania procesem podziału na strony. Ideą może być wykorzystanie polecenia SQL o następnej postaci: Select TOP 5 * From Products Where ProductID >6 Order By ProductID Te polecenie wywoła 5 rekordów z tabeli bazy danych z indeksem >6. Dla wywołania oddzielnych bloków rekordów może być za każdym razem wykorzystane podobne polecenie. W listingu SqlDataGridPageCustom.aspx jest pokazany przykład wykorzystania sterowaniem podziału na strony przez program użytkownika. Listing SqlDataGridPageCustom.aspx. 1. <%@ Page CodeBehind="SqlDataGridPageCustom.aspx.vb" Language="vb" AutoEventWireup="false" Inherits="PrezentacjaDanych.SqlDataGridPageCustom" %> 2. <HTML> 3. <HEAD> 4. <title>datagrid</title> 5. </HEAD> 6. <body> 126

127 7. Page <%=ViewState( "PageNumber" ) %> of 8. <%=ViewState( "PageCount" ) %> 9. <form Runat="Server"> 10. <asp:datagrid id="mydatagrid" AutoGenerateColumns="False" 11. cellpadding="3" Runat="Server"> 12. <Columns> 13. <asp:boundcolumn HeaderText="Product ID" 14. DataField="ProductID" /> 15. <asp:boundcolumn HeaderText="Product Name" 16. DataField="ProductName" /> 17. <asp:boundcolumn HeaderText="Price" 18. DataField="UnitPrice" DataFormatString="{0:c}" /> 19. </Columns> 20. </asp:datagrid> 21. <p> 22. <asp:linkbutton id="prevbutton" Text="<< Previous" 23. onclick="pagegrid" commandargument="previous" 24. Runat="Server" /> 25. <asp:linkbutton id="nextbutton" Text="Next >>" 26. onclick="pagegrid" commandargument="next" 27. Runat="Server" /> 28. </form> 29. </P> 30. </body> 31. </HTML> Kod klasy programowej jest pokazany w listingu SqlDataGridPageCustom.aspx.vb Listing SqlDataGridPageCustom.aspx.vb. 1. Public Class SqlDataGridPageCustom 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Const PageSize = Dim myconnection As System.Data.SqlClient.SqlConnection 7. Dim myadapter As System.Data.SqlClient.SqlDataAdapter 8. Dim sqlstring As String 9. Dim mydataset As DataSet 10. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 11. myconnection = New 12. System.Data.SqlClient.SqlConnection("Server=Localhost;uid=sa; 13. pwd=;database=northwind") 14. If Not IsPostBack Then 15. ViewState("PageNumber") = ViewState("PageCount") = getpagecount() 17. ViewState("startProductID") = ViewState("endProductID") = movenext() 20. End If 21. End Sub 22. Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender 127

128 23. If ViewState("PageNumber") = ViewState("PageCount") Then 24. nextbutton.enabled = False 25. Else 26. nextbutton.enabled = True 27. End If 28. If ViewState("PageNumber") = 1 Then 29. prevbutton.enabled = False 30. Else 31. prevbutton.enabled = True 32. End If 33. End Sub 34. Function getpagecount() As Integer 35. Dim thecount As Double 36. Dim sqlstring As String 37. Dim mycommand As System.Data.SqlClient.SqlCommand 38. sqlstring = "Select Count(*) thecount From Products" 39. mycommand = New System.Data.SqlClient.SqlCommand _ 40. (sqlstring, myconnection) 41. myconnection.open() 42. thecount = mycommand.executescalar() 43. myconnection.close() 44. Return Math.Ceiling(theCount / PageSize) 45. End Function 46. Sub pagegrid(byval s As Object, ByVal e As EventArgs) 47. If s.commandargument = "Next" Then 48. movenext() 49. Else 50. moveprevious() 51. End If 52. End Sub 53. Sub movenext() 54. Dim lastrowindex As Integer 55. sqlstring = "Select Top " & PageSize.toString() & _ 56. " * from Products " _ 57. & "Where ProductID > " & ViewState("endProductID")._ 58. tostring() 59. myadapter = New System.Data.SqlClient.SqlDataAdapter _ 60. (sqlstring, myconnection) 61. mydataset = New DataSet 62. myadapter.fill(mydataset, "Products") 63. mydatagrid.datasource = mydataset 64. mydatagrid.databind() 65. ViewState("PageNumber") = ViewState("PageNumber") ViewState("startProductID") = _ 67. MyDataSet.Tables("Products").Rows(0).Item("ProductID", _ 68. DataRowVersion.Current) 69. lastrowindex = mydataset.tables("products").rows.count ViewState("endProductID") = _ 71. MyDataSet.Tables("Products").Rows(lastRowIndex). _ 72. Item("ProductID", DataRowVersion.Current) 73. End Sub 74. Sub moveprevious() 75. Dim mydataview As DataView 76. Dim lastrowindex As Integer 77. sqlstring = "Select Top " & PageSize.toString() & _ 78. " * from Products " & " Where ProductID < " & _ 79. ViewState("startProductID").toString() _ 80. & " Order By ProductID DESC" 81. myadapter = New System.Data.SqlClient.SqlDataAdapter _ 128

129 82. (sqlstring, myconnection) 83. mydataset = New DataSet 84. myadapter.fill(mydataset, "Products") 85. mydataview = mydataset.tables("products").defaultview 86. mydataview.sort = "ProductID" 87. mydatagrid.datasource = mydataview 88. mydatagrid.databind() 89. lastrowindex = mydataset.tables("products"). _ 90. Rows.Count ViewState("PageNumber") = ViewState("PageNumber") ViewState("startProductID") = _ 93. MyDataSet.Tables("Products").Rows(lastRowIndex). _ 94. Item("ProductID", DataRowVersion.Current) 95. ViewState("endProductID") = _ 96. MyDataSet.Tables("Products").Rows(0).Item _ 97. ("ProductID", DataRowVersion.Current) 98. End Sub 99. End Class Kontrolki walidacyjne ASP.NET Walidacja jest procesem wielopoziomowym i stanowi zbiór reguł, które nakładają na zbierane dane. Dane zbierane do walidacji pochodzą z formularzy aplikacji. Walidacja może być następnych typów: Walidacja po stronie klienta; Walidacja po stronie serwera. Kontrolki walidacyjne : RequiredFieldValidator CompareValidator RangeValidator RegularExpressionValidator CustomValidator ValidtionSummary Sprawdza, czy do elementu formularza zostało coś wprowadzone Pozwala porównać dane wprowadzone przez użytkownika z innym elementem ( innym polem formularza lub dowolnej stalej) Sprawdza, czy wartość wprowadzona przez użytkownika mieści się w podanym zakresie liczb lub znaków. Sprawdza, czy wpis użytkownika jest zgodny ze wzorcem zdefiniowanym przez wyrażenie regularne. Sprawdza wpis użytkownika za pomocą własnej logiki walidacyjnej. Wyświetla wszystkie komunikaty o błędach wszystkich kontrolek walidacyjnych w jednym miejscu na stronie. Opracowanie interfejsów graficznych (GUI) za dopomogą stron wzorcowych. Strony wzorcowe są narzędziem, pozwalającym tworzyć szablony stron dla wielokrotnego użytku. Szablon zawiera ogólne wymogi do wyglądu stron, którzy będą dziedziczyły ten szablon. Dowolna nowa strona może dziedziczyć tylko jeden szablon. Każda strona oprócz 129

130 komponentów dziedziczonych, może zawierać także i szczegóły interfejsu skojarzone tylko z tą samą stroną oraz nie dziedziczone od szablonu. Żeby wyznaczyć w szablonie części dla dziedziczenia oraz części które nie mogą być dziedziczone trzeba wykorzystać kontrolkę ContentPlaceHolder. Ta kontrolka musi być zdefiniowana w szablonie oraz jest przeznaczona dla indywidualnych celów każdej strony. Zawartość kontrolki ContentPlaceHolder nie jest dziedziczona przez inny strony. Ta kontrolka wyznacza przestrzeń interfejsu która nie jest dziedziczona. Wszystkie inne elementy szablonu poza kontrolek ContentPlaceHolder są dziedziczone. Niżej jest rozpatrywany przykład tworzenia i wykorzystania szablonów stron. Na rys. 1 jest pokazany projekt witryny szablon, która zawiera dwie strony wzorcowe typu master. Interfejsy tych stron wzorcowych mogą być dziedziczone. Rys.1. Na rys 2. jest pokazane okno dodawania strony wzorcowej do treści projektu witryny(strony typu master ). Po stworzeniu strony master do jej zawartości automatyczne będzie dodany obiekt klasy ContentPlaceHolder. Na rys.3 jest pokazany ten obiekt na panelu Designer strony SiteMaster.master. Wydruk kodów HTML prezentacji GUI dla tej strony(do opracowania wzorca) jest pokazany w listingu Site.master (do opracowania). Strona SiteMaster.master została dopracowana do innej postaci wzorcowej pokazanej w oknie projektu na Rys.4. Kody HTML strony wzorca są pokazane w listingu 2. Nowy wzorzec strony zawiera 3 panele - lewy, centralny, prawy, oraz stopkę. W lewym i prawym będą prezentowane komponenty ogólne dla wszystkich stron. To są obrazek Microsoft Windows XP w lewym panelu oraz kontrolki Button i Label w prawym panelu. Przy naciśnięciu przycisku Button w kontrolce Label będzie komunikat Hello World! na stronie wzorca oraz na każdej stronie dzidziczonej. Centralny panel oraz stopka mogą zawierać komponenty GUI wyspecjalizowane dla każdej oddzielnej strony interfejsu. Wzorcowa strona zawiera tu odpowiednie kontrolki ContentPlaceHolder. 130

131 Rys. 2. Rys.3. Listing1. Site.master (do opracowania) Master Language="C#" AutoEventWireup="true" CodeFile="Site.master.cs" Inherits="MasterPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " <html xmlns=" > <head runat="server"> <title>untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:contentplaceholder id="contentplaceholder1" runat="server"> </asp:contentplaceholder> </div> </form> </body> </html> 131

132 Rys.4. Listing2. SiteMaster.master (po opracowaniu) Master Language="C#" AutoEventWireup="true" CodeFile="SiteMaster.master.cs" Inherits="SiteMaster" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " <html xmlns=" > <head runat="server"> <title>untitled Page</title> </head> <body> <form id="form1" runat="server"> <table width=100% border=2 callspacing=1 cellpadding=1 cellspacing="3"> <tr> <td valign=top style="height: 199px; width: 150px; text-align: justify;"> To jest lewy panel ustalonej treści, zawierający obiekty, które będą dziedziczone na każdej stronie <asp:image ID="Image1" runat="server" ImageUrl="~/image/winxp.gif" Style="left: 22px; position: absolute; top: 152px; z- index: 100;" Width="140px" /> </td> <td valign=top style="height: 199px; width: 180px;"> <asp:contentplaceholder ID="plhMain" runat=server> Treść po środku dowolnej strony znajdzie się tutaj </asp:contentplaceholder> </td> <td valign= top align=right style="height: 199px; width: 140px; text-align: justify;"> To jest prawa strona dla ustalonej treści 132

133 <asp:label ID="Label1" runat="server" Text="Label" Width="149px"></asp:Label> <asp:button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /></td> </tr> <tr> <td colspan=3> <asp:contentplaceholder ID="plhFooter" runat=server> W tym miejscu znajdzie się treść stopki dowolnej strony</asp:contentplaceholder> </td> </tr> </table> </form> </body> </html> Żeby stworzyć stronę, która dziedziczy stronę wzorcową trzeba ustalić właściwość dziedziczenia select master page w oknie dodawania nowego komponentu projektu. To niemożliwe zrobić, kiedy strona już istnieje. Dlatego wszystkie strony dziedziczone trzeba dodawać do projektu. Na rys 5 jest pokazane okno dla dodawania strony ContentSample.aspx, która będzie dziedziczyć stronę wzorcową SiteMaster.master. Strona ta została dopracowana nowymi komponentami interfejsu. Na rys.6 jest pokazane okno projektu strony ContentSample.aspx. Do strony wprowadzono następne zmainy: do panelu centralnego dodana kontrolka Calendar oraz stopka strony zawiera logo Politechniki Koszalińskiej. W listingu 3 pokazany jest kod HTML strony ContentSample.aspx. Przy uruchomieniu strony w przeglądarce będą odwzorowane wszystkie komponenty GUI. Na rys. 7 jest pokazany ostateczny wygląd strony przy uruchomieniu w przeglądarce. Rys

134 Rys. 6. Listing3. ContentSample.aspx. Page Language="C#" MasterPageFile="~/SiteMaster.master" AutoEventWireup="true" CodeFile="ContentSample.aspx.cs" Inherits="ContentSample" Title="Untitled Page" %> <asp:content ID="Content1" ContentPlaceHolderID="plhMain" Runat="Server"> To się pojawi w głównym połu zawartości<br /> <asp:calendar ID="Calendar1" runat="server"></asp:calendar> </asp:content> <asp:content ID="Content2" ContentPlaceHolderID="plhFooter" Runat="Server"> &copy: Politechnika Koszalińska </asp:content> 134

135 Rys.7. Tworzenie interfejsu graficznego za dopomogą tematów i skórek. Wykorzystanie tematów i skórek pozwoli się personalizować witryny internetowe poprzez ustawienie wyglądu i działania kontrolek w sposób spełniający preferencje projektanta. Temat to jest zbiór skórek opisujące wygląd, jaki powinny przyjąć kontrolki. Każdy temat w projekcie witryny musi być rozlokowany w podkatalogu App_Themes. Ten folder może być dodany do witryny przez opcję Add ASP.NET Folder menu kontekstowego pokazanego na rys

136 Rys.1 Dodanie tematu do witryny. Do tego folderu można dodać arkusze styli (pliki.css) i pliki skórek (pliki.skin). Istnieją dwie metody określania tematu. 1. Pierwsza polega na wykorzystaniu elementu <pages> z pliku Web.Config, np.: <pages theme= Green > Ta linia kodu XML w pliku konfiguracyjnym wskazuje, że wszystkie strony w danej aplikacji będą domyślnie korzystały z tematu Green. Każda strona będzie mogła samodzielnie nadpisać wybór tematu na jeden z dwóch sposobów. 2. Druga metoda wykorzystuje bezpośrednio na stronie, np.: <%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="skindemo.aspx.cs" Inherits="skindemo" Title="Untitled Page" Theme="Red"%> Ten kod jest wykorzystany przez stronę do przesłonięcia ustawień z pliku Web.Config i wymusza zastosowanie tematu Red dla tej strony. Można także programowo ustawić bieżący temat dla strony, np.: protected override void OnPreInit(EventArgs e) { base.onpreinit(e); Theme = "red"; } Przykład demonstracji wykorzystania tematów oraz skórek jest pokazany w witrynie C:\Inetpub\wwwroot\ThemesSkins. Do witryny została dodana strona wzorcowa Site.master. Wygląd strony w panelu designer jest pokazany na rys

137 Rys.2 Kod tej strony pokazany w listingu. Listing 1. (Kod strony Site.master) 1. <%@ Master Language="C#" AutoEventWireup="true" CodeFile="Site.master.cs" Inherits="Site" %> 2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " 3. <html xmlns=" > 4. <head runat="server"> 5. <title>untitled Page</title> 6. </head> 7. <body> 8. <form id="form1" runat="server"> 9. <div> 10. <img src="image/winxp.gif" /> 11. </div> 12. <table> 13. <tr> 14. <td style="width: 906px"> 15. <asp:contentplaceholder id="contentplaceholder1" runat="server"> 16. </asp:contentplaceholder> 17. </td> 18. </tr> 19. </table> 20. </form> 21. </body> 22. </html> W znacznikach <asp:contentplaceholder id="contentplaceholder1" runat="server"> </asp:contentplaceholder> 137

138 jest wyznaczony element ContentPlaceholder który zawiera przestrzeń dla tworzenia interfejsu na stronach witryny. Interfejs strony będzie rozlokowany tylko w kontrolce Content. W tej przestrzeni będą nie dziedziczone elementy interfejsu. Strona default.aspx dziedziczy stronę wzorcową oraz zawiera dodatkowe elementy interfejsu w obszarze Content. W pliku Web.Config są ustalone wymagania dla wszystkich stron, którzy muszą mieć wygląd wyznaczony zgodnie z tematem Green. Kod pliku Web.Config jest pokazany w listingu 2. Listing 2. (Kod pliku Web.Config) 1. <?xml version="1.0"?> 2. <configuration> 3. <appsettings/> 4. <connectionstrings/> 5. <system.web> 6. <pages theme="green" /> 7. <compilation debug="false" /> 8. <authentication mode="windows" /> 9. </system.web> 10. </configuration> W linii 6 jest ustalony temat Green dla wszystkich stron witryny. Kod default.aspx strony jest pokazany w listingu 3. Listing 3. (kod strony default.aspx) 1. <%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Title="Untitled Page" %> 2. <asp:content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> 3. <asp:button ID="Button1" runat="server" Height="34px" Text="Button" Width="96px" /><br /> 4. <br /> 5. <asp:label ID="Label1" runat="server" Font-Size="Large" Height="31px" Text="Tworzenie interfejsu Użytkownika" Width="254px"></asp:Label><br /> 6. </asp:content> Wygląd strony przy uruchomieniu jest pokazany na rys. 3. Na rys 3 są zielone tło, czcionka normal po domyśleniu, ustalone w pliku green.css tematu Green. 138

139 Rys.3 Temat tej strony może być zmieniony w sposób programowy. W listingu 4 jest pokazany kod klasy pośredniej dla strony default.aspx.cs. Listing 4. (strona default.aspx.cs ) 7. using System; 8. using System.Data; 9. using System.Configuration; 10. using System.Collections; 11. using System.Web; 12. using System.Web.Security; 13. using System.Web.UI; 14. using System.Web.UI.WebControls; 15. using System.Web.UI.WebControls.WebParts; 16. using System.Web.UI.HtmlControls; 17. public partial class _Default : System.Web.UI.Page 18. { 19. protected void Page_Load(object sender, EventArgs e) 20. { 21. } 22. protected override void OnPreInit(EventArgs e) 23. { 24. base.onpreinit(e); 25. Theme = "red"; 26. } 27. } W liniach jest wykorzystana metoda OnPreInit() dla przesłonięcia tematu Green, wyznaczonego w pliku Web.Config przez temat Red, omowiony w pliku red.css. Nowy wygląd strony jest pokazany na rys.4. (na rys. są czerwone tło, czcionka Italic ) 139

140 Rys.4 Dla realizacji dynamicznego sterowania wyglądem kontrolek trzeba wykorzystać pliki skórek odpowiednich tematów. W listingu 5 jest pokazany plik controls.skin tematu Green. Listing 5. (plik controls.skin tematu Green) 1. <%-- domyślny przycisk--%> 2. <asp:button runat="server" ForeColor="Green" BackColor="White"/> 3. <%-- przycisk pojawia się po wyborze identyfikatora skórki 'Flat'-- %> 4. <asp:button runat="server" ForeColor="Black" BackColor="Blue" BorderStyle="None" SkinID="Flat" /> 5. <%-- przycisk pojawia się po wyborze identyfikatora skórki 'Inverse'--%> 6. <asp:button runat="server" ForeColor="White" BackColor="Green" SkinID="Inverse" /> Kod w listingu 5 zawiera częściową definicję kontrolek. Zwłaszcza są parametry runat="server", ale są nieobecne identyfikatory ID kontrolek. Definicje kontrolek w tym pliku są przeznaczone dla ustalenia właściwości interfejsu użytkownika i wyświetlania. To oznacza, że można ustawić style wierszy parzystych i nieparzystych kontrolki DataGrid, ale nie można w tym pliku wyznaczyć źródła danych. W pliku Listing 5. są wyznaczone wyglądy trzech typów kontrolek Button. W linii 2 jest ustalone wymogi do wszystkich kontrolek Button po domyśleniu. Dla tych kontrolek nie trzeba wyznaczać parametry SkinID. W liniach 4-6 są wyznaczone inne wyglądy kontrolek Button mające ustalone parametry SkinID. Przy stworzeniu interfejsu stron.asp trzeba odwołać się do parametrów SkinID w kontrolkach mające inny wygląd inny czym wygląd po domyśleniu. Przykład strony skindemo.aspx jest pokazany w listingu 6. Listing 6 (strona skindemo.aspx.) 1. <%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="skindemo.aspx.cs" Inherits="skindemo" Title="Untitled Page" Theme="green"%> 2. <asp:content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> 140

141 3. <asp:button ID="defaultButton" runat="server" Text="To jest domyślny przycisk" Width="291px" /><br /> 4. <br /> 5. <asp:button ID="flatButton" runat="server" Text="To jest płaski przycisk" Width="290px" SkinID= "Flat" /> 6. <br /> 7. <br /> 8. <asp:button ID="inverseButton" runat="server" Text="To jest odwroconyi przycisk" Width="290px" SkinID="Inverse" /> 9. </asp:content> W przestrzeni Content zostali zdefiniowane trzy kontrolki Button którzy odwalają się do odpowiednich skórek. Wygląd strony jest pokazany na rys. 5. Rys.5 Opracowanie mechanizmów nawigacji witryn WWW W przypadkach komplikowanych projektów witryn WWW zawierających wiele stron powstaje pytanie stworzenia mechanizmów nawigacji, pozwalających podpowiedzieć użytkownikowi gdzie on się znajduje oraz w jaki sposób można zrealizować przejście do innej strony. Zestaw kontrolek i klas ASP.NET zawiera zasoby sterowania nawigacją w witrynie. W większości przypadków trzeba rozmieścić tę kontrolki na każdej stronie, dlatego lepiej wykorzystać stronę wzorcową dla tworzenia stron. Głównym elementem nawigacji jest plik XML, zawierający hierarchiczną bazę danych XML węzłów witryny. Ten plik może być dodany do projektu przez okno Add New Item. Po domyśleniu plik nawigacji ma nazwę Web.sitemap. Szkielet tego pliku przy stworzeniu jest pokazany w listingu 1. Listing 1. Web.sitemap (szkielet pliku nawigacji ). <?xml version="1.0" encoding="utf-8"?> 141

142 <sitemap xmlns=" > <sitemapnode url="" title="" description=""> <sitemapnode url="" title="" description="" /> <sitemapnode url="" title="" description="" /> </sitemapnode> </sitemap> Realna mapa witryny musi zawierać uzupełnione definicje znaczników XML <sitemapnode> oraz druga linia kodu w listingu 1 odwoła się do pliku tych definicji. Atrybut URL w linii 3 musi zawierać URL strony witryny odpowiadającej węzłowi, atrybut title definiuje tekst, który jest używany jako łącze, natomiast atrybut description będzie używany jako podpowiedź. Realny plik Web.sitemap musi zawierać uzupełnioną strukturę węzłów. Dla demonstracji możliwości nawigacji jest stworzony projekt witryny. Projekt SiteNavigation zawiera przykłady stron witryny oraz plik Web.sitemap są pokazane na rys.1. Rys.1 Plik Web.sitemap w listingu 1 został zastąpiony plikiem mapy witryny mający ostateczny wygląd w listingu 2. Listing 2. Web.sitemap (mapa stron witryny) <?xml version="1.0" encoding="utf-8"?> <sitemap xmlns=" > <sitemapnode title="witamy" description="witamy" url="~/welcome.aspx"> <sitemapnode title="pisanie" description="pisanie" url="~/writing.aspx"> <sitemapnode title="książki" description="książki" url="~/books.aspx"> <sitemapnode title="książki w druku" description="książki w druku" url="~/booksinprint.aspx" /> <sitemapnode title="książki niedostępne" description="książki niedostępne" url="~/outofprintbooks.aspx" /> </sitemapnode> <sitemapnode title="artykuły" description="artykuły" 142

143 url="~/articles.aspx" /> </sitemapnode> <sitemapnode title="programowanie" description="programowanie" url="~/programming.aspx"> <sitemapnode title="prgramowanie On-Site" description="programowanie On-site" url="~/onsiteprogramming.aspx" /> <sitemapnode title="programowanie Off-Site" description="programowanie Off-site" url="~/offsiteprogramming.aspx" /> </sitemapnode> <sitemapnode title="szkolenia" description="szkolenia na miejscu " url="~/training.aspx"> <sitemapnode title="szkolenia w zakresie C#" description="szkolenia w zakresie C#" url="~/traincsharp.aspx" /> <sitemapnode title="szkolenia w zakresie VB" description="szkolenia w zakresie VB" url="~/trainvbnet.aspx" /> <sitemapnode title="szkolenia w zakresie ASP.NET" description="szkolenia w zakresie ASP.NET" url="~/trainaspnet.aspx" /> <sitemapnode title="szkolenia w zakresie technologii Windows Forms" description="szkolenia w zakresie technologii Windows Forms" url="~/trainwinforms.aspx" /> </sitemapnode> <sitemapnode title="doradztwo" description="doradztwo" url="~/consulting.aspx"> <sitemapnode title="analiza aplikacji" description="analiza aplikacji" url="~/applicationanalysis.aspx" /> <sitemapnode title="projektowanie aplikacji" description="projektowanie aplikacji" url="~/applicationdesign.aspx" /> <sitemapnode title="mentoring" description="mentoring zespołu" url="~/mentoring.aspx" /> </sitemapnode> </sitemapnode> </sitemap> Plik mapy witryny posiada pojedynczy element <sitemap>, który definiuje przestrzeń nazw XML. Wewnątrz elementu sitemap został zagnieżdżony jeden element <SiteMapNode>, odpowiadający stronie Welcome witryny. Ten pierwszy element zawiera pewną liczbę elementów potomnych <sitemapnode>. Wszystkie strony dziedziczą od strony wzorcową Master.page. Do tej strony zostali dodane kontrolki którzy będą dziedziczone przez inne strony. To są kontrolki: SiteMapDataSource, TreeView, SiteMapPath oraz ContentPlaceHolder. Wydruk strony projektu wzorca jest pokazany w listingu 3. Listing 3. Master.Page. <%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " 143

144 <html xmlns=" > <head runat="server"> <title>untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:sitemapdatasource ID="SiteMapDataSource1" runat="server" /> <asp:table ID="Table1" runat="server" Width="100%" Height="233px" BorderWidth="3px" > <asp:tablerow runat="server"> <asp:tablecell runat="server" BorderWidth="3px"> <asp:treeview ID="TreeView1" runat="server" DataSourceID="SiteMapDataSource1" /> </asp:tablecell> <asp:tablecell VerticalAlign="Top" runat="server"> <asp:sitemappath ID="SiteMapPath1" runat="server" /> <br /><br /> <asp:contentplaceholder id="contentplaceholder1" runat="server"> </asp:contentplaceholder> </asp:tablecell> </asp:tablerow> </asp:table> </div> </form> </body> </html> Wszystkie kontrolki zostali rozmieśczone w jednym wierszu tablicy oraz w dwoch kolumnach tego wierszu. W lewej kolumnie jest rozmiejśczony element TreeView oraz w prawej kolumnie są kontrolki SiteMapDataSource i ContentplaceHolder. Żrodlem danych kontrolki TreeView jest wyznaczona kontrolka SiteMapDataSource. Kontrolka SiteMapDataSource po domyśleniu jest skojarzona z plikiem mapy Web.Sitemap, dlatego każda strona witryny będzie zawierać hierarchiczną mapę witryny z lewej części prezentowaną elementem TreeView oraz nawigacyjny wizualny element typu jesteś tutaj z prawej części, prezentowany przez kontrolkę SiteMapDataSource. Oprócz tego, w prawej części każdej strony mogą być rozmieszczone specyficzne zawartości każdej strony w kontrolce Content. Kontrolka Content jest stworzona w sposób automatyczny i odwoła się do kontrolki ContentPlaceHolder wzorca MasterPage.master. Przykład strony witryny jest pokazany na rys

145 \ Rys.1 Tworzenie serwisów WWW Serwis WWW (usługa WWW, usługa sieciowa, usługa Web) to jest komponent programowy, niezależny od platformy i implementacji, rozmieszczony na serwerze WWW, dostarczający metody które mogą być wywołane przez sieć za pomocą protokołów standardowych HTTP oraz XML. Usługa WWW może być opisana za pomocą języka opisu usług, opublikowana w rejestrze (katalogu) usług, oraz może być wyszukana za pomocą standardowego mechanizmu. Usługa WWW może być wywołana za pomocą interfejsu API w sieci. Główną zaletą serwisów WWW jest możliwość zjednoczenia możliwości funkcjonalnych dla niekompatybilnych systemów informatycznych np. J2EE oraz.net, którzy mogą być rozproszone na różnych hostach sieci. 145

146 Dla uruchomienia serwisu WWW oraz przekazania parametrów wejściowych trzeba wykorzystać odpowiednie standardowe protokoły HTTP. Serwis WWW to jest czarna skrzynia zawierająca komplikowane możliwości funkcjonalne z prostym interfejsem. Dostęp do serwisów WWW może być zrealizowany przez protokoły standardowe WWW. W środowisku.net Framework Web Serwis może być zrealizowany w postaci obiektu COM, który oprócz binarnych ma dodatkowe interfejsy obsługiwania zapytań HTTP. Standardowymi protokółami WWW są : HTTP-Get protokół umożliwiający klientom komunikację z serwerami przy użyciu protokołu HTTP. Klient przesyła na serwer żądania HTTP dotyczące zasobu o konkretnym adresie URL, a serwer w odpowiedzi zwraca odpowiedni kod HTML. Wszelkie parametry konieczne do prawidłowego obsłużenia żądania są dołączone do adresu URL jako łańcuch zapytania w postaci par nazwa-wartość. Serwisy sieci WWW mogą wykorzystywać żądania HTTP-Get i łańcuch zapytania do przesyłania poleceń i zwracania wyników, zamiast komunikatów zapisanych w języku XML. Informacje przesyłane w ten sposób stanowią część adresu URL. Protokół ten ma ograniczone możliwości, gdyż umożliwia przesyłanie wyłącznie par nazwa-wartość. HTTP-Post protokół ten przypomina HTTP-Get, lecz różni się od niego tym, iż informacje nie są przekazywane w formie łańcucha zapytania, lecz zapisywane w nagłówkach żądania HTTP. Gdy klient przesyła żądanie przy użyciu tego protokołu, generuje on żądanie HTTP zawierające dodatkowe informacje zapisane w formie par nazwa-wartość w nagłówkach HTTP. Serwer odbierając takie żądanie musi je odczytać z nagłówków oraz przetworzyć, aby określić nazwy parametrów oraz ich wartości. Protokół ten jest najczęściej wykorzystywany przy przesyłaniu formularzy HTML. Możliwości tego protokołu, podobnie jak poprzedniego, ograniczają się jedynie do przesyłania par nazwa-wartość. SOAP (Simple Object Access Protocol) prosty protokół dostępu do obiektów w odróżnieniu od poprzednich protokołów przesyła informacje w formie XML. Oznacza to, że przy użyciu tego protokołu można przesyłać nie tylko proste pary nazwa-wartość, lecz także znacznie bardziej skomplikowane obiekty, takie jak złożone typy danych, klasy obiekty itp. Protokół SOAP jest nadbudową nad HTTP, to oznaczy, że wykorzystuje HTTP, jednak jego działanie nie ogranicza się do modelu żądanie-odpowiedż. Ponieważ protokół ten bazuje się na języku XML, można go wykorzystywać do przesyłania informacji za pośrednictwem WWW bez ograniczeń. Demonstracja działania serwisów Web D:\2310B\Media\2310B_13A001.htm Na rys. 44 jest pokazany ogólny schemat poszukiwania i rejestracji usługi WWW zgodnie ze standardem UDDI(Universal Description Discovery and Integration). Ten schemat zawiera następne czynności: 1. Publikacja w katalogu UDDI (w formacie XML) URL deskryptora.disko serwisu WWW. Deskryptor.disko to jest plik w formacie XML, który zawiera odwołania URL do resursów serwisu WWW. 2. Znajdowanie klientem w katalogu UDDI przez przeglądarkę UDDI URL deskryptora.disko serwisu WWW. 3. Odczytanie deskryptora.disko, który zawiera lokalizacje usług WWW w postaci URL. 4. Odczytanie pliku.wsdl do generacji klasy proxy usługi WWW. 5. Generacja klasy proxy oraz ustalenie połączenie z klasą usługi WWW. 6. Wywołanie usługi WWW przez klasę proxy, przekazanie ją parametrów oraz otrzymanie z powrotem rezultatów. 146

147 Rys.44 Te kroki są niezbędne, kiedy projektant nie wie, gdzie jest lokalizowana usługa WWW. W przypadku, kiedy użytkownik dokładnie wie URL serwisu WWW można bezpośrednio odczytać deskryptor.disko tej usługi bez wykorzystania protokołu UDDI. WWW serwis może być stworzony w środowisku VS.NET w sposób podobny do stworzenia projektu aplikacji ASP.NET. W tym przypadku przy wywołaniu trybu New Project w VS.NET w oknie Templates zamiast ikony ASP.NET Web Applikcation trzeba wybrać ASP.NET Web Service. Środowisko VS.NET tworzy się komponenty projektu do WWW serwisu. Projekt serwisu WWW zawiera pliki Web.config, Global.asax oraz plik Serwis_Name.asmx z kodem serwisu. Kod pliku.asmx zawiera wszystkie niezbędne definicji do stworzenia klasy WWW serwisu. Sam serwis jest zawarty w pliku.dll katalogu bin projektu. Przykład kodu WWW serwisu jest pokazany w listingu Service1.asmx. (Projekty ClientWebService1, WebService1, WebServiceCalculator) Listing Service1.asmx. 1. Imports System.Web.Services 2. <System.Web.Services.WebService(Namespace := " _ 3. Public Class Service1 4. Inherits System.Web.Services.WebService 5. #Region " Web Services Designer Generated Code " 6. #End Region 7. ' WEB SERVICE EXAMPLE 8. ' The HelloWorld() example service returns the string Hello World. 9. ' To build, uncomment the following lines then save and build the project. 10. ' To test this web service, ensure that the.asmx file is the start page 11. ' and press F ' 13. '<WebMethod()> _ 14. 'Public Function HelloWorld() As String 15. ' Return "Hello World" 147

148 16. 'End Function 17. <WebMethod()> _ 18. Public Function TestString(ByVal x As String) As String 19. TestString = _ 20. "TestString received the following as input: " & x 21. End Function 22. <WebMethod()> _ 23. Public Function TestMath(ByVal y As Integer, ByVal z As _ 24. Integer) As Integer 25. TestMath = y + z 26. End Function 27. End Class Wszystkie metody serwisów WWW mają atrybut <WebMethod()>. W liniach 7-16 są pokazane instrukcji dla stworzenia metod serwisów WWW na przykładzie znanej metody HelloWorld(). W liniach jest stworzona przykładowa metoda serwisu WWW TestString(ByVal x As String),w postaci funkcji, która dodaje do argumentu wejściowego x następny tekst: "TestString received the following as input: ". Ten tekst razem ze zmiennej wejściowej x będzie z powrotem odesłany do strony, która wywołała ten serwis. W liniach jest zdefiniowana metoda WWW serwisu TestMath(ByVal y As Integer, ByVal z As Integer), która realizuje operację sumy argumentów. Serwis można protestować bez aplikacji wywołującej ten serwis. Dlatego trzeba uruchomić plik.asmx w przeglądarce. Będą wyświetlane linki do deskryptora serwisu w postaci pliku WSDL (Web Services Description Language) oraz do metod serwisu. Plik WSDL definiuje interfejs usługi sieciowej, szczegóły wiązania (protokół sieciowy, wymagania związane z kodowaniem danych) oraz jej umiejscowienie w sieci. Ten plik jest potrzebny dla stworzenia klasy proxy usługi WWW na stronie klienta. Testować usługę WWW można i bez strony klienta. W tym przypadku przy testowaniu serwisu WWW jest wykorzystany protokół HTTP oraz nie jest potrzebny protokół SOAP. Klikniejcie linka spowoduje wywołanie odpowiedniej metody usługi WWW i przekazanie do tej metody wprowadzonego lub wprowadzonych parametrów. Jeśli wewnątrz metody zostanie wygenerowany błąd, to komunikat o błędzie zostanie wyświetlony na stronie. Jeśli metoda zostanie wykonana bez błędu, na stronie zostanie wyświetlona wartość zwrócona przez tę metodę w postaci znaczników XML. Kod strony klienta jest pokazany w listingu WebForm1.aspx.vb. Listing WebForm1.aspx.vb 1. Public Class WebForm1 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub ButtonA_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButtonA.Click 6. Dim objservice As New ClientWebService1.localhost.Service1 7. Me.Label1.Text = objservice.teststring(me.textbox1.text) 8. End Sub 9. Private Sub ButtonB_Click1(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButtonB.Click 10. Dim objservice As New ClientWebService1.localhost.Service1 11. If (Me.TextBox2.Text <> "") And (Me.TextBox3.Text <> "") Then 12. Me.Labelrezult.Text = "Rezultat = " + _ 13. objservice.testmath(ctype(me.textbox2.text, Integer), _ 14. CType(Me.TextBox3.Text, Integer)).ToString 15. End If 16. End Sub 17. End Class 148

149 Dodawanie klasy proxy do strony klienta może być zrealizowane w projekcie VS.NET przez opcję menu Add Web Reference. Na rys.45 jest pokazana zawartość metod klasy proxy serwisu WWW Service1 w Object Browser VS.NET. Ta klasa oprócz podstawowych metod TestMath() oraz TestString() zawiera metody typu BeginXXX oraz EndXXX. Te metody mogą być wykorzystane do uruchomienia serwisu WWW w trybie asynchronicznym. Rys.45 Tryb synchroniczny został wykorzystany w poprzednim listingu. Wywołanie synchroniczne musi powstrzymać realizację aplikacji klienta na termin oczekiwania realizacji serwisu WWW. W trybie asynchronicznym aplikacja może kontynuować pracę. Przykład wykorzystania serwisu WWW TestMath w trybie asynchronicznym dla poprzedniego przykładu jest pokazany w listingu WebForm1.aspx.vb (tryb asynchroniczny). Listing WebForm1.aspx.vb(tryb asynchroniczny). 1. Public Class WebForm1 2. Inherits System.Web.UI.Page 3. #Region " Web Form Designer Generated Code " 4. #End Region 5. Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 6. End Sub 7. Private Sub ButtonA_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButtonA.Click 8. Dim objservice As New ClientWebService1.localhost.Service1 9. Me.Label1.Text = objservice.teststring(me.textbox1.text) 10. End Sub 11. Private Sub ButtonB_Click1(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButtonB.Click 12. Dim objservice As New ClientWebService1.localhost.Service1 13. 'asynchroniczny tryb WWW serwisu(1 linia): 14. Dim ar As IAsyncResult 15. ' koniec kodu asynchronicznego If (Me.TextBox2.Text <> "") And (Me.TextBox3.Text <> "")_ 17. Then 18. 'asynchroniczny tryb WWW serwisu(3 linii): 19. ar = objservice.begintestmath _ 20. (CType(Me.TextBox2.Text, Integer),_ 21. CType(Me.TextBox3.Text,Integer), Nothing, Nothing) 149

150 22. ar.asyncwaithandle.waitone() 23. Me.Labelrezult.Text = "Rezultat = " + _ 24. objservice.endtestmath(ar).tostring 25. ' koniec kodu asynchronicznego ' synchroniczny tryb WWW serwisu (2linii): 27. ' Me.Labelrezult.Text = "Rezultat = " +_ 28. ' objservice.testmath(ctype(me.textbox2.text, Integer), _ 29. ' CType(Me.TextBox3.Text, Integer)).ToString 30. ' koniec kodu synchronicznego End If 32. End Sub 33. End Class W linii 14 procedury ButtonA_Click()jest zadeklarowana zmienna obiektowa ar klasy IAsyncResult. Egzemplarz tej klasy został stworzony w linii za dopomogą metody BeginXXX() klasy proxy objservice. Metoda BeginXXX() w tym przypadku ma cztery parametry: pierwszy dwa wyznaczają parametry wejściowe x oraz y dla serwisu WWW, trzeci parametr wyznacza odwołanie do obiektu AsyncCallback oraz parametr czwartyodwołanie do stworzonej klasy proxy usługi WWW. Parametry trzeci i czwarty nie są w tym przypadku potrzebne oraz dlatego zostali ustalone wartości Nothing. W linii 22 metoda WaitOne() ustali się tryb oczekiwania równoległych procesów klientem usługi WWW. W tym przypadku trzeba czekać zakończenia jednego procesu skojarzonego z metodą TestMath(). W liniach metoda EndTestMath() wraca rezultaty. Technologia AJAX w ASP.NET. Technologia AJAX ( Asynchronous JavaScript and XML asynchroniczny kod JavaScript oraz XML) łączy w sobie szereg innych technologii : HTML(XHTML) i CSS do tworzenia interfejsu użytkownika Model DOM (Document Object Model) brousera klienta do obsługi elementów dynamicznych i interakcji Obiektu XMLHttpRequest (XHR) do asynchronicznej wymiany danych. Główna idea technologii AJAX polega w tym, że oddzielne elementy interfejsu klienta w przeglądarce internetowej mogą być uaktualnieni przez wykonanie asynchronicznych wywołań, zapytań do innych stron czy serwisów WWW bez konieczności obrazowania i uaktualnienia innych elementów interfejsu. Innymi słowy jest możliwe otrzymanie danych na stronie klienta bez konieczności powtórnego przeładowania całej strony. Dla zrozumienia zasad technologii AJAX trzeba rozpatrzyć następne poziomy realizacji tej technologii: Wykorzystanie obiektu XMLHttpRequest dla asynchronicznej wymiany danych. Wykorzystanie API Script Callback (zwrotne wywołania stron). Wykorzystanie kontrolek biblioteki MS ASP.NET 2.0 AJAX. 1.Wykorzystanie obiektu XMLHttpRequest dla asynchronicznej wymiany danych. Obiekt XMLHttpRequest jest głównym w technologii AJAX. Po raz pierwszy ten obiekt został zaimplementowany w IE 5.0. Obiekt XMLHttpRequest powstał na pobieranie stron WWW z serwera za pomocą metody GET lub wysyłanie do serwera żądania za pomocą metody POST. Dla uruchomienia metod i wykorzystania właściwości XHR trzeba stworzyć instancję obiektu w kodzie JScript klienta. W przypadku, kiedy obiekt jest zaimplementowany do przeglądarki właściwość window.xmlhttprequest= true. W innym przypadku trzeba uruchomić komponent COM Microsoft.XMLHttp. Trzeba zauważyć, że przy wykorzystaniu bibliotek AJAX oraz narzędzi implementowanych do VS2005 nie będzie potrzeby bezpośrednio tworzyć ten obiekt w kodach programowych. Wyższe nazwane programowe środowisko realizuje niezbędne funkcje tego obiektu w sposób przezroczysty dla programisty. Aczkolwiek rozpatrzenie zasad wykorzystania tego obiektu jest polecane dla 150

151 lepszego zrozumienia technologii AJAX. W tablice 1 są pokazane metody obiektu XMLHttpRequest. Tablica 1. Metoda (parametry) Opis abort() Anuluje aktualne żądanie HTTP getallresponseheader () Pobiera wartości wszystkich nagłówków HTTP getallresponseheader Pobierany zostanie wyznaczony nagłówek (header) open (metod,url,asynch, username,password) Zainicjalizowane zostanie żądanie do serwera. Pierwszy parametr metoda polecenia: PUT,GET, POST. Drugi parametr URL polecenia. Trzeci (opcjonalny) typ polecenia (synchroniczny lub asynchroniczny). Czwarty oraz piąty są opcjonalne, przeznaczone dla chronionych stron. send (content) Wysyła żądanie do serwera i odbiera odpowiedź. setrequestheader Ustalenie wartości klucza nagłówka. (Musi być wcześniej (header,value) sformowana metoda open().) W tablice 2 są pokazane właściwości obiektu XMLHttpRequest. Tablica 2. Właściwość Opis onreadystatechange Jest wyznaczona metoda dla obsługiwania zdarzeń przy każdej zmianie stanu polecenia readystate Zwraca stan aktualnego żądania. Są dostępne następne wartości: 0- żądanie nie zostało zainicjalizowane, 1 trwa lądowanie, 2- lądowanie zakończone, 3 interaktywny, 4 gotowy (complete). responsetext Odpowiedź serwera w wyglądzie tekstu z łańcuchem znaków responsexml Odpowiedź serwera w wyglądzie obiektu XML. Ten obiekt może być weryfikowany oraz parserowany jako komponent DOM. status StatusText Kod statusu protokołu HTML, np. 200 OK. Nazwa kodu statusu HTML w wyglądzie łańcucha tekstu W listingu HTMLPage.htm (projekt AJAX1) jest pokazany kod strony JScript gdzie jest wykorzystany obiekt XMLHttpRequest. Strona zawiera przycisk typu button. Naciśniecie przycisku powoduje uruchomienie na serwerze metody formującej komunikat Hello World, który będzie wyświetlany na stronie bez konieczności przeładowania strony. Listing HTMLPage.htm 1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " 2. <html xmlns=" > 3. <head> 4. <title>simple XMLHttpRequest page</title> 5. <script type="text/javascript"> 6. var xmlhttp; 7. function createxmlhttprequest () 8. { 9. if (window.activexobject) 10. { 11. xmlhttp = new ActiveXObject ("Microsoft.XMLHttp"); 12. } 151

152 13. else if (window.xmlhttprequest) 14. { 15. xmlhttp = new XMLHttpRequest (); 16. } 17. } 18. function startrequest() 19. { 20. createxmlhttprequest(); 21. xmlhttp.onreadystatechange = handlestatechange; 22. xmlhttp.open ("GET","Handler.ashx", true); 23. // xmlhttp.send(null); 24. xmlhttp.send(); 25. } 26. function handlestatechange() 27. { 28. if (xmlhttp.readystate ==4) 29. { 30. if (xmlhttp.status ==200) 31. { 32. alert ("Server odpowiada: " + xmlhttp.responsetext); 33. } 34. } 35. } 36. </script> 37. </head> 38. <body> 39. <input type=button value= "Startuj asynchroniczna wymiane danych " onclick = "startrequest();" 40. /> 41. </body> 42. </html> W linii 39 jest wyznaczona funkcja klienta startrequest(), która będzie uruchomiana przy klikniejciu przycisku Startuj... na s przeglądarce. Funkcja StartReqest () w linii 20 uruchomi funkcję createxmlhttprequest ()(linie 7-17).W liniach 11 lub 15 został stworzony obiekt XMLHttpRequest. W linii 21 do obrabiania zdarzeń obiektu XMLHttpRequest na poziomie klienta została podłączona funkcja z nazwą handlestatechange(). Ta funkcja będzie monitorować stany obiektu XHR. W Linii 22 zostanie przekazane polecenie GET do strony Handler.ashx na serwerze, która zawiera metodę dla obsługiwania zdarzeń. Funkcja handlestatechange() jest wyznaczona w liniach W linii 28 dla stanu obiektu XMLHttpRequest readystate sprawdzamy czy jest zakończona już operacja ( xmlhttp.readystate ==4). Strona MyHandler.ashx jest przeznaczona dla obsługiwania zdarzenia i została stworzona w VS2005 jako plik typu handler (Generic Handler). Kod tego pliku jest pokazany w listingu MyHandler.ashx. Listing MyHandler.ashx. <%@ WebHandler Language="VB" Class="Handler" %> Imports System Imports System.Web Public Class Handler : Implements IHttpHandler Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest context.response.contenttype = "text/plain" context.response.write(" Hello World ") End Sub 152

153 Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable Get Return False End Get End Property End Class Przy realizacji metody GET metoda ProcessRequest() klasy Handler zwraca dokument typu text/plain z łańcuchem znaków Hello World. 2.Wykorzystanie API Script Callback (zwrotne wywołania stron). ASP.NET 2.0 zawiera integrowany API który nazywa się ASP.NET Script Callback. Ten interfejs może być wykorzystany dla realizacji poza strefowych wywołań klienta do stron aplikacji WWW. Wywołanie poza strefowe nie jest zwykłym poleceniem protokołu HTTP. Żądanie w tym przypadku poczyna się na stronie klienta i powoduje zdarzenie. Stan początkowy strony klienta jest przekazany do strony serwera. Dodatkowa informacja jest przekazana przez pola dodatkowe. Na serwerze działa zwykły konwejer obrabiania zdarzeń strony serwera. Natomiast w tym konwejerze nie ma fazy obrazowania strony - fazy prerendering. Zamiast tej fazy będzie uruchomiana metoda CallBack na serwerze. Rezultaty metody zostaną serializowane oraz przekazane z powrotem do odpowiedniej funkcji CallBack klienta. Faza obrazowania oraz faza pre-rendering nigdy nie będą uruchomiane w tym interfejsu. Rozpatrzymy szczegółowo wykorzystanie API Script Callback. Zdarzenie na stronie klienta uruchomi się funkcję JScript z sygnaturą WebForm_DoCallback. Ta funkcja jest przeznaczona dla obrabiania zdarzenia na poziomie klienta oraz automatyczne dodawana jest do strony klienta. Funkcja WebForm_DoCallback ma następny stereotyp : WebForm_DoCallBack (pageid, argument, clientcallback, context, errorcallback, useasync); gdzie: pageid ID strony, która realizuje żądanie na serwerze; argument argument w formacie String, który jest przekazany do serwera; clientcallback sygnatura funkcji JavaScript na stronie klienta, która otrzyma zwrotnie wywołanie od serwera; context dani, którzy będą przekazane do clientcallback; errorcallback sygnatura funkcji na stronie klienta która będzie uruchomiana przy błędach na poziomie serwera; useasync kiedy = true, wywołanie realizuje się w sposób asynchroniczny. Funkcja WebForm_DoCallback skojarzona jest z kontrolką powodującej zdarzenie AJAX. Niżej pokazane są linie kodu dla kontrolki DropDownList gdzie wyznaczony jest warunek wywołania funkcji onchange.... <select name="ddlmanufacturers" id="ddlmanufacturers" onchange="webform_docallback(' Page',document.all['ddlManufacturers'].options(docum ent.all['ddlmanufacturers'].selectedindex).value,callbackfunction,'callbackcontext',null,false );return false;"> <option value="mercedes">mercedes</option> <option value="bmw">bmw</option> <option value="renault">renault</option> <option value="toyota">toyota</option> <option value="daewoo">daewoo</option> 153

154 Funkcja WebForm_DoCallback tworzy obiekt XMLHttpRequest oraz realizuje wszystkie żądania protokołu HTTP. Scenariusz skryptu WebForm_DoCallback jest przechowywany w zespole system.web.dll oraz będzie połączony ze stroną przez następne dyrektywę : <script src="/ajax_1/webresource.axd?d=psglmi0gsjsla481o_78hw2&t= " type="text/javascript"> </script> Trzeba wiedzieć że kiedy wywołania poza strefowe są skojarzone z przyciskami, to przycisk powodujący wywołanie WebForm_DoCallback nie może mieć typ submit button. Dla przycisku typu submit zostanie zrealizowane zwykłe przesyłanie formularzy oraz wywołania wszystkich zdarzeń strony na poziomie serwera bez realizacji technologii AJAX. Klasy interfejsu API Script Callback inkapsulują odwołania do obiektu XmlHttpRequest. W kodzie programu nie musi stworzony ten obiekt, wykorzystanie XmlHttpRequest jest przezroczystym. Strona serwera musi realizować interfejs System.Web.UI.IcallbackEventHandler: Partial Class CallBacksite Inherits System.Web.UI.Page : Implements System.Web.UI.ICallbackEventHandler W interfejsie IcallbackEventHandler są dwie metody: GetCallbackRezult() oraz RaiseCallbackEvent(eventArgument as string). Metoda RaiseCallbackEvent(eventArgument as string) jest wywołana pierwszej. W tej metodzie muszą być realizowane czynności przygotowawcze. Otrzymane od klienta dani muszą być deserializowane. Metoda GetCallbackRezult() jest wywołana dla zwrotnego przesyłania danych do strony klienta. Listing CallBacksite zawiera kod strony serwera. W liniach 5-14 oraz są zdefiniowane funkcje GetCallbackRezult() oraz RaiseCallbackEvent(). W linii 3 jest wyznaczony parametr evarg który będzie zawierał wartość pola kontrolki DropDownList od klienta. W linii 24 jest zdefiniowana zmienna argclientfunction, która jest przeznaczona dla formowania w linii 27 drugiego argumentu funkcji WebForm_DoCallBack(). Ciała sygnatura funkcji WebForm_DoCallBack() będzie sformowana w zmiennej cscript w linii 28. Kod funkcji CallBackFunction() klienta jest sformowany w zmiennej scr w liniach Dla przeniesienia tej sygnatury do klienta jest wykorzystana metoda RegisterStartupScript () w linii 48. Zadaniem funkcji CallBackFunction() klienta jest deserializacja danych i ustalenie nowego stanu drugiej kontrolki DropDownList. Listing CallBacksite. 1. Partial Class CallBacksite 2. Inherits System.Web.UI.Page : Implements System.Web.UI.ICallbackEventHandler 3. Protected evarg As String 4. #Region "ICallbackEventHandler Members" 5. Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult 6. 'Throw New Exception("The method or operation is not implemented") 7. BindModels(evArg) 8. evarg = String.Empty 9. Dim i As Integer 154

155 10. For i = 0 To ddlmodel.items.count - 1 Step evarg = evarg + ddlmodel.items(i).tostring + ";" 12. Next 13. Return evarg 14. End Function 15. Public Sub RaiseCallbackEvent(ByVal eventargument As String) Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent 16. 'Throw New Exception("The method or operation is not implemented") 17. evarg = eventargument 18. End Sub 19. #End Region 20. Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 21. If Not IsPostBack Then 22. Me.BindManufacturers() 23. End If 24. Dim argclientfunction As String 25. Dim cscript As String 26. Dim scr As String 27. argclientfunction = "document.all['" + ddlmanufacturers.clientid + "'].options(document.all['" + ddlmanufacturers.clientid + "'].selectedindex).value" 28. cscript = ClientScript.GetCallbackEventReference(Me, argclientfunction, "CallbackFunction", "'CallbackContext'", "null", False) 29. ddlmanufacturers.attributes.add("onchange", cscript + ";return false;") 30. scr = "<script language=javascript>" 31. scr += "function CallbackFunction(callbackResult, callbackcontext)" 32. scr += "{" 33. scr += " var ddlmodel = document.all['" + ddlmodel.clientid + "'];" 34. scr += " var l = ddlmodel.options.length;" 35. scr += " for(var i=0; i<l; i++)" 36. scr += " ddlmodel.options.remove(0);" 37. scr += " var models = callbackresult.split(';');" 38. scr += " for(var i=0; i<models.length; i++)" 39. scr += " {" 40. scr += " var ooption = document.createelement(""option"");" 41. scr += " ooption.text = models[i];" 42. scr += " ooption.value = models[i];" 43. scr += " ddlmodel.options.add(ooption);" 44. scr += " }" 45. scr += " return false;" 46. scr += "}" 47. scr += "</script>" 48. Me.RegisterStartupScript("scr" + Me.ClientID.ToString, scr) 49. End Sub 50. Sub BindManufacturers() 51. ddlmanufacturers.items.add(new ListItem("Mercedes")) 52. ddlmanufacturers.items.add(new ListItem("BMW")) 53. ddlmanufacturers.items.add(new ListItem("Renault")) 54. ddlmanufacturers.items.add(new ListItem("Toyota")) 55. ddlmanufacturers.items.add(new ListItem("Daewoo")) 56. End Sub 155

156 57. Sub BindModels(ByVal manufacturer As String) 58. Select Case manufacturer 59. Case "Mercedes" 60. ddlmodel.items.clear() 61. ddlmodel.items.add(new ListItem("S350")) 62. ddlmodel.items.add(new ListItem("S500")) 63. ddlmodel.items.add(new ListItem("S600")) 64. ddlmodel.items.add(new ListItem("CLK")) 65. 'break() 66. Case "BMW" 67. ddlmodel.items.clear() 68. ddlmodel.items.add(new ListItem("model 3")) 69. ddlmodel.items.add(new ListItem("model 5")) 70. ddlmodel.items.add(new ListItem("model 7")) 71. ddlmodel.items.add(new ListItem("X3")) 72. ddlmodel.items.add(new ListItem("X5")) 73. 'break() 74. Case "Renault" 75. ddlmodel.items.clear() 76. ddlmodel.items.add(new ListItem("12")) 77. ddlmodel.items.add(new ListItem("19")) 78. ddlmodel.items.add(new ListItem("21")) 79. 'break; 80. Case "Toyota" 81. ddlmodel.items.clear() 82. ddlmodel.items.add(new ListItem("Aristo")) 83. ddlmodel.items.add(new ListItem("Avalon")) 84. ddlmodel.items.add(new ListItem("Avensis")) 85. ddlmodel.items.add(new ListItem("Bandeirante")) 86. 'break; 87. Case "Daewoo" 88. ddlmodel.items.clear() 89. ddlmodel.items.add(new ListItem("Sens")) 90. ddlmodel.items.add(new ListItem("Lanos")) 91. 'break; 92. End Select 93. End Sub 94. End Class Wykorzystanie kontrolek biblioteki MS ASP.NET 2.0 AJAX. W celu polepszenia pracy projektanta w API MS ASP.NET 2.0 AJAX są stworzone następne kontrolki: ScriptManager UpdatePanel UpdateProgress Timer Nazwane powyżej kontrolki mogą być rozmieszczone na stronie aspx w sposób podobny innym kontrolkom ASP.NET. Wykorzystanie kontrolek AJAX pozwoli implementować do interfejsu AJAX inne kontrolki ASP.NET w sposób przezroczysty, bez konieczności stworzenia obiektów XMLHttpRequest. W tym przypadku także niema potrzeby tworzyć kody dla metod wywołań zwrotnych. Każda strona aplikacji AJAX musi zostać wyposażona w jeden egzemplarz kontrolki ScriptManager. ScriptManager jest centralnym elementem biblioteki MS ASP.NET 2.0 AJAX oraz implementuje klasy i metody dla zarządzania wszystkimi elementami dostępnymi na 156

157 stronie i pochodzącymi z tejże biblioteki. Ten element koordynuje i rejestruje skrypty na poziomie klienta odpowiedzialne za częściowe odświeżanie strony. Na rys.1 są pokazane kontrolki używane w projekcie aplikacji AJAX. Właściwości kontrolki ScriptManager jest pokazane na rys. 2. Trzeba zwrócić uwagę na właściwość EnablePartialRendering, która umożliwia korzystanie z technologii AJAX na stronie. Rys.1 157

158 Rys.2 158

159 Kontrolka UpdatePanel realizuje implementację mechanizmów częściowego odświeżania strony, dzięki czemu możliwe jest ograniczenie czasu ponownego lądowania strony. UpdatePanel jest kontrolką będącą kontenerem elementów podlegających dynamicznemu odświeżaniu na stronie. Na rys.3 są pokazane właściwości kontrolki UpdatePanel1 w projekcie. Rys.3 Każda kontrolka UpdatePanel zawiera szablon ContentTemplate, widoczny tylko w kodzie XML Script projektu. Ten szablon stanowi kontener kontrolek podlegających dynamicznemu odświeżaniu strony. Dodawanie kontrolek do tej strefy polega na przeciągnięciu odpowiedniego elementu z panelu narzędzi do panelu kontrolki UpdatePanel. Wykorzystanie kontrolki UpdatePanel jako wyznaczonego obszaru elementów interfejsu strony, dynamiczne odświeżanych bez potrzeby ponownego ładowania strony jest powiązane z procesem dodawania kontrolek bezpośrednio do szablonu ContentTemplate. Wszystkie zdarzenia generowane przez kontrolki będące częścią UpdatePanelu nie powodują ponownego przeładowania calej strony ich działanie odnosi się tylko do panelu. Kontrolka UpdatePanel zawiera kolekcję Triggers. Tryger odpowiada zdarzeniu które powoduje odświeżanie panelu. Trygery mogą być dwóch typów: AsyncPostBackTrigger PostBackTrigger Na rys. 4 jest pokazane okno dla definicji trygerów. Bardzo ważnym rzeczą, jest rodzaj reakcji kontrolki UpdatePanel na odświeżanie strony, której częścią jest dany egzemplarz klasy UpdatePanel. Zachowanie to zależy od wartości właściwości UpdateMode i przedstawia się następująco: 1. Jeśli wartość właściwości UpdateMode jest ustawiona na Always (wartość po domyśleniu), zawartość panelu odświeżana jest każdorazowo w sytuacji gdy następuje ponowne ładowanie calej zawartości strony zawierającej kontrolkę UpdatePanel. 2. Jeśli wartość właściwości UpdateMode jest ustawiona na Conditional, zawartość panelu odświeżana jest w następujących okolicznościach: Wywoływana jest metoda Update() panelu. Wywołanie powodowane jest przez kontrolkę definiowaną jako trigger. 159

160 Rys. 4. AsyncPostBackTrigger definiuje zdarzenie odświeżania panelu, które związane jest z kontrolką nie będącą częścią tego panelu. Wywołanie zdarzenia przypisanego do trygeru dokonuje zmian wewnątrz panelu i nie generuje zdarzenia PostBack strony. Zdarzeniem kontrolki powodującej odświeżanie zawartości panelu, może być np. kontrolka Button i zdarzenie Click_Button. PostBackTrigger - definiuje zdarzenie odświeżania panelu oraz generuje zdarzenie PostBack strony. W następnym listingu jest pokazany kod XML Script projektu. <html xmlns=" <head runat="server"> <title>ajax</title> </head> <body> <form id="form1" runat="server"> <asp:scriptmanager ID="ScriptManager1" runat="server" /> <div> <asp:updatepanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:gridview ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="UserID" DataSourceID="AccessDataSource1" PageSize="4" AllowPaging="True" BackColor="#FFE0C0" BorderColor="Navy" BorderStyle="Groove"> <Columns> <asp:boundfield DataField="UserID" HeaderText="UserID" InsertVisible="False" ReadOnly="True" SortExpression="UserID" > <HeaderStyle BackColor="#FFC0FF" /> </asp:boundfield> <asp:boundfield DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" /> <asp:boundfield DataField="LastName" HeaderText="LastName" SortExpression="LastName" /> 160

161 <asp:boundfield DataField="Address" HeaderText="Address" SortExpression="Address" /> <asp:boundfield DataField="City" HeaderText="City" SortExpression="City" /> <asp:boundfield DataField="State" HeaderText="State" SortExpression="State" /> <asp:boundfield DataField="ZIP" HeaderText="ZIP" SortExpression="ZIP" /> <asp:boundfield DataField="Phone" HeaderText="Phone" SortExpression="Phone" /> </Columns> <HeaderStyle BackColor="#FFC0FF" /> </asp:gridview> <asp:accessdatasource ID="AccessDataSource1" runat="server" DataFile="C:\aspnet\aspnet_bazy_test\banking.mdb" SelectCommand="SELECT [UserID], [FirstName], [LastName], [Address], [City], [State], [ZIP], [Phone] FROM [tblusers]"> </asp:accessdatasource> </ContentTemplate> </asp:updatepanel> </div> <asp:updateprogress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1"> <ProgressTemplate> Pobieram pracownikow... </ProgressTemplate> </asp:updateprogress> <asp:updatepanel ID="UpdatePanel2" runat="server" EnableViewState="False"> <ContentTemplate> Zegarek wewnątrz panelu UpdatePanel :<asp:label ID="Label1" runat="server" Text="Label"></asp:Label> </ContentTemplate> <Triggers> <asp:asyncpostbacktrigger /> </Triggers> </asp:updatepanel> <asp:button ID="Button1" runat="server" Text="Button" /> <asp:label ID="Label2" runat="server" Text="Label" style="left: - 5px; top: -22px" Width="74px"></asp:Label> </form> </body> </html> W następnym listingu pokazany jest kod klasy pośredniej. Partial Class _Default Inherits System.Web.UI.Page Protected Sub GridView1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.PageIndexChanged System.Threading.Thread.Sleep(3000) End Sub Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Me.Label1.Text = DateTime.Now.ToString Me.Label2.Text = "Zegarek z zewnątrz panelu UpdatePanel: " & DateTime.Now.ToString End Sub End Class 161

162 Kontrolka UpdateProgress jest powiązana z kontrolką UpdatePanel i umożliwia wykonywania określonych działań (wcześniej zdefiniowanych przez programistę) podczas odświeżania zawartości panelu. Tymi działaniami mogą być np. wyświetlanie danego tekstu. Elementy, stanowiące zawartość tej kontrolki jak również sama kontrolka nie są widoczne w przeglądarce do czasu rozpoczęcia odświeżania panelu i są widoczny tylko w czasie trwania tego procesu. Powiązanie z kontrolką UpdateProgress może być zrealizowane przez właściwość AssociatedUpdatePanelID. W przypadku, kiedy powiązanie nie zostanie zdefiniowane, czynności wyznaczone w UpdateProgress będą uruchomiane dla każdego elementu UpdatePanel. Technologia Web Parts w ASP.NET Technologia Web Parts jest zintegrowaną częścią ASP.NET 2.0 udostępnianą poprzez zestaw kontrolek serwerowych, które pozwalają użytkownikowi dostosować wygląd strony do własnych upodobań. Można modyfikować: Zawartość użytkownik może określić, które elementy mają być widoczne na stronie, może je dodawać lub usuwać. Wygląd można zmieniać wygląd kontrolek oraz przenosić je w inne miejsce strony (drag-and-drop) Zachowanie poprzez specjalnie zdefiniowane właściwości można określać zachowanie kontrolek, Wszystkie te ustawienia są ściśle związane z mechanizmem personalizacji. Wprowadzone modyfikacje zapisywane są w odpowiedniej strukturze tabel wygenerowanych podczas konfiguracji ASP.NET. Kontrolki Web Parts są to dowolne kontrolki dostępne w ASP.NET, umieszczone w odpowiednich strefach, tzw. Zones. Komponenty Web Parts WebPartManager zarządza wszystkimi elementami Web Parts na stronie. Nie posiada on interfejsu graficznego i nie jest widoczny dla użytkownika. WebPartZone przechowuje widoczne elementy Web Parts, określa ich domyślny układ oraz zachowanie. Umożliwia użytkownikowi przenoszenie kontrolek do innych stref typu WebPartZone EditorZone zawiera edytor dla poszczególnych elementów WebParts, widoczny dopiero po przełączeniu strony w tryb edycji CatalogZone zawiera elementy opcjonalne, które początkowo nie są widoczne ale mogą zostać dodane do wybranej strefy WebPartZone. Podobnie jak 162

163 EditorZone strefa ta nie jest widoczna domyślnie, a dopiero po przełączeniu w odpowiedni tryb ConnectionsZone umożliwia tworzenie połączeń pomiędzy elementami Web Parts Rys. 1 Przykładowy układ elementów WebParts na stronie Dostępne tryby pracy z elementami Web Parts: Browse - normalne przeglądanie strony, bez dodatkowych opcji Design umożliwia zarządzanie układem elementów na stronie, Editor w tym trybie można edytować właściwości wybranych elementów Catalog umożliwia pokazanie bądź ukrycie elementów dodatkowych, domyślnie ukrytych Connect edycja połączeń pomiędzy elementami Dostęp do poszczególnych trybów zależy od uprawnień przypisanych danemu użytkownikowi. Są dwa rodzaje zasięgu personalizacji: UserScope domyślny dla wszystkich zalogowanych użytkowników, zmiany wprowadzone w tym trybie dotyczą tylko jednego użytkownika i nie są widoczne przez innych. 163

164 SharedScope dostępny dla użytkowników którym przydzielono prawa do tego trybu, wprowadzone zmiany widoczne są przez wszystkich użytkowników; tryb ten umożliwia administratorom systemu edycję i dostosowanie układu stron całego portalu. Etapy tworzenia strony wykorzystującej Web Parts. Dla lepszego zobrazowania elementów Web Parts przedstawione zostaną kolejne etapy tworzenia strony wykorzystującej Web Parts. Całość przykładowej aplikacji znajduje się na dołączonej płycie CD. Utworzenie pustej strony strona ta zostanie wykorzystana do prezentacji możliwości Web Parts Uruchomienie Microsoft Visual Studio Wybranie opcji New Web Site z menu File Wybranie typu projektu jako ASP.NET Web Site, a język programowania C# podanie nazwy i lokalizacji dla strony i OK Przygotowanie strony ustwienie układu graficznego strony i przygotowanie miejsca gdzie będą dodawane kolejne elementy Otwarcie pliku Default.aspx trybie Design Wstawienie tabeli opcja Layout->Insert Table, tabela o 3 wierszach i 3 kolumnach, szerokość tabeli 100% Przygotowanie układu strony połączenie kolumn w wierszu 1. oraz 2. (opcja Merge Cells w menu kontektowym), dodanie do pierwszego wiersza etykiety z tytułem strony Kod tabeli: 164

165 <table style="width: 100%;"> <tr> <td align="left" colspan="3" style="background-color: steelblue;"> <asp:label ID="lblHeader" runat="server" ForeColor="Cyan" Text="Web Parts test" Font-Bold="True" Font-Names="Verdana" Font-Size="18pt"></asp:Label> </td> </tr> <tr> <td align="right" colspan="3"></td> </tr> <tr> <td></td> <td></td> <td></td> </tr> </table> Dodanie elementu WebPartManager Wybranie z panelu Toolbox komponentu WebPartManager i dodanie go przed tabelą. Komponent ten musi znajdować się na górze strony, przed innymi elementami. Dodanie stref WebPartZone Wybranie z panelu Toolbox komponentu WebPartZone i dodanie go do pierwszej kolumny ostatniego wiersza. Określenie nazwy komponentu jako LeftZone Wybranie jednego ze zdefiniowanych dla niego styli, np.: Professional Dodanie drugiej strefy do trzeciej kolumny ostatniego wiersza, nazwanie jej RightZone i określenie stylu Professional Komponenty WebPartZone będą stanowiły pewnego rodzaju kontenery na poszczególne elementy WebPart 165

166 Dodanie pierwszego elementu WebPart elementami WebParts są dowolne kontrolki dostępne w ASP.NET, a więc zarówno kontrolki serwerowe jak i kontrolki zdefiniowane Dodanie do strefy LeftZone kontrolki Calendar Przełączenie widoku w tryb Source i ustawienie tytułu kontrolki poprzez zdefiniowanie atrybutu Title= Kalendarz dla dodanego komponentu Calendar w <ZoneTemplate> Dodanie kolejnych kontrolek typu WebPart - zdefiniowanie własnych kontrolek, które będą mogły być wykorzystane na stronie Kliknięcie prawym przyciskiem myszy na głównym węźle projektu i wybranie opcji Add New Item z menu kontekstowego Wybranie typu Web User Control i kliknięcie Add Utworzenie przykładowej kontrolki Search.ascx <%@ Control Language="C#" AutoEventWireup="true" CodeFile="Search.ascx.cs" Inherits="Search" %> <table width="100%"> <tr> <td align="right"> <asp:textbox ID="TextBox1" runat="server" Font-Names="Verdana" Font-Size="8pt"> </asp:textbox> </td> </tr> <tr> <td align="right"> <asp:button ID="Button1" runat="server" Font-Names="Verdana" Font-Size="8pt" Text="Szukaj" /> </td> </tr> <tr> <td align="right"> 166

167 <asp:hyperlink ID="HyperLink1" runat="server" Font-Names="Verdana" Font-Size="8pt"> Szukanie zaawansowane</asp:hyperlink> </td> </tr> </table> Utworzenie drugiej kontrolki Ankieta.ascx Control Language="C#" AutoEventWireup="true" CodeFile="Ankieta.ascx.cs" Inherits="WebUserControl" %> <table style="width: 200px"> <tr> <td><asp:label ID="Label1" runat="server" Text="Czy podoba Ci się ASP.NET?" Font- Names="Verdana" Font-Size="8pt"></asp:Label> </td> </tr> <tr> <td style="padding-left: 20px"> <asp:radiobuttonlist ID="RadioButtonList1" runat="server" Font-Names="Verdana" Font- Size="8pt"> <asp:listitem>tak</asp:listitem> <asp:listitem>nie</asp:listitem> <asp:listitem>jeszcze nie wiem</asp:listitem> </asp:radiobuttonlist> </td> </tr> </table> Otworzenie pliku Default.aspx w trybie Design i dodanie nowych kontrolek do strefy RightZone Określenie tytułów tych kontrolek poprzez zdefiniowanie atrybutów Title dla komponentów dodanych do <ZoneTemplate> <asp:webpartzone ID="RightZone"... >... <ZoneTemplate> <uc1:search Title="Szukaj" ID="Search1" runat="server" /> <uc2:ankieta Title="Ankieta" ID="Ankieta1" runat="server" /> </ZoneTemplate> </asp:webpartzone> Uruchomienie strony - Ctrl+F5 167

168 W tym momencie można już minimalizować lub zamykać poszczególne elementy za pomocą menu rozwijanego, tzw. Verbs menu Umożliwienie zmiany trybu pracy z elementami WebParts Dodanie odnośników, za pomocą których będą przełączane tryby modyfikacja drugiego wiersza tabeli na stronie... <tr> <td align="right" colspan="3" style="background-color: gold;"> <asp:linkbutton ID="linkBtnBrowse" ForeColor="Maroon" Text="Browse" style="text-decoration: none" Runat="server" Font-Bold="True" Font-Names="Verdana" Font-Size="8pt" /> <asp:linkbutton ID="linkBtnDesign" ForeColor="Maroon" Text="Design" style="text-decoration: none" Runat="server" Font-Bold="True" Font-Names="Verdana" Font-Size="8pt" /> <asp:linkbutton ID="linkBtnCatalog" ForeColor="Maroon" Text="Catalog" style="text- Decoration: none" Runat="server" Font-Bold="True" Font-Names="Verdana" Font-Size="8pt"/> <asp:linkbutton ID="linkBtn_Edit" ForeColor="Maroon" Text="Edit" style="text-decoration: none" Runat="server" Font-Bold="True" Font-Names="Verdana" Font-Size="8pt"/> <asp:linkbutton ID="linkBtnReset" ForeColor="Maroon" Text="Reset" style="text-decoration: none" Runat="server" Font-Bold="True" Font-Names="Verdana" Font-Size="8pt" /> </td> </tr>... Zdefiniowanie obsługi zdarzenia kliknięcia na poszczególne odnośniki kliknąć dwukrotnie na każdy z odnośników utworzone zostaną metody obsługujące zdarzenia Dodanie odpowiedniego kodu do poszczególnych metod protected void linkbtnbrowse_click(object sender, EventArgs e) { WebPartManager1.DisplayMode = WebPartManager.BrowseDisplayMode; } protected void linkbtndesign_click(object sender, EventArgs e) { WebPartManager1.DisplayMode = WebPartManager.DesignDisplayMode; 168

169 } protected void linkbtncatalog_click(object sender, EventArgs e) { WebPartManager1.DisplayMode = WebPartManager.EditDisplayMode; } protected void linkbtnedit_click(object sender, EventArgs e) { WebPartManager1.DisplayMode = WebPartManager.CatalogDisplayMode; } protected void linkbtnreset_click(object sender, EventArgs e) { PersonalizationAdministration.ResetUserState("~/Default.aspx"); } Uruchomienie strony - Ctrl+F5 Przełączenie w tryb Design (tryby Catalog oraz Edit nie są jeszcze zaimplementowane) Można już zmieniać położenie poszczególnych komponentów łapiąc je i przenosząc w inne miejsce (drag-and-drop) 169

170 Wybranie opcji Reset spowoduje powrót do ustawień początkowych Dodanie komponentu CatalogZone przechowywać on będzie elementy dodatkowe, które mogą być pokazane na stronie, ale nie muszą Wybranie z panelu Toolbox komponentu CatalogZone i dodanie go jednej ze stref, np.: LeftZone, Można zastosować jeden z dostępnych styli graficznych, np.: Professional Zdefiniowanie nowej kontrolki Description.ascx <%@ Control Language="C#" AutoEventWireup="true" CodeFile="Description.ascx.cs" Inherits="PopularLinks" %> <asp:label ID="lblDesc" runat="server" Font-Names="Verdana" Font-Size="8pt" Text="Technologia Web Parts jest zintegrowaną częścią ASP.NET 2.0 udostępnianą poprzez zestaw kontrolek serwerowych, które pozwalają użytkownikowi dostosować wygląd strony do własnych upodobań." Width="199px"></asp:Label> Dodanie komponentu DeclarativeCatalogPart na CatalogZone Dla DeclarativeCatalogPart wybranie opcji EditTemplate i przeciągnięcie kontrolki Description.ascx. Kod dla elementu CatalogZone powinnien wyglądać mniej więcej tak jak poniżej. <asp:catalogzone ID="CatalogZone1"... >... <ZoneTemplate> <asp:declarativecatalogpart ID="DeclarativeCatalogPart1" runat="server"> <WebPartsTemplate> <uc3:description Title="Opis" ID="Description1" runat="server" /> </WebPartsTemplate> </asp:declarativecatalogpart> </ZoneTemplate> </asp:catalogzone> 170

171 Uruchomienie strony - Ctrl+F5 Można teraz zaznaczyć dodatkową kontrolkę i dodać ją do jednej ze stref Elementy dostępne poprzez CatalogZone mogą być usuwane za pomocą opcji w menu (Verbs menu) 171

172 Dodanie komponentu EditorZone umożliwi on edycję wyglądu i zachowania poszczególnych elementów Wybranie z panelu Toolbox komponentu EditorZone i dodanie go jednej ze stref, np.: LeftZone, Można zastosować jeden z dostępnych styli graficznych, np.: Professional Dodanie do EditorZone komponentu AppearanceEditorPart (umożliwi edycję pewnych cech wyglądu Uruchomienie strony - Ctrl+F5 Wybranie trybu Edit Wybranie opcji Edit z menu (Verbs menu) dla danej kontrolki Web Part, np.: dla Szukaj Jak widać istnieje teraz możliwość określenia tytułu kontrolki, stylu oraz rozmiaru. Można, np.: usunąć pasek z tytułem bądź obramowanie. 172

173 Zmiana wyglądu kontrolki określenie nowego tytułu Edycja zdefiniowanych przez użytkownika właściwości Dodanie do EditorZone komponentu PropertyGridEditorPart (służy do edycji specjalnie zdefiniowanych właściwości elementów Web Parts) Określenie edytowalnej właściwości dla kontrolki Description.ascx - aby właściwości kontrolek były edytowalne należy je zdefiniować z atrybutami Personalizable oraz WebBrowsable. Kod pliku Description.ascx.cs powinien wyglądać tak: public partial class UserControls_NewProducts : System.Web.UI.UserControl { private string _desc = ""; [Personalizable(), WebBrowsable, WebDisplayName("Opis")] public string Description { get { return _desc; } set { _desc = value; } } } protected void Page_Load(object sender, EventArgs e) { if (_desc!= "") lbldesc.text = _desc; } Uruchomienie strony - Ctrl+F5 Jeśli element Opis jest niewidoczny, przełączenie w tryb Catalog i dodanie jej do jednej ze stref. Wybranie trybu Edit Wybranie opcji Edit z menu (Verbs menu) dla kontrolki Opis 173

174 Poprzez komponent PropertyGridEditorPart jest możliwość edycji wcześniej zdefiniowanej właściwości. Element Kalendarz został zamknięty (opcja Close w Verbs menu. Zdefiniowanie nowego opisu dla kontrolki Kliknięcie Ok i zmiana trybu na Browse W kontrolce widoczny jest nowy opis zdefiniowany przez właściwość. 174

Instrukcja laboratoryjna cz.3

Instrukcja laboratoryjna cz.3 Języki programowania na platformie.net cz.2 2015/16 Instrukcja laboratoryjna cz.3 Język C++/CLI Prowadzący: Tomasz Goluch Wersja: 2.0 I. Utworzenie projektu C++/CLI z interfejsem graficznym WPF 1 Cel:

Bardziej szczegółowo

4 Web Forms i ASP.NET...149 Web Forms...150 Programowanie Web Forms...150 Możliwości Web Forms...151 Przetwarzanie Web Forms...152

4 Web Forms i ASP.NET...149 Web Forms...150 Programowanie Web Forms...150 Możliwości Web Forms...151 Przetwarzanie Web Forms...152 Wstęp...xv 1 Rozpoczynamy...1 Co to jest ASP.NET?...3 W jaki sposób ASP.NET pasuje do.net Framework...4 Co to jest.net Framework?...4 Czym są Active Server Pages (ASP)?...5 Ustawienia dla ASP.NET...7 Systemy

Bardziej szczegółowo

Podstawy programowania. Wprowadzenie

Podstawy programowania. Wprowadzenie Podstawy programowania Wprowadzenie Proces tworzenia programu Sformułowanie problemu funkcje programu zakres i postać danych postać i dokładność wyników Wybór / opracowanie metody rozwiązania znaleźć matematyczne

Bardziej szczegółowo

- Narzędzie Windows Forms. - Przykładowe aplikacje. Wyższa Metody Szkoła programowania Techniczno Ekonomiczna 1 w Świdnicy

- Narzędzie Windows Forms. - Przykładowe aplikacje. Wyższa Metody Szkoła programowania Techniczno Ekonomiczna 1 w Świdnicy Wyższa Metody Szkoła programowania Techniczno Ekonomiczna 1 w Świdnicy - Narzędzie Windows Forms - Przykładowe aplikacje 1 Narzędzia Windows Form Windows Form jest narzędziem do tworzenia aplikacji dla

Bardziej szczegółowo

2. W oknie dialogowym Choose Toolbox Items w zakładce.net Framework Components naciskamy przycisk Browse...

2. W oknie dialogowym Choose Toolbox Items w zakładce.net Framework Components naciskamy przycisk Browse... KORZYSTANIE Z KONTROLKI.NET LENDEVICERS232 DODAWANIE KONTROLKI DO ZBIORU KOMPONENTÓW DOSTĘPNYCH W PALECIE TOOLBOX (ŚRODOWISKA PROGRAMISTYCZNE FIRMY MICROSOFT) W środowisku programistycznym (Visual C++,

Bardziej szczegółowo

Wybrane działy Informatyki Stosowanej

Wybrane działy Informatyki Stosowanej Wybrane działy Informatyki Stosowanej JSP - Java Server Pages dr hab. inż. Andrzej Czerepicki a.czerepicki@wt.pw.edu.pl http://www2.wt.pw.edu.pl/~a.czerepicki 2019 Aplikacje i skrypty WWW klasyfikacja

Bardziej szczegółowo

Infrastruktura aplikacji WWW

Infrastruktura aplikacji WWW ASP.NET WebForms Infrastruktura aplikacji WWW Gotowe rozwiązania architektoniczne i szkielety aplikacji zwalniają twórców aplikacji z implementacji infrastruktury, zwiększając ich produktywność Stanowy,

Bardziej szczegółowo

Wykład 8: klasy cz. 4

Wykład 8: klasy cz. 4 Programowanie obiektowe Wykład 8: klasy cz. 4 Dynamiczne tworzenie obiektów klas Składniki statyczne klas Konstruktor i destruktory c.d. 1 dr Artur Bartoszewski - Programowanie obiektowe, sem. 1I- WYKŁAD

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Programowanie obiektowe Laboratorium 1. Wstęp do programowania w języku Java. Narzędzia 1. Aby móc tworzyć programy w języku Java, potrzebny jest zestaw narzędzi Java Development Kit, który można ściągnąć

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Laboratorium z przedmiotu Programowanie obiektowe - zestaw 07 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami tworzenia aplikacji okienkowych w C#. Wprowadzenie teoretyczne. Rozważana w

Bardziej szczegółowo

C# 6.0 : kompletny przewodnik dla praktyków / Mark Michaelis, Eric Lippert. Gliwice, cop Spis treści

C# 6.0 : kompletny przewodnik dla praktyków / Mark Michaelis, Eric Lippert. Gliwice, cop Spis treści C# 6.0 : kompletny przewodnik dla praktyków / Mark Michaelis, Eric Lippert. Gliwice, cop. 2016 Spis treści Spis rysunków 11 Spis tabel 13 Przedmowa 15 Wprowadzenie 17 Podziękowania 27 O autorach 29 1 Wprowadzenie

Bardziej szczegółowo

Instrukcja laboratoryjna nr.4

Instrukcja laboratoryjna nr.4 Języki programowania na platformie.net cz.2 2016/17 Instrukcja laboratoryjna nr.4 Język Visual Basic for.net Prowadzący: Tomasz Goluch Wersja: 3.1 I. Współpraca Visual Basic z C# Cel: Wykorzystanie w kodzie

Bardziej szczegółowo

Języki i paradygmaty programowania doc. dr inż. Tadeusz Jeleniewski

Języki i paradygmaty programowania doc. dr inż. Tadeusz Jeleniewski Języki i paradygmaty programowania doc. dr inż. Tadeusz Jeleniewski e-mail: t.jeleniewski@neostrada.pl tadeusz.jeleniewski@pwr.wroc.pl http://www.tjeleniewski.wstt.edu.pl Treści kształcenia: Paradygmaty

Bardziej szczegółowo

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ),

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ), PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ), Program 351203 Opracowanie: Grzegorz Majda Tematyka zajęć 2. Przygotowanie środowiska pracy

Bardziej szczegółowo

MATERIAŁY DO ZAJĘĆ I. Podstawowe pojęcia. Algorytm. Spis treści Przepis

MATERIAŁY DO ZAJĘĆ I. Podstawowe pojęcia. Algorytm. Spis treści Przepis MATERIAŁY DO ZAJĘĆ I Podstawowe pojęcia Spis treści I. Algorytm II. Schemat blokowy III. Struktury danych IV. Program komputerowy V. Opis środowiska programistycznego VI. Obsługa wejścia wyjścia VII. Przykład

Bardziej szczegółowo

Języki i paradygmaty programowania - 1

Języki i paradygmaty programowania - 1 doc. dr inż. Tadeusz Jeleniewski e-mail: t.jeleniewski@neostrada.pl tadeusz.jeleniewski@pwr.edu.pl http://www.tjeleniewski.wstt.edu.pl Cele przedmiotu Umiejętność zastosowania i oceny przydatności paradygmatów

Bardziej szczegółowo

1 Wprowadzenie do J2EE

1 Wprowadzenie do J2EE Wprowadzenie do J2EE 1 Plan prezentacji 2 Wprowadzenie do Java 2 Enterprise Edition Aplikacje J2EE Serwer aplikacji J2EE Główne cele V Szkoły PLOUG - nowe podejścia do konstrukcji aplikacji J2EE Java 2

Bardziej szczegółowo

Ćwiczenie 8. Kontrolki serwerowe

Ćwiczenie 8. Kontrolki serwerowe Ćwiczenie 8 Temat: Kontrolki serwerowe ASP.NET cz.2 Cel ćwiczenia: W ramach tego ćwiczenie student zapozna się z kolejnymi kontrolkami serwerowymi oraz z metodami ich walidacji, a także z kontrolkami umożliwiającymi

Bardziej szczegółowo

Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz

Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz Zagadnienia 1. Delegaty wiązane, właściwości indeksowane 2. Delegaty niewiązane 3. Nowa wersja kalkulatora, delegaty

Bardziej szczegółowo

Studia podyplomowe. Programowanie na platformie Microsoft Visual Studio.NET

Studia podyplomowe. Programowanie na platformie Microsoft Visual Studio.NET Studia podyplomowe Programowanie na platformie Microsoft Visual Studio.NET I. Charakterystyka kursów Aplikacje bazodanowe dla biznesu (Microsoft Visual Studio.NET 2008) (35 godz.) W ramach kursu słuchacze

Bardziej szczegółowo

Zaawansowane aplikacje internetowe - laboratorium

Zaawansowane aplikacje internetowe - laboratorium Zaawansowane aplikacje internetowe - laboratorium Web Services (część 3). Do wykonania ćwiczeń potrzebne jest zintegrowane środowisko programistyczne Microsoft Visual Studio 2005. Ponadto wymagany jest

Bardziej szczegółowo

Aplikacje WWW. Laboratorium z przedmiotu Aplikacje WWW - zestaw 01

Aplikacje WWW. Laboratorium z przedmiotu Aplikacje WWW - zestaw 01 Laboratorium z przedmiotu Aplikacje WWW - zestaw 01 Cel zajęć. Celem zajęć jest zapoznanie z technologią ASP.NET Web Forms. Wprowadzenie teoretyczne. 1. Komunikacja klient-serwer poprzez połączenie internetowe

Bardziej szczegółowo

Tworzenie i wykorzystanie usług sieciowych

Tworzenie i wykorzystanie usług sieciowych Ćwiczenie 14 Temat: Tworzenie i wykorzystanie usług sieciowych Cel ćwiczenia: W trakcie ćwiczenia student zapozna się z procedurą tworzenia usługi sieciowej w technologii ASP.NET oraz nauczy się tworzyć

Bardziej szczegółowo

Programowanie obiektowe - 1.

Programowanie obiektowe - 1. Programowanie obiektowe - 1 Mariusz.Masewicz@cs.put.poznan.pl Programowanie obiektowe Programowanie obiektowe (ang. object-oriented programming) to metodologia tworzenia programów komputerowych, która

Bardziej szczegółowo

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki Dariusz Brzeziński Politechnika Poznańska, Instytut Informatyki Język programowania prosty bezpieczny zorientowany obiektowo wielowątkowy rozproszony przenaszalny interpretowany dynamiczny wydajny Platforma

Bardziej szczegółowo

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz Programowanie obiektowe Literatura: Autor: dr inŝ. Zofia Kruczkiewicz Java P. L. Lemay, Naughton R. Cadenhead Java Podręcznik 2 dla kaŝdego Języka Programowania Java Linki Krzysztof Boone oprogramowania

Bardziej szczegółowo

Wykład 5: Klasy cz. 3

Wykład 5: Klasy cz. 3 Programowanie obiektowe Wykład 5: cz. 3 1 dr Artur Bartoszewski - Programowanie obiektowe, sem. 1I- WYKŁAD - podstawy Konstruktor i destruktor (część I) 2 Konstruktor i destruktor KONSTRUKTOR Dla przykładu

Bardziej szczegółowo

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL III TI 4 godziny tygodniowo (4x30 tygodni =120 godzin ),

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL III TI 4 godziny tygodniowo (4x30 tygodni =120 godzin ), PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH KL III TI 4 godziny tygodniowo (4x30 tygodni =120 godzin ), Program 351203 Opracowanie: Grzegorz Majda Tematyka zajęć 1. Wprowadzenie do aplikacji internetowych

Bardziej szczegółowo

Multimedia JAVA. Historia

Multimedia JAVA. Historia Multimedia JAVA mgr inż. Piotr Odya piotrod@sound.eti.pg.gda.pl Historia 1990 rozpoczęcie prac nad nowym systemem operacyjnym w firmie SUN, do jego tworzenia postanowiono wykorzystać nowy język programowania

Bardziej szczegółowo

Programowanie zaawansowane

Programowanie zaawansowane Programowanie zaawansowane Ćwiczenie 6 Komunikacja silnie typowana I. Utwórz aplikację okienkową realizującą proste obliczenia arytmetyczne. Obsługa zdarzeń w aplikacji typu Windows Form Application odbywa

Bardziej szczegółowo

Kurs WWW ASP.NET. Paweł Rajba. pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/

Kurs WWW ASP.NET. Paweł Rajba. pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/ ASP.NET Paweł Rajba pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/ Wprowadzenie Z czego składa się aplikacja w ASP.NET? ASP.NET Web Forms (.aspx) ASP.NET Web services (.asmx) Klas, stron,,code-behind''

Bardziej szczegółowo

Wykład 4: Klasy i Metody

Wykład 4: Klasy i Metody Wykład 4: Klasy i Metody Klasa Podstawa języka. Każde pojęcie które chcemy opisać w języku musi być zawarte w definicji klasy. Klasa definiuje nowy typ danych, których wartościami są obiekty: klasa to

Bardziej szczegółowo

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu. Zrozumienie funkcji danych statycznych jest podstawą programowania obiektowego. W niniejszym artykule opiszę zasadę tworzenia klas statycznych w C#. Oprócz tego dowiesz się czym są statyczne pola i metody

Bardziej szczegółowo

A Zasady współpracy. Ocena rozwiązań punktów punktów punktów punktów punktów

A Zasady współpracy. Ocena rozwiązań punktów punktów punktów punktów punktów A Zasady współpracy Ocena rozwiązań 3.0 25 40 punktów 3.5 41 65 punktów 4.0 66 80 punktów 4.5 81 100 punktów 5.0 101 130 punktów Warunki zaliczenia przedmiotu Student uzyska ocenę zaliczającą (3.0) o ile

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Laboratorium z przedmiotu Programowanie obiektowe - zestaw 02 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami projektowania oraz implementacji klas i obiektów z wykorzystaniem dziedziczenia.

Bardziej szczegółowo

Środowiska i platformy programistyczne

Środowiska i platformy programistyczne Środowiska i platformy programistyczne 1 Rys historyczny lata 80-90: efektywność! Cel: zwiększyć efektywność programisty jedno narzędzie: integracja edytor kodu, funkcje programistyczne (kompilacja, łączenie,

Bardziej szczegółowo

REFERAT O PRACY DYPLOMOWEJ

REFERAT O PRACY DYPLOMOWEJ REFERAT O PRACY DYPLOMOWEJ Temat pracy: Projekt i realizacja elektronicznego dziennika ocen ucznia Autor: Grzegorz Dudek wykonanego w technologii ASP.NET We współczesnym modelu edukacji, coraz powszechniejsze

Bardziej szczegółowo

Aplikacje RMI https://docs.oracle.com/javase/tutorial/rmi/overview.html

Aplikacje RMI https://docs.oracle.com/javase/tutorial/rmi/overview.html Aplikacje RMI https://docs.oracle.com/javase/tutorial/rmi/overview.html Dr inż. Zofia Kruczkiewicz wykład 4 Programowanie aplikacji internetowych, wykład 4 1 1. Zadania aplikacji rozproszonych obiektów

Bardziej szczegółowo

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody Obiektowy PHP Czym jest obiekt? W programowaniu obiektem można nazwać każdy abstrakcyjny byt, który programista utworzy w pamięci komputera. Jeszcze bardziej upraszczając to zagadnienie, można powiedzieć,

Bardziej szczegółowo

Tworzenie aplikacji Web Alicja Zwiewka. Page 1

Tworzenie aplikacji Web Alicja Zwiewka. Page 1 Tworzenie aplikacji Web Alicja Zwiewka Page 1 Co to są web-aplikacje? Aplikacja internetowa (ang. web application) program komputerowy, który pracuje na serwerze i komunikuje się poprzez sieć komputerową

Bardziej szczegółowo

Przykładowa dostępna aplikacja w Visual Studio - krok po kroku

Przykładowa dostępna aplikacja w Visual Studio - krok po kroku Przykładowa dostępna aplikacja w Visual Studio - krok po kroku Zadaniem poniższego opisu jest pokazanie, jak stworzyć aplikację z dostępnym interfejsem. Sama aplikacja nie ma konkretnego zastosowania i

Bardziej szczegółowo

Jarosław Kuchta Administrowanie Systemami Komputerowymi. Internetowe Usługi Informacyjne

Jarosław Kuchta Administrowanie Systemami Komputerowymi. Internetowe Usługi Informacyjne Jarosław Kuchta Internetowe Usługi Informacyjne Komponenty IIS HTTP.SYS serwer HTTP zarządzanie połączeniami TCP/IP buforowanie odpowiedzi obsługa QoS (Quality of Service) obsługa plików dziennika IIS

Bardziej szczegółowo

Narzędzia i aplikacje Java EE. Usługi sieciowe Paweł Czarnul pczarnul@eti.pg.gda.pl

Narzędzia i aplikacje Java EE. Usługi sieciowe Paweł Czarnul pczarnul@eti.pg.gda.pl Narzędzia i aplikacje Java EE Usługi sieciowe Paweł Czarnul pczarnul@eti.pg.gda.pl Niniejsze opracowanie wprowadza w technologię usług sieciowych i implementację usługi na platformie Java EE (JAX-WS) z

Bardziej szczegółowo

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego Iwona Kochaoska Programowanie Obiektowe Programowanie obiektowe (ang. object-oriented programming) - metodyka tworzenia programów komputerowych,

Bardziej szczegółowo

PHP: bloki kodu, tablice, obiekty i formularze

PHP: bloki kodu, tablice, obiekty i formularze 1 PHP: bloki kodu, tablice, obiekty i formularze SYSTEMY SIECIOWE Michał Simiński 2 Bloki kodu Blok if-else Switch Pętle Funkcje Blok if-else 3 W PHP blok if i blok if-else wyglądają tak samo i funkcjonują

Bardziej szczegółowo

Platforma.NET laboratorium 4 Aktualizacja: 15/11/2013. Visual Basic.NET dostęp do bazy danych. Baza Microsoft SQL Server Compact

Platforma.NET laboratorium 4 Aktualizacja: 15/11/2013. Visual Basic.NET dostęp do bazy danych. Baza Microsoft SQL Server Compact Platforma.NET laboratorium 4 Aktualizacja: 15/11/2013 Prowadzący: mgr inż. Tomasz Jaworski Strona WWW: http://tjaworski.kis.p.lodz.pl/ Visual Basic.NET dostęp do bazy danych Baza Microsoft SQL Server Compact

Bardziej szczegółowo

Programowanie współbieżne i rozproszone

Programowanie współbieżne i rozproszone Programowanie współbieżne i rozproszone WYKŁAD 11 dr inż. CORBA CORBA (Common Object Request Broker Architecture) standard programowania rozproszonego zaproponowany przez OMG (Object Management Group)

Bardziej szczegółowo

TEMAT : KLASY DZIEDZICZENIE

TEMAT : KLASY DZIEDZICZENIE TEMAT : KLASY DZIEDZICZENIE Wprowadzenie do dziedziczenia w języku C++ Język C++ możliwa tworzenie nowej klasy (nazywanej klasą pochodną) w oparciu o pewną wcześniej zdefiniowaną klasę (nazywaną klasą

Bardziej szczegółowo

Bazodanowe usługi sieciowe w technologii ASP.NET. dr inż. Tomasz Tatoń

Bazodanowe usługi sieciowe w technologii ASP.NET. dr inż. Tomasz Tatoń Bazodanowe usługi sieciowe w technologii ASP.NET dr inż. Tomasz Tatoń Spis treści 2 Część 1 Tworzenie bazy danych w Microsoft SQL Server Część 2 Tworzenie usługi sieciowej WebService (polecenie select)

Bardziej szczegółowo

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016 Wstęp - wykład 0 22 lutego 2016 Historia Simula 67 język zaprojektowany do zastosowan symulacyjnych; Smalltalk 80 pierwszy język w pełni obiektowy; Dodawanie obiektowości do języków imperatywnych: Pascal

Bardziej szczegółowo

Wykład 5 Okna MDI i SDI, dziedziczenie

Wykład 5 Okna MDI i SDI, dziedziczenie Wykład 5 Okna MDI i SDI, dziedziczenie Autor: Zofia Kruczkiewicz Zagadnienia 1. Aplikacja wielookienkowa. Zakładanie projektu typu CLR Windows Forms 1.1. Aplikacja typu MDI 1.2. Aplikacja typu SDI 2. Dziedziczenie

Bardziej szczegółowo

Część I Tworzenie baz danych SQL Server na potrzeby przechowywania danych

Część I Tworzenie baz danych SQL Server na potrzeby przechowywania danych Spis treści Wprowadzenie... ix Organizacja ksiąŝki... ix Od czego zacząć?... x Konwencje przyjęte w ksiąŝce... x Wymagania systemowe... xi Przykłady kodu... xii Konfiguracja SQL Server 2005 Express Edition...

Bardziej szczegółowo

Część I Dostęp do danych oraz moŝliwości programowe (silnik bazy danych)

Część I Dostęp do danych oraz moŝliwości programowe (silnik bazy danych) Spis treści Wstęp... xi Część I Dostęp do danych oraz moŝliwości programowe (silnik bazy danych) 1 Program SQL Server Management Studio oraz język Transact SQL... 3 Omówienie programu SQL Server Management

Bardziej szczegółowo

Typy przetwarzania. Przetwarzanie zcentralizowane. Przetwarzanie rozproszone

Typy przetwarzania. Przetwarzanie zcentralizowane. Przetwarzanie rozproszone Typy przetwarzania Przetwarzanie zcentralizowane Systemy typu mainfame Przetwarzanie rozproszone Architektura klient serwer Architektura jednowarstwowa Architektura dwuwarstwowa Architektura trójwarstwowa

Bardziej szczegółowo

1 Atrybuty i metody klasowe

1 Atrybuty i metody klasowe 1 Atrybuty i metody klasowe Składowe klasowe (statyczne) Każdy obiekt klasy posiada własny zestaw atrybutów. Metody używają atrybutów odpowiedniego obiektu. Czasem potrzeba atrybutów wspólnych dla wszystkich

Bardziej szczegółowo

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3 3 ASP.NET MVC Podstawy 1 1. Cel zajęć Celem zajęć jest zapoznanie się z podstawami ASP.NET MVC 2.0 Framework. 2. Zadanie Proszę zbudować prostą aplikację WWW przy zastosowaniu framework a ASP.NET MVC 2.0

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Laboratorium z przedmiotu - zestaw 02 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami projektowania oraz implementacji klas i obiektów z wykorzystaniem dziedziczenia. Wprowadzenie teoretyczne.

Bardziej szczegółowo

Wykłady 1, 2. Wstęp do programowania w środowisku Visual C++ Autor: Zofia Kruczkiewicz

Wykłady 1, 2. Wstęp do programowania w środowisku Visual C++ Autor: Zofia Kruczkiewicz Wykłady 1, 2 Wstęp do programowania w środowisku Visual C++ Autor: Zofia Kruczkiewicz 1 Zagadnienia 1. Podstawowe pojęcia 2. Tworzenie aplikacji w Windows Forms 3. Zawartość projektu 4. Podstawowe cechy

Bardziej szczegółowo

Wykład V. Rzut okiem na języki programowania. Studia Podyplomowe INFORMATYKA Podstawy Informatyki

Wykład V. Rzut okiem na języki programowania. Studia Podyplomowe INFORMATYKA Podstawy Informatyki Studia Podyplomowe INFORMATYKA Podstawy Informatyki Wykład V Rzut okiem na języki programowania 1 Kompilacja vs. interpretacja KOMPILACJA Proces, który przetwarza program zapisany w języku programowania,

Bardziej szczegółowo

Microsoft.NET: ASP.NET MVC + Entity Framework (Code First)

Microsoft.NET: ASP.NET MVC + Entity Framework (Code First) Microsoft.NET: ASP.NET MVC + Entity Framework (Code First) Do realizacji projektu potrzebne jest zintegrowane środowisko programistyczne Microsoft Visual Studio 2012. W ramach projektu budowana jest prosta

Bardziej szczegółowo

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji. JAVA Java jest wszechstronnym językiem programowania, zorientowanym obiektowo, dostarczającym możliwość uruchamiania apletów oraz samodzielnych aplikacji. Java nie jest typowym kompilatorem. Źródłowy kod

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Programowanie obiektowe Wykład 2 Marcin Młotkowski 4 marca 2015 Plan wykładu 1 2 3 4 5 Marcin Młotkowski Programowanie obiektowe 2 / 47 Krótki opis C Obiektowy, z kontrolą typów; automatyczne odśmiecanie;

Bardziej szczegółowo

Serwery Statefull i Stateless

Serwery Statefull i Stateless Serwery Statefull i Stateless Wszystkie serwery aplikacji są określone jako stateless podczas projektowania. Te aplikacje nie przetrzymują stałego połączenia z klientem. Wysyłają one pakiety danych na

Bardziej szczegółowo

Architektura ADO.NET Dostawcy danych Modele dostępu do danych model połączeniowy Model bezpołączeniowy

Architektura ADO.NET Dostawcy danych Modele dostępu do danych model połączeniowy Model bezpołączeniowy Architektura ADO.NET Dostawcy danych Modele dostępu do danych model połączeniowy Model bezpołączeniowy 2015-12-18 1 Języki i paradygmaty - 9 Architektura ADO.NET - zestaw abstrakcyjnych klas, które udostępniają

Bardziej szczegółowo

Delphi podstawy programowania. Środowisko Delphi

Delphi podstawy programowania. Środowisko Delphi Delphi podstawy programowania Środowisko Delphi Olsztyn 2004 Delphi Programowanie obiektowe - (object-oriented programming) jest to metodologia tworzeniu programów komputerowych definiująca je jako zbiór

Bardziej szczegółowo

Wywoływanie metod zdalnych

Wywoływanie metod zdalnych Wywoływanie metod zdalnych model systemu Wywoływanie metod zdalnych aplikacja kliencka interfejs obiekt serwer Podejście obiektowe do budowy systemów rozproszonych proxy szkielet sieć Istota podejścia

Bardziej szczegółowo

Plan. Wprowadzenie. Co to jest APEX? Wprowadzenie. Administracja obszarem roboczym

Plan. Wprowadzenie. Co to jest APEX? Wprowadzenie. Administracja obszarem roboczym 1 Wprowadzenie do środowiska Oracle APEX, obszary robocze, użytkownicy Wprowadzenie Plan Administracja obszarem roboczym 2 Wprowadzenie Co to jest APEX? Co to jest APEX? Architektura Środowisko Oracle

Bardziej szczegółowo

Plan wykładu. Tworzenie programów dla platformy.net. Kontrolki list. Kontrolki weryfikujące. Wiązanie danych. Dostęp do danych

Plan wykładu. Tworzenie programów dla platformy.net. Kontrolki list. Kontrolki weryfikujące. Wiązanie danych. Dostęp do danych Tworzenie programów dla platformy.net ASP.NET Odsłona trz ecia Gliwice, Maj 2004 Marek Mittmann Plan wykładu Kontrolki weryfikujące Kontrolki list i wiązanie danych ADO.NET w aplikacjach ASP.NET Korzy

Bardziej szczegółowo

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych Obiekty reprezentują pewne pojęcia, przedmioty, elementy rzeczywistości. Obiekty udostępniają swoje usługi: metody operacje,

Bardziej szczegółowo

Czym jest Java? Rozumiana jako środowisko do uruchamiania programów Platforma software owa

Czym jest Java? Rozumiana jako środowisko do uruchamiania programów Platforma software owa 1 Java Wprowadzenie 2 Czym jest Java? Język programowania prosty zorientowany obiektowo rozproszony interpretowany wydajny Platforma bezpieczny wielowątkowy przenaszalny dynamiczny Rozumiana jako środowisko

Bardziej szczegółowo

OpenLaszlo. OpenLaszlo

OpenLaszlo. OpenLaszlo OpenLaszlo Spis Treści 1 OpenLaszlo Co to jest? Historia Idea Architektura Jako Flash lub DHTML Jako servlet lub SOLO Jak to działa? Język LZX Struktura programu Skrypty Obiekty i klasy Atrybuty i metody

Bardziej szczegółowo

Metodyka programowania. Podstawy C#

Metodyka programowania. Podstawy C# Metodyka programowania Podstawy C# Platforma.NET Platforma.NET (.NET Framework) Platforma programistyczna Microsoft, Obejmuje - środowisko uruchomieniowe CLR (Common Language Runtime) - biblioteki klas

Bardziej szczegółowo

Język JAVA podstawy. wykład 2, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Język JAVA podstawy. wykład 2, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna Język JAVA podstawy wykład 2, część 1 1 Język JAVA podstawy Plan wykładu: 1. Rodzaje programów w Javie 2. Tworzenie aplikacji 3. Tworzenie apletów 4. Obsługa archiwów 5. Wyjątki 6. Klasa w klasie! 2 Język

Bardziej szczegółowo

Microsoft.NET: LINQ to SQL, ASP.NET AJAX

Microsoft.NET: LINQ to SQL, ASP.NET AJAX Microsoft.NET: LINQ to SQL, ASP.NET AJAX Do realizacji projektu potrzebne jest zintegrowane środowisko programistyczne Microsoft Visual Studio 2008 oraz serwer bazy danych SQL Server Express 2005 (lub

Bardziej szczegółowo

Przewodnik instalacji i rozpoczynania pracy. Dla DataPage+ 2013

Przewodnik instalacji i rozpoczynania pracy. Dla DataPage+ 2013 Przewodnik instalacji i rozpoczynania pracy Dla DataPage+ 2013 Ostatnia aktualizacja: 25 lipca 2013 Spis treści Instalowanie wymaganych wstępnie komponentów... 1 Przegląd... 1 Krok 1: Uruchamianie Setup.exe

Bardziej szczegółowo

Programowanie obiektowe zastosowanie języka Java SE

Programowanie obiektowe zastosowanie języka Java SE Programowanie obiektowe zastosowanie języka Java SE Wstęp do programowania obiektowego w Javie Autor: dr inŝ. 1 Java? Java język programowania obiektowo zorientowany wysokiego poziomu platforma Javy z

Bardziej szczegółowo

Podstawy Programowania 2

Podstawy Programowania 2 Podstawy Programowania 2 Laboratorium 7 Instrukcja 6 Object Pascal Opracował: mgr inż. Leszek Ciopiński Wstęp: Programowanie obiektowe a programowanie strukturalne. W programowaniu strukturalnym, któremu

Bardziej szczegółowo

Część I Rozpoczęcie pracy z usługami Reporting Services

Część I Rozpoczęcie pracy z usługami Reporting Services Spis treści Podziękowania... xi Wprowadzenie... xiii Część I Rozpoczęcie pracy z usługami Reporting Services 1 Wprowadzenie do usług Reporting Services... 3 Platforma raportowania... 3 Cykl życia raportu...

Bardziej szczegółowo

Bazy danych 2. Wykład 1

Bazy danych 2. Wykład 1 Bazy danych 2 Wykład 1 Sprawy organizacyjne Materiały i listy zadań zamieszczane będą na stronie www.math.uni.opole.pl/~ajasi E-mail: standardowy ajasi@math.uni.opole.pl Sprawy organizacyjne Program wykładu

Bardziej szczegółowo

Wybrane działy Informatyki Stosowanej

Wybrane działy Informatyki Stosowanej Wybrane działy Informatyki Stosowanej Aplikacje WWW. Statyczne oraz dynamiczne strony WWW. Skrypty po stronie klienta. Dr inż. Andrzej Czerepicki a.czerepicki@wt.pw.edu.pl http://www2.wt.pw.edu.pl/~a.czerepicki

Bardziej szczegółowo

Informatyka I. Standard JDBC Programowanie aplikacji bazodanowych w języku Java

Informatyka I. Standard JDBC Programowanie aplikacji bazodanowych w języku Java Informatyka I Standard JDBC Programowanie aplikacji bazodanowych w języku Java dr inż. Andrzej Czerepicki Politechnika Warszawska Wydział Transportu 2017 Standard JDBC Java DataBase Connectivity uniwersalny

Bardziej szczegółowo

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018 Informatyka I Klasy i obiekty. Podstawy programowania obiektowego dr inż. Andrzej Czerepicki Politechnika Warszawska Wydział Transportu 2018 Plan wykładu Pojęcie klasy Deklaracja klasy Pola i metody klasy

Bardziej szczegółowo

Aplikacje w środowisku VBA. Visual Basic for Aplications

Aplikacje w środowisku VBA. Visual Basic for Aplications Aplikacje w środowisku VBA Visual Basic for Aplications Podstawowe informacje o VBA Visual Basic for Aplications, w skrócie VBA, to język programowania rozwijany przez Microsoft, którego zastosowanie pozwala

Bardziej szczegółowo

Rozdział 4 KLASY, OBIEKTY, METODY

Rozdział 4 KLASY, OBIEKTY, METODY Rozdział 4 KLASY, OBIEKTY, METODY Java jest językiem w pełni zorientowanym obiektowo. Wszystkie elementy opisujące dane, za wyjątkiem zmiennych prostych są obiektami. Sam program też jest obiektem pewnej

Bardziej szczegółowo

Podstawy programowania. Ćwiczenie. Pojęcia bazowe. Języki programowania. Środowisko programowania Visual Studio

Podstawy programowania. Ćwiczenie. Pojęcia bazowe. Języki programowania. Środowisko programowania Visual Studio Podstawy programowania Ćwiczenie Pojęcia bazowe. Języki programowania. Środowisko programowania Visual Studio Tematy ćwiczenia algorytm, opis języka programowania praca ze środowiskiem, formularz, obiekty

Bardziej szczegółowo

Projekt Hurtownia, realizacja rejestracji dostaw produktów

Projekt Hurtownia, realizacja rejestracji dostaw produktów Projekt Hurtownia, realizacja rejestracji dostaw produktów Ćwiczenie to będzie poświęcone zaprojektowaniu formularza pozwalającego na rejestrację dostaw produktów dla naszej hurtowni. Dane identyfikujące

Bardziej szczegółowo

Wykład 4. Architektura ADO.NET Dostawcy danych Modele dostępu do danych model połączeniowy Model bezpołączeniowy. Bazy danych 2

Wykład 4. Architektura ADO.NET Dostawcy danych Modele dostępu do danych model połączeniowy Model bezpołączeniowy. Bazy danych 2 Wykład 4 Architektura ADO.NET Dostawcy danych Modele dostępu do danych model połączeniowy Model bezpołączeniowy 2017-02-24 Bazy danych 2 W4 1 Architektura ADO.NET (Active Data Objects) Zestaw abstrakcyjnych

Bardziej szczegółowo

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej. Polimorfizm jest filarem programowania obiektowego, nie tylko jeżeli chodzi o język C++. Daje on programiście dużą elastyczność podczas pisania programu. Polimorfizm jest ściśle związany z metodami wirtualnymi.

Bardziej szczegółowo

Java jako język programowania

Java jako język programowania Java jako język programowania Interpretowany programy wykonują się na wirtualnej maszynie (JVM Java Virtual Machine) Składnia oparta o język C++ W pełni zorientowany obiektowo (wszystko jest obiektem)

Bardziej szczegółowo

Smarty PHP. Leksykon kieszonkowy

Smarty PHP. Leksykon kieszonkowy IDZ DO PRZYK ADOWY ROZDZIA SPIS TREœCI KATALOG KSI EK KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG Smarty PHP. Leksykon kieszonkowy Autor: Daniel Bargie³ ISBN: 83-246-0676-9 Format: B6, stron: 112 TWÓJ KOSZYK

Bardziej szczegółowo

Budowa aplikacji ASP.NET z wykorzystaniem wzorca MVC

Budowa aplikacji ASP.NET z wykorzystaniem wzorca MVC Akademia MetaPack Uniwersytet Zielonogórski Budowa aplikacji ASP.NET z wykorzystaniem wzorca MVC Krzysztof Blacha Microsoft Certified Professional Budowa aplikacji ASP.NET z wykorzystaniem wzorca MVC Agenda:

Bardziej szczegółowo

C# /.NET. Copyright by 3bird Projects 2018,

C# /.NET. Copyright by 3bird Projects 2018, C# /.NET Copyright by 3bird Projects 2018, http://edukacja.3bird.pl Ogólne Opracowana przez Microsoft platforma programistyczna.net Framework jest odpowiednikiem platformy Java. Obejmuje gotowe biblioteki,

Bardziej szczegółowo

Projekt Hurtownia, realizacja rejestracji dostaw produktów

Projekt Hurtownia, realizacja rejestracji dostaw produktów Projekt Hurtownia, realizacja rejestracji dostaw produktów Ćwiczenie to będzie poświęcone zaprojektowaniu formularza pozwalającego na rejestrację dostaw produktów dla naszej hurtowni. Dane identyfikujące

Bardziej szczegółowo

Aplikacje WWW - laboratorium

Aplikacje WWW - laboratorium Aplikacje WWW - laboratorium Serwlety Celem ćwiczenia jest przygotowanie kilku prostych serwletów ilustrujących możliwości tej technologii. Poszczególne ćwiczenia prezentują sposób przygotowania środowiska,

Bardziej szczegółowo

Bazy danych i strony WWW

Bazy danych i strony WWW Bazy danych i strony WWW Obsługa baz danych poprzez strony WWW Niezbędne narzędzia: serwer baz danych np. MySQL serwer stron WWW np. Apache przeglądarka stron WWW interpretująca język HTML język skryptowy

Bardziej szczegółowo

1 LINQ. Zaawansowane programowanie internetowe Instrukcja nr 1

1 LINQ. Zaawansowane programowanie internetowe Instrukcja nr 1 1 LINQ 1 1. Cel zajęć Celem zajęć jest zapoznanie się z technologią LINQ oraz tworzeniem trójwarstwowej aplikacji internetowej. 2. Zadanie Proszę przygotować aplikację WWW, która: będzie pozwalała na generowanie

Bardziej szczegółowo

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości Rozpoczniemy od zaprojektowania bazy danych w programie SYBASE/PowerDesigner umieszczamy dwie Encje (tabele) prawym

Bardziej szczegółowo

Materiały oryginalne: ZAWWW-2st1.2-l11.tresc-1.0kolor.pdf. Materiały poprawione

Materiały oryginalne: ZAWWW-2st1.2-l11.tresc-1.0kolor.pdf. Materiały poprawione Materiały oryginalne: ZAWWW-2st1.2-l11.tresc-1.0kolor.pdf Materiały poprawione Rozwiązanie zadania w NetBeans IDE 7.4: Jarosław Ksybek, Adam Miazio Celem ćwiczenia jest przygotowanie prostej aplikacji

Bardziej szczegółowo

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania 1) Cel ćwiczenia Celem ćwiczenia jest zapoznanie się z podstawowymi elementami obiektowymi systemu Windows wykorzystując Visual Studio 2008 takimi jak: przyciski, pola tekstowe, okna pobierania danych

Bardziej szczegółowo

JAVA W SUPER EXPRESOWEJ PIGUŁCE

JAVA W SUPER EXPRESOWEJ PIGUŁCE JAVA W SUPER EXPRESOWEJ PIGUŁCE Obiekt Obiekty programowe to zbiór własności i zachowań (zmiennych i metod). Podobnie jak w świecie rzeczywistym obiekty posiadają swój stan i zachowanie. Komunikat Wszystkie

Bardziej szczegółowo