Członkostwo
autor: Microsoft
Uwaga
Ponieważ ten artykuł został napisany, dostawcy ASP.NET członkostwa zostały zastąpione przez usługę ASP.NET Identity. Zdecydowanie zalecamy aktualizowanie aplikacji w celu korzystania z platformy ASP.NET Identity , a nie dostawców członkostwa opisanych w tym artykule. ASP.NET Identity ma wiele zalet w systemie członkostwa ASP.NET, w tym :
- Lepsza wydajność
- Ulepszona rozszerzalność i możliwość testowania
- Obsługa uwierzytelniania OAuth, OpenID Connect i uwierzytelniania dwuskładnikowego
- Obsługa tożsamości opartej na oświadczeniach
- Lepsza współdziałanie z platformą ASP.Net Core
ASP.NET Członkostwo opiera się na powodzeniu modelu uwierzytelniania formularzy z ASP.NET 1.x. Uwierzytelnianie ASP.NET Forms zapewnia wygodny sposób dołączania formularza logowania do aplikacji ASP.NET i weryfikowania użytkowników względem bazy danych lub innego magazynu danych.
ASP.NET Członkostwo opiera się na powodzeniu modelu uwierzytelniania formularzy z ASP.NET 1.x. Uwierzytelnianie ASP.NET Forms zapewnia wygodny sposób dołączania formularza logowania do aplikacji ASP.NET i weryfikowania użytkowników względem bazy danych lub innego magazynu danych. Członkowie klasy FormsAuthentication umożliwiają obsługę plików cookie na potrzeby uwierzytelniania, sprawdzanie prawidłowego logowania, rejestrowanie użytkownika itp. Jednak implementacja uwierzytelniania formularzy w aplikacji ASP.NET 1.x może wymagać sporo kodu.
Członkostwo w ASP.NET 2.0 jest głównym postępem w zakresie korzystania tylko z uwierzytelniania formularzy. (Członkostwo jest najbardziej niezawodne w połączeniu z uwierzytelnianiem formularzy, ale korzystanie z uwierzytelniania formularzy nie jest wymagane). Jak już wkrótce zobaczysz, możesz użyć ASP.NET członkostwa i kontrolek logowania w ASP.NET 2.0, aby zaimplementować zaawansowany system członkostwa bez konieczności pisania w ogóle kodu.
Implementowanie członkostwa w ASP.NET 2.0
Członkostwo jest implementowane, wykonując cztery kroki. Należy pamiętać, że istnieje wiele kroków podrzędnych, które są zaangażowane, a także opcjonalną konfigurację, którą można zaimplementować. Te kroki mają na celu zilustrowanie dużego obrazu konfigurowania członkostwa.
Utwórz bazę danych członkostwa (jeśli SQL Server jest używana jako magazyn członkostwa).
Określ opcje członkostwa w plikach konfiguracji aplikacji. (Członkostwo jest domyślnie włączone).
Określ typ magazynu członkostwa, którego chcesz użyć. Dostępne opcje:
- Microsoft SQL Server (wersja 7.0 lub nowsza)
- Magazyn usługi Active Directory
- Niestandardowy dostawca członkostwa
Skonfiguruj aplikację na potrzeby uwierzytelniania ASP.NET Forms. Po raz kolejny członkostwo jest przeznaczone do korzystania z uwierzytelniania formularzy, ale korzystanie z uwierzytelniania formularzy nie jest wymagane.
Zdefiniuj konta użytkowników dla członkostwa i skonfiguruj role w razie potrzeby.
Tworzenie bazy danych członkostwa
Jeśli używasz SQL Server 7.0 lub nowszego jako magazynu członkostwa, możesz skonfigurować bazę danych przy użyciu narzędzia aspnet_regsql (dostępnego najłatwiej w wierszu polecenia programu Visual Studio .NET 2005). Narzędzie aspnet_regsql może służyć jako narzędzie wiersza polecenia lub za pomocą kreatora graficznego interfejsu użytkownika. Metoda kreatora to najprostszy sposób konfigurowania bazy danych. Aby uzyskać dostęp do kreatora, wystarczy uruchomić następujące polecenie:
aspnet_regsql W
Po uruchomieniu tego polecenia zostanie wyświetlony Kreator instalacji ASP.NET SQL Server, jak pokazano poniżej.
Rysunek 1
Kreator instalacji ASP.NET SQL Server tworzy witrynę sieci Web w wystąpieniu określonym w kreatorze. Jednak ASP.NET użyje parametrów połączenia w pliku machine.config w celu nawiązania połączenia z bazą danych. Domyślnie te parametry połączenia wskazują wystąpienie SQL Server 2005, więc jeśli używasz wystąpienia SQL Server 2000 lub SQL Server 7.0, musisz zmodyfikować parametry połączenia w pliku machine.config. Te parametry połączenia można znaleźć tutaj:
<configuration>
<connectionStrings>
<add name="LocalSqlServer"
connectionString="data source=(local);
Integrated Security=SSPI;Initial Catalog=aspnetdb;"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
Niestety, jeśli nie zmodyfikujesz parametrów połączenia, ASP.NET nie da ci opisowego błędu. Po prostu będzie nadal narzekać, mówiąc, że nie utworzono bazy danych. W powyższym przypadku zmodyfikowałem parametry połączenia, aby wskazać lokalne wystąpienie SQL Server 2000.
Określanie konfiguracji i dodawania użytkowników i ról
Następnym krokiem konfigurowania członkostwa jest dodanie niezbędnych informacji do pliku web.config aplikacji. W ASP.NET 1.x modyfikowanie pliku web.config było czasami trudne ze względu na użycie lowerCamelCase i brak funkcji IntelliSense. Program Visual Studio .NET 2005 znacznie ułatwia zadanie z funkcją Intellisense dla plików konfiguracji, ale ASP.NET 2.0 idzie o krok dalej, udostępniając interfejs internetowy do edytowania plików konfiguracji.
Interfejs internetowy można uruchomić, klikając przycisk ASP.NET Konfiguracja na pasku narzędzi Eksplorator rozwiązań, jak pokazano poniżej. Możesz również uruchomić interfejs internetowy za pomocą wyskakujących okienek wyświetlanych po wstawieniu kontrolek logowania.
Rysunek 2
Spowoduje to uruchomienie narzędzia ASP.NET Administracja witrynami sieci Web pokazane poniżej. ASP.NET Administracja witryną sieci Web to czterokarty interfejs, który ułatwia zarządzanie ustawieniami aplikacji. Dostępne są następujące karty:
- Ekran główny
- Zabezpieczeń Konfigurowanie użytkowników, ról i dostępu.
- Aplikacji Konfigurowanie ustawień aplikacji.
- Dostawca Skonfiguruj i przetestuj dostawcę członkostwa w aplikacjach.
Narzędzie do administrowania witrynami sieci Web umożliwia łatwe tworzenie nowych użytkowników, tworzenie nowych ról oraz zarządzanie użytkownikami i rolami. Ta możliwość nie jest dostępna w interfejsie systemu Windows. Interfejs systemu Windows umożliwia łatwe definiowanie ustawień autoryzacji oraz dodawanie, usuwanie dostawców i zarządzanie nimi, możliwości, które nie znajdują się w narzędziu administrowania witrynami sieci Web.
Aby uruchomić interfejs systemu Windows, otwórz przystawkę Internet Information Services, kliknij prawym przyciskiem myszy aplikację i wybierz pozycję Właściwości. Kliknij kartę ASP.NET, a następnie kliknij przycisk Edytuj konfigurację. (Aby włączyć przycisk Edytuj konfigurację, aplikacja musi być uruchomiona w ASP.NET 2.0. Możesz również skonfigurować wersję ASP.NET w oknie dialogowym ASP.NET). Zostanie wyświetlone okno dialogowe ustawienia konfiguracji ASP.NET, jak pokazano poniżej.
Rysunek 3
Na karcie Ogólne są wyświetlane parametry połączenia i ustawienia aplikacji. Wszystkie ustawienia w kursywie są definiowane w pliku konfiguracji nadrzędnej (machine.config lub web.config na wyższym poziomie), a ustawienia nie w kursywie pochodzą z pliku konfiguracji aplikacji. Jeśli ustawienie zostanie dodane, usunięte lub edytowane na poziomie aplikacji, ASP.NET doda, usunie lub zmodyfikuje ustawienie na poziomach aplikacji web.config zamiast usuwania ustawienia z pliku konfiguracji, z którego jest dziedziczony.
Poniżej przedstawiono kartę Uwierzytelnianie. W tym miejscu skonfigurujesz ustawienia członkostwa. Ustawienia uwierzytelniania formularzy, dostawcy członkostwa i dostawcy ról można skonfigurować tutaj.
Rysunek 4
Implementowanie członkostwa w aplikacji
Najprostszym sposobem zaimplementowania członkostwa ASP.NET 2.0 w aplikacji jest użycie udostępnionych kontrolek logowania. Ta metoda umożliwia zaimplementowanie podstaw członkostwa ASP.NET 2.0 bez konieczności pisania kodu.
Następujące kontrolki logowania są dostępne w ASP.NET 2.0:
Kontrolka logowania
Kontrolka Logowania udostępnia interfejs, który może zalogować się do systemu członkostwa. Udostępnia ona pole tekstowe nazwy użytkownika i hasła oraz przycisk logowania. Wiele innych typowych funkcji, takich jak link do rejestracji osób, które jeszcze tego nie zrobiły, pole wyboru umożliwiające użytkownikowi automatyczne logowanie się podczas kolejnych wizyt, link do przypomnienia o hasłach itp. Wszystkie funkcje kontrolki Logowania można dostosowywać za pomocą właściwości kontrolki.
W ASP.NET 1.x deweloperzy musieli napisać sporo kodu, aby wykonać wyszukiwanie przy użyciu uwierzytelniania formularzy. Dzięki członkostwu w wersji ASP.NET 2.0 można zweryfikować użytkowników bez konieczności pisania żadnego kodu. ASP.NET automatycznie wykona wyszukiwanie użytkownika. (Jeśli używasz kontrolki Logowania bez używania ASP.NET członkostwa, możesz użyć metody OnAuthenticate , aby zweryfikować użytkownika).
LoginView, kontrolka
Kontrolka LoginView to kontrolka szablonu, która domyślnie udostępnia dwa szablony; Element AnonymousTemplate i LogInTemplate. Wyświetlany szablon zależy od tego, czy użytkownik jest zalogowany do systemu członkostwa. Ta kontrolka jest zwykle używana do wyświetlania kontrolki Logowania, gdy użytkownik nie zalogował się jeszcze i kontrolka LoginStatus i/lub inne kontrolki logowania, gdy użytkownik się zalogował. Jeśli używasz zarządzania rolami w aplikacji ASP.NET, kontrolka LoginView może wyświetlać określony szablon na podstawie roli użytkowników. (Więcej informacji na temat zarządzania rolami ASP.NET zostanie omówionych później).
PasswordRecovery, kontrolka
Kontrolka PasswordRecovery umożliwia użytkownikom odbieranie wiadomości e-mail przy użyciu bieżącego hasła lub resetowanie jego hasła. Można odzyskać i wysłać wiadomości e-mail do użytkowników w postaci zwykłego tekstu i zaszyfrowanych haseł. Jeśli hasło jest skrótem, nie można go odzyskać. Zamiast tego użytkownik będzie musiał wykonać resetowanie hasła.
LoginStatus, kontrolka
Kontrolka LoginStatus służy do wyświetlania wskaźnika logowania dla użytkowników, którzy nie są zalogowani, oraz wskaźnik wylogowania dla użytkowników, którzy są obecnie zalogowani. Właściwość Request.IsAuthenticated służy do określania, który wskaźnik ma być wyświetlany. Wskaźnik wyświetlany przez kontrolkę LoginStatus może być tekstem (zaimplementowany za pośrednictwem właściwości LoginText i LogoutText ) lub obrazów (zaimplementowanych za pomocą właściwości LoginImageUrl i LogoutImageUrl ).
Gdy użytkownik wyloguje się za pośrednictwem kontrolki LoginStatus, zostanie przekierowany do adresu URL określonego przez właściwość LogoutPageUrl . Jeśli ta właściwość nie jest ustawiona, bieżąca strona zostanie odświeżona. Ponieważ witryna jest prawdopodobnie chroniona przez uwierzytelnianie za pomocą formularzy, odświeżanie bieżącej strony spowoduje przekierowanie użytkownika do strony logowania witryny.
LoginName, kontrolka
Kontrolka LoginName wyświetla nazwę użytkownika aktualnie zalogowanego do witryny.
CreateUserWizard, kontrolka
Kontrolka CreateUserWizard zapewnia użytkownikom wygodny sposób rejestrowania się w systemie członkostwa. Kroki (zaimplementowane jako kolekcja WizardSteps) można dodać za pośrednictwem interfejsu przedstawionego poniżej.
Rysunek 5
CreateUserWizard to szablonowa kontrolka pochodząca z klasy Kreator i udostępnia następujące szablony:
- Headertemplate Ten szablon steruje wyglądem nagłówka kreatora.
- Sidebartemplate Ten szablon steruje wyglądem paska bocznego kreatora.
- Startnavigationtemplate Ten szablon steruje wyglądem nawigacji kreatora w kroku startowym.
- Stepnavigationtemplate Ten szablon steruje wyglądem obszaru nawigacji, gdy nie znajduje się w kroku rozpoczęcia lub zakończenia.
- Finishnavigationtemplate Ten szablon steruje wyglądem obszaru nawigacji po zakończeniu kroku.
Ponadto dla każdego kroku dodanego do Kreatora ASP.NET utworzy szablon niestandardowy zawierający zarówno element ContentTemplate, jak i element CustomNavigationTemplate dla tego kroku. Aby uzyskać szczegółowe informacje na temat dostosowywania elementu CreateUserWizard, zobacz dokumentację VS.NET 2005:
ChangePassword, kontrolka
Kontrolka ChangePassword umożliwia użytkownikom zmianę hasła. Jeśli właściwość DisplayUserName ma wartość true (domyślnie jest to fałsz), użytkownik może zmienić jego hasło, gdy nie jest zalogowany. Jeśli użytkownik jest już zalogowany, a właściwość DisplayUserName ma wartość true, użytkownik będzie mógł zmienić hasło innego użytkownika, który nie jest zalogowany, podając, że zna identyfikator użytkownika tego użytkownika.
Pamiętaj, że jeśli chcesz, aby użytkownicy mogli zmieniać hasła bez konieczności logowania, musisz upewnić się, że strona, na której jest wyświetlana kontrolka ChangePassword, zezwala na dostęp anonimowy. Oczywiście użytkownicy będą musieli podać swoje stare hasło, aby zmienić swoje hasło.
Zarządzanie rolami
Zarządzanie rolami umożliwia przypisanie użytkowników do określonej roli, a następnie ograniczenie dostępu do określonych plików lub folderów na podstawie tej roli. Zarządzanie rolami udostępnia również interfejs API, dzięki czemu można programowo określić rolę kogoś lub określić wszystkich użytkowników w określonej roli i odpowiednio odpowiedzieć.
Zarządzanie rolami nie jest wymagane w ASP.NET członkostwie ani nie wymaga członkostwa w celu korzystania z zarządzania rolami. Jednak oba uzupełniają się ładnie i jest prawdopodobne, że deweloperzy będą używać ich w połączeniu ze sobą.
Aby włączyć zarządzanie rolami w aplikacji, wprowadź następującą zmianę w pliku web.config:
<roleManager enabled="true" cacheRolesInCookie="true" cookieProtection="All" />
Gdy atrybut cacheRolesInCookie ma wartość true, ASP.NET buforuje członkostwo użytkowników w pliku cookie na kliencie. Umożliwia to wyszukiwanie ról bez wywołań do dostawcy ról. W przypadku korzystania z tego atrybutu deweloperzy są zachęcani do upewnienia się, że atrybut cookieProtection jest ustawiony na Wszystkie. (To jest ustawienie domyślne). Dzięki temu dane plików cookie są szyfrowane i pomagają zapewnić, że zawartość plików cookie nie została zmieniona. Role można dodawać przy użyciu narzędzia do administrowania witrynami sieci Web. Umożliwia łatwe definiowanie ról, konfigurowanie dostępu do części witryny na podstawie tych ról i przypisywanie użytkowników do ról.
Rysunek 6
Jak pokazano powyżej, nowe role można dodać, wprowadzając po prostu nazwę roli, a następnie klikając pozycję Dodaj rolę. Istniejące role można zarządzać lub usuwać, klikając odpowiedni link na liście istniejących ról.
Podczas zarządzania rolą można dodawać lub usuwać użytkowników, jak pokazano poniżej.
Rysunek 7
Zaznaczając pole wyboru Użytkownik jest w roli, możesz łatwo dodać użytkownika do określonej roli. ASP.NET automatycznie zaktualizuje bazę danych członkostwa przy użyciu odpowiednich wpisów. Należy również skonfigurować reguły dostępu dla aplikacji. ASP.NET deweloperzy 1.x znają to za pośrednictwem <elementu autoryzacji> w pliku web.config i ta opcja jest nadal dostępna w ASP.NET 2.0. Jednak łatwiej jest zarządzać regułami dostępu przy użyciu narzędzia do administrowania witrynami sieci Web, jak pokazano poniżej.
Rysunek 8
W takim przypadku folder Administracja jest wyróżniony (trudno go zobaczyć, ponieważ narzędzie wyróżnia je w jasnoszarym), a rola Administratorzy została udzielona dostępu. Wszyscy inni użytkownicy są odrzucani. Możesz kliknąć ikonę głowy, aby wybrać regułę, a następnie użyć przycisków Przenieś w górę i Przenieś w dół, aby rozmieścić reguły. Podobnie jak w przypadku elementu autoryzacji> ASP.NET <reguły są przetwarzane w kolejności ich wyświetlania. Innymi słowy, jeśli kolejność reguł na powyższym zdjęciu została odwrócona, nikt nie będzie miał dostępu do folderu Administracja, ponieważ pierwsza reguła, która ASP.NET napotkałaby, będzie regułą, która odmawia wszystkim dostępu do folderu.
ASP.NET 2.0 dodaje plik web.config do folderu, dla którego określasz regułę dostępu. Reguły dostępu można edytować za pośrednictwem pliku konfiguracji lub za pośrednictwem narzędzia administracyjnego witryny sieci Web. Innymi słowy, narzędzie do administrowania witrynami sieci Web to po prostu interfejs, za pomocą którego plik konfiguracji można edytować w środowisku przyjaznym dla użytkownika.
Używanie ról w kodzie
Interfejs API zarządzania rolami nie uległ zmianie od wersji 1.x. Metoda IsInRole służy do określania, czy użytkownik jest w określonej roli.
if (User.IsInRole(Administrators)) {
btnManageSite.Visible = true;
}
ASP.NET tworzy również wystąpienie RolePrincipal jako element członkowski bieżącego kontekstu. Obiekt RolePrincipal może służyć do uzyskania wszystkich ról, do których należy użytkownik w następujący sposób:
string[] userRoles = ((RolePrincipal)User).GetRoles();
Używanie grup ról z kontrolką LoginView
Teraz, gdy masz wiedzę na temat zarządzania rolami i członkostwa, omówimy krótko, jak kontrolka LoginView korzysta z tej możliwości w ASP.NET 2.0. Jak wspomniano wcześniej, kontrolka LoginView jest domyślnie szablonową kontrolką zawierającą dwa szablony; Element AnonymousTemplate i LogInTemplate. W oknie dialogowym Zadania elementu LoginView znajduje się link (pokazany poniżej), który umożliwia edytowanie grup ról.
Rysunek 9
Każdy obiekt RoleGroup zawiera tablicę ciągów definiujących role, do których ma zastosowanie grupa ról. Aby dodać nową grupę RoleGroup do kontrolki LoginView, kliknij link Edytuj grupy ról. Na powyższej ilustracji widać, że dodano nową grupę ról dla administratorów. Wybierając tę grupę ról (RoleGroup[0]) z listy rozwijanej Widoki, można skonfigurować szablon, który będzie wyświetlany tylko członkom roli Administratorzy. Na poniższej ilustracji dodano nową grupę ról, która ma zastosowanie do członków roli Sales i roli Dystrybucja. Spowoduje to dodanie drugiej grupy ról do listy rozwijanej Widoki w oknie dialogowym Zadania elementu LoginView i wszystkie dodane do tego szablonu będą widoczne dla każdego użytkownika w roli Sprzedaż lub Dystrybucja.
Rysunek 10
Zastępowanie istniejącego dostawcy członkostwa
Istnieje kilka sposobów rozszerzania funkcjonalności członkostwa ASP.NET. Przede wszystkim można oczywiście zmienić istniejące funkcje klasy SqlMembershipProvider, dziedzicząc ją i przesłaniając jej metody. Jeśli na przykład chcesz zaimplementować własną funkcjonalność podczas tworzenia użytkowników, możesz utworzyć własną klasę dziedziczą z klasy SqlMembershipProvider w następujący sposób:
public class jForumMembershipProvider : SqlMembershipProvider {
public jForumMembershipProvider() {
}
public override MembershipUser CreateUser(
string username,
string password,
string email,
string passwordQuestion,
string passwordAnswer,
bool isApproved,
object providerUserKey,
out MembershipCreateStatus status) {
// your own implementation
return base.CreateUser(
username,
password,
email,
passwordQuestion,
passwordAnswer,
isApproved,
providerUserKey,
out status);
}
}
Jeśli z drugiej strony chcesz utworzyć własnego dostawcę (aby przechowywać informacje o członkostwie w bazie danych programu Access, na przykład), możesz utworzyć własnego dostawcę.
Tworzenie własnego dostawcy członkostwa
Aby utworzyć własnego dostawcę członkostwa, należy najpierw utworzyć klasę dziedziczą z klasy MembershipProvider. Jeśli używasz VB.NET, program Visual Studio 2005 doda wycinki dla wszystkich metod, które należy zastąpić. Jeśli używasz języka C#, należy dodać wycinki.
Należy zastąpić następujące elementy:
- Właściwość ApplicationName
- ChangePassword, funkcja
- ChangePasswordQuestionAndAnswer, funkcja
- CreateUser, funkcja
- DeleteUser, funkcja
- Właściwość EnablePasswordReset
- Właściwość EnablePasswordRetrieval
- FindUsersByEmail, funkcja
- FindUsersByName, funkcja
- GetAllUsers, funkcja
- GetNumberOfUsersOnline, funkcja
- GetPassword, funkcja
- GetUser, funkcja
- GetUserNameByEmail, funkcja
- Właściwość MaxInvalidPasswordAttempts
- Właściwość MinRequiredNonAlphanumericCharacters
- Właściwość MinRequiredPasswordLength
- PasswordAttempt WłaściwośćWindow
- Właściwość PasswordFormat
- PasswordStrengthRegularExpression, właściwość
- Wymaga właściwościQuestionAndAnswer
- RequiresUniqueEmail, właściwość
- ResetPassword, funkcja
- Odblokowywanie funkcji użytkownika
- UpdateUser, funkcja
- ValidateUser, funkcja
To dość lista do zaimplementowania jako deweloper języka C#. Możesz łatwiej utworzyć klasę w VB.NET bez żadnej implementacji, a następnie użyć refleksora .NET lub podobnego narzędzia, aby przekonwertować kod na C#.
Parametry połączenia i inne właściwości powinny być ustawione na wartości domyślne w metodzie Initialize. (Metoda Initialize jest uruchamiana, gdy dostawca jest ładowany w czasie wykonywania). Drugi parametr metody Initialize jest typu System.Collections.Specialized.NameValueCollection i jest odwołaniem do <elementu dodawania> skojarzonego z dostawcą niestandardowym w pliku web.config. Ten wpis wygląda następująco:
<system.web>
<authentication mode="Forms"/>
<membership
defaultProvider="jForumCustomMembershipProvider" >
<providers>
<add name="jForumCustomMembershipProvider"
type="jForumCustomMembershipProvider"
requiresQuestionAndAnswer="true"
connectionString="Provider=Microsoft.Jet.
OLEDB.4.0;Data Source=C:\jForumCustomMembershipProvider\
App_Data\Members.mdb;Persist Security
Info=False"
/>
</providers>
</membership>
</system.web>
Oto przykład metody Initialize.
public override void Initialize(string name,
System.Collections.Specialized.NameValueCollection config) {
if (config["requiresQuestionAndAnswer"])
_requiresQuestionAndAnswer = true;
_connString = config["connectionString"];
base.Initialize(name, config);
}
Aby zweryfikować użytkownika podczas przesyłania formularza logowania, należy użyć metody ValidateUser. Ta metoda jest uruchamiana, gdy użytkownik kliknie przycisk logowania w kontrolce Logowanie. Kod, który wykonuje wyszukiwanie użytkownika w tej metodzie.
Jak widać, pisanie własnego dostawcy członkostwa nie jest trudne i pozwala rozszerzyć tę zaawansowaną funkcjonalność ASP.NET 2.0.