Przypisywanie ról do użytkowników (C#)

Autor: Scott Mitchell

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

Pobierz kod lub pobierz plik PDF

W tym samouczku utworzymy dwie strony ASP.NET, które ułatwiają zarządzanie użytkownikami należącymi do ról. Pierwsza strona będzie zawierać obiekty, aby zobaczyć, którzy użytkownicy należą do danej roli, do jakich ról należy określony użytkownik, oraz możliwość przypisywania lub usuwania określonego użytkownika z określonej roli. Na drugiej stronie rozszerzymy kontrolkę CreateUserWizard, tak aby zawierała krok określający, do jakich ról należy nowo utworzony użytkownik. Jest to przydatne w scenariuszach, w których administrator może tworzyć nowe konta użytkowników.

Wprowadzenie

W poprzednim samouczku przeanalizowano platformę Role i SqlRoleProviderelement ; zobaczyliśmy, jak używać Roles klasy do tworzenia, pobierania i usuwania ról. Oprócz tworzenia i usuwania ról musimy mieć możliwość przypisywania lub usuwania użytkowników z roli. Niestety, ASP.NET nie jest dostarczana z żadnymi kontrolkami sieci Web do zarządzania użytkownikami należącymi do ról. Zamiast tego musimy utworzyć własne strony ASP.NET w celu zarządzania tymi skojarzeniami. Dobrą wiadomością jest to, że dodawanie i usuwanie użytkowników do ról jest dość proste. Klasa Roles zawiera wiele metod dodawania co najmniej jednego użytkownika do co najmniej jednej roli.

W tym samouczku utworzymy dwie strony ASP.NET, które ułatwiają zarządzanie użytkownikami należącymi do ról. Pierwsza strona będzie zawierać obiekty, aby zobaczyć, którzy użytkownicy należą do danej roli, do jakich ról należy określony użytkownik, oraz możliwość przypisywania lub usuwania określonego użytkownika z określonej roli. Na drugiej stronie rozszerzymy kontrolkę CreateUserWizard, tak aby zawierała krok określający, do jakich ról należy nowo utworzony użytkownik. Jest to przydatne w scenariuszach, w których administrator może tworzyć nowe konta użytkowników.

Zaczynamy!

Wyświetlanie listy użytkowników należących do ról

Pierwsza kolejność działalności biznesowej dla tego samouczka polega na utworzeniu strony internetowej, z której użytkownicy mogą być przypisywani do ról. Zanim zaczniemy się martwić o sposób przypisywania użytkowników do ról, najpierw skoncentrujmy się na tym, jak określić, do jakich ról należą użytkownicy. Istnieją dwa sposoby wyświetlania tych informacji: "według roli" lub "według użytkownika". Możemy zezwolić odwiedzającym na wybranie roli, a następnie pokazać im wszystkich użytkowników należących do roli (wyświetlanie "według roli") lub poprosić odwiedzających o wybranie użytkownika, a następnie wyświetlenie im ról przypisanych do tego użytkownika (wyświetlanie "według użytkownika").

Widok "według roli" jest przydatny w sytuacjach, gdy odwiedzający chce znać zestaw użytkowników należących do określonej roli; widok "według użytkownika" jest idealny, gdy użytkownik musi znać role określonego użytkownika. Na naszej stronie znajdują się zarówno interfejsy "by role" i "by user".

Zaczniemy od utworzenia interfejsu "by user". Ten interfejs będzie składać się z listy rozwijanej i listy pól wyboru. Lista rozwijana zostanie wypełniona zestawem użytkowników w systemie; pola wyboru będą wyliczać role. Wybranie użytkownika z listy rozwijanej spowoduje sprawdzenie tych ról, do których należy użytkownik. Osoba odwiedzająca stronę może następnie zaznaczyć lub usunąć zaznaczenie pól wyboru, aby dodać lub usunąć wybranego użytkownika z odpowiednich ról.

Uwaga

Używanie listy rozwijanej do wyświetlania listy kont użytkowników nie jest idealnym wyborem dla witryn internetowych, w których mogą istnieć setki kont użytkowników. Lista rozwijana została zaprojektowana tak, aby umożliwić użytkownikowi wybranie jednego elementu z stosunkowo krótkiej listy opcji. Szybko staje się niewygodny w miarę wzrostu liczby elementów listy. Jeśli tworzysz witrynę internetową, która będzie mieć potencjalnie dużą liczbę kont użytkowników, warto rozważyć użycie alternatywnego interfejsu użytkownika, takiego jak stronicowy element GridView lub interfejs z możliwością filtrowania, który wyświetla monit o wybranie litery przez odwiedzających, a następnie pokazuje tylko tych użytkowników, których nazwa użytkownika zaczyna się od wybranej litery.

Krok 1. Kompilowanie interfejsu użytkownika "Według użytkownika"

UsersAndRoles.aspx Otwórz stronę. W górnej części strony dodaj kontrolkę Etykieta sieci Web o nazwie ActionStatus i wyczyść jej Text właściwość. Użyjemy tej etykiety, aby przekazać opinię na temat wykonanych akcji, wyświetlając komunikaty takie jak "Użytkownik Tito został dodany do roli Administratorzy" lub "Użytkownik Jisun został usunięty z roli Nadzorcy". Aby wyróżnić te komunikaty, ustaw właściwość Etykieta CssClass na "Ważne".

<p align="center"> 

     <asp:Label ID="ActionStatus" runat="server" CssClass="Important"></asp:Label> 
</p>

Następnie dodaj następującą definicję klasy CSS do Styles.css arkusza stylów:

.Important 
{ 
     font-size: large; 
     color: Red; 
}

Ta definicja CSS instruuje przeglądarkę, aby wyświetlała etykietę przy użyciu dużej, czerwonej czcionki. Rysunek 1 przedstawia ten efekt za pośrednictwem programu Visual Studio Projektant.

Właściwość CssClass etykiety powoduje wyświetlenie dużej, czerwonej czcionki

Rysunek 1. Właściwość etykiety CssClass powoduje wyświetlenie dużej, czerwonej czcionki (kliknij, aby wyświetlić obraz pełnowymiarowy)

Następnie dodaj listę DropDownList do strony, ustaw jej ID właściwość na , i ustaw jej AutoPostBack właściwość na UserListTrue. Użyjemy tej listy rozwijanej, aby wyświetlić listę wszystkich użytkowników w systemie. Ta lista rozwijana zostanie powiązana z kolekcją obiektów MembershipUser. Ponieważ chcemy, aby lista Rozwijana Lista rozwijana wyświetlała właściwość UserName obiektu MembershipUser (i użyjemy jej jako wartości elementów listy), ustaw właściwości Listy rozwijanej DataTextField na DataValueField "UserName".

Poniżej listy rozwijanej dodaj element Repeater o nazwie UsersRoleList. To repeater wyświetli listę wszystkich ról w systemie jako serię pól wyboru. Zdefiniuj element Repeater ItemTemplate przy użyciu następującego deklaratywnego znaczników:

<asp:Repeater ID="UsersRoleList" runat="server"> 
     <ItemTemplate> 
          <asp:CheckBox runat="server" ID="RoleCheckBox" AutoPostBack="true" 

               Text='<%# Container.DataItem %>' /> 
          <br /> 
     </ItemTemplate> 
</asp:Repeater>

Znaczniki ItemTemplate zawierają pojedynczą kontrolkę sieci Web CheckBox o nazwie RoleCheckBox. Właściwość CheckBox jest ustawiona AutoPostBack na wartość True, a Text właściwość jest powiązana z Container.DataItemwartością . Powodem, dla którego składnia powiązania danych jest po prostu Container.DataItem taka, że struktura Role zwraca listę nazw ról jako tablicę ciągów i jest to tablica ciągów, którą będziemy wiązać z repeaterem. Dokładny opis przyczyny użycia tej składni do wyświetlania zawartości tablicy powiązanej z kontrolką sieci Web danych wykracza poza zakres tego samouczka. Aby uzyskać więcej informacji na ten temat, zobacz Powiązanie tablicy skalarnej z kontrolką sieci Web danych.

W tym momencie znacznik deklaratywny interfejsu użytkownika powinien wyglądać podobnie do następującego:

<h3>Manage Roles By User</h3> 

<p> 
     <b>Select a User:</b> 
     <asp:DropDownList ID="UserList" runat="server" AutoPostBack="True" 
          DataTextField="UserName" DataValueField="UserName"> 

     </asp:DropDownList> 
</p> 
<p> 
     <asp:Repeater ID="UsersRoleList" runat="server"> 
          <ItemTemplate> 
               <asp:CheckBox runat="server" ID="RoleCheckBox" AutoPostBack="true" 

                    Text='<%# Container.DataItem %>' /> 
               <br /> 
          </ItemTemplate> 
     </asp:Repeater> 
</p>

Teraz możemy napisać kod, aby powiązać zestaw kont użytkowników z listą rozwijaną i zestawem ról na repeater. W klasie code-behind strony dodaj metodę o nazwie i inną o nazwie BindUsersToUserListBindRolesList, używając następującego kodu:

private void BindUsersToUserList() 
{ 
     // Get all of the user accounts 
     MembershipUserCollection users = Membership.GetAllUsers(); 
     UserList.DataSource = users; 
     UserList.DataBind(); 
}
 
private void BindRolesToList() 
{ 
     // Get all of the roles 
     string[] roles = Roles.GetAllRoles(); 
     UsersRoleList.DataSource = roles; 
     UsersRoleList.DataBind(); 
}

Metoda BindUsersToUserList pobiera wszystkie konta użytkowników w systemie za pośrednictwem Membership.GetAllUsers metody . MembershipUserCollection Zwraca obiekt, który jest kolekcją MembershipUser wystąpień. Ta kolekcja jest następnie powiązana z listą UserList Rozwijaną. MembershipUser Wystąpienia, które makijaż kolekcji zawierają różne właściwości, takie jak UserName, Email, CreationDatei IsOnline. Aby poinstruować listę DropDownList, aby wyświetlić wartość UserName właściwości, upewnij się, że UserList właściwości listy rozwijanej DataTextField i DataValueField właściwości zostały ustawione na "UserName".

Uwaga

Metoda Membership.GetAllUsers ma dwa przeciążenia: jeden, który nie akceptuje parametrów wejściowych i zwraca wszystkich użytkowników, oraz jeden, który przyjmuje wartości całkowite dla indeksu strony i rozmiar strony, i zwraca tylko określony podzbiór użytkowników. Jeśli w elemecie interfejsu użytkownika jest wyświetlana duża liczba kont użytkowników, drugie przeciążenie może służyć do bardziej wydajnej strony za pośrednictwem użytkowników, ponieważ zwraca tylko dokładny podzbiór kont użytkowników, a nie wszystkich z nich.

Metoda BindRolesToList rozpoczyna się od wywołania Roles metody klasyGetAllRoles, która zwraca tablicę ciągów zawierającą role w systemie. Ta tablica ciągów jest następnie powiązana z repeaterem.

Na koniec musimy wywołać te dwie metody po pierwszym załadowaniu strony. Dodaj następujący kod do programu obsługi zdarzeń Page_Load :

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 
     } 
}

Po utworzeniu tego kodu poświęć chwilę, aby odwiedzić stronę za pośrednictwem przeglądarki; Ekran powinien wyglądać podobnie do rysunku 2. Wszystkie konta użytkowników są wypełniane na liście rozwijanej i poniżej tej roli są wyświetlane jako pole wyboru. Ponieważ ustawiamy AutoPostBack właściwości Listy rozwijanej i Pola wyboru na True, zmiana wybranego użytkownika lub sprawdzanie lub usuwanie zaznaczenia roli powoduje powrót. Nie jest jednak wykonywana żadna akcja, ponieważ musimy jeszcze napisać kod do obsługi tych akcji. W kolejnych dwóch sekcjach zajmiemy się tymi zadaniami.

Strona wyświetla użytkowników i role

Rysunek 2. Strona wyświetla użytkowników i role (kliknij, aby wyświetlić obraz pełnowymiarowy)

Sprawdzanie ról, do których należy wybrany użytkownik

Gdy strona zostanie załadowana po raz pierwszy lub gdy odwiedzający wybierze nowego użytkownika z listy rozwijanej, musimy zaktualizować UsersRoleListpola wyboru , aby pole wyboru danej roli było zaznaczone tylko wtedy, gdy wybrany użytkownik należy do tej roli. Aby to zrobić, utwórz metodę o nazwie CheckRolesForSelectedUser z następującym kodem:

private void CheckRolesForSelectedUser() 
{ 
     // Determine what roles the selected user belongs to 
     string selectedUserName = UserList.SelectedValue; 
     string[] selectedUsersRoles = Roles.GetRolesForUser(selectedUserName); 

     // Loop through the Repeater's Items and check or uncheck the checkbox as needed 

     foreach (RepeaterItem ri in UsersRoleList.Items) 
     { 
          // Programmatically reference the CheckBox 
          CheckBox RoleCheckBox = ri.FindControl("RoleCheckBox") as CheckBox; 
          // See if RoleCheckBox.Text is in selectedUsersRoles 
          if (selectedUsersRoles.Contains<string>(RoleCheckBox.Text)) 
               RoleCheckBox.Checked = true; 
          else 
               RoleCheckBox.Checked = false; 
     } 
}

Powyższy kod rozpoczyna się od określenia, kim jest wybrany użytkownik. Następnie używa metody klasy GetRolesForUser(userName) Roles, aby zwrócić zestaw ról określonego użytkownika jako tablicę ciągów. Następnie elementy repeatera są wyliczane, a pole wyboru każdego elementu RoleCheckBox jest programowo przywoływane. Pole wyboru jest sprawdzane tylko wtedy, gdy rola, z jaką odpowiada, znajduje się w tablicy ciągów selectedUsersRoles .

Uwaga

Składnia selectedUserRoles.Contains<string>(...) nie zostanie skompilowana, jeśli używasz ASP.NET wersji 2.0. Metoda Contains<string> jest częścią biblioteki LINQ, która jest nowa do ASP.NET 3.5. Jeśli nadal używasz ASP.NET w wersji 2.0, użyj Array.IndexOf<string> metody .

Metoda CheckRolesForSelectedUser musi być wywoływana w dwóch przypadkach: po pierwszym załadowaniu strony i za każdym razem, gdy UserList wybrany indeks Listy rozwijanej zostanie zmieniony. W związku z tym wywołaj tę metodę z Page_Load procedury obsługi zdarzeń (po wywołaniach do BindUsersToUserList i BindRolesToList). Ponadto utwórz procedurę obsługi zdarzeń dla zdarzenia DropDownList SelectedIndexChanged i wywołaj tę metodę stamtąd.

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 

          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 
          // Check the selected user's roles 
          CheckRolesForSelectedUser(); 
     } 
} 

... 

protected void UserList_SelectedIndexChanged(object sender, EventArgs e) 
{ 
     CheckRolesForSelectedUser(); 
}

Za pomocą tego kodu możesz przetestować stronę za pośrednictwem przeglądarki. Jednak ponieważ UsersAndRoles.aspx strona obecnie nie ma możliwości przypisywania użytkowników do ról, żaden użytkownik nie ma ról. Utworzymy interfejs do przypisywania użytkowników do ról za chwilę, więc możesz użyć mojego słowa, że ten kod działa i sprawdzi, czy to zrobi później, lub możesz ręcznie dodać użytkowników do ról, wstawiając rekordy do aspnet_UsersInRoles tabeli w celu przetestowania tej funkcji teraz.

Przypisywanie i usuwanie użytkowników z ról

Gdy odwiedzający sprawdza lub usuwa zaznaczenie pola wyboru w UsersRoleList repeaterze, musimy dodać lub usunąć wybranego użytkownika z odpowiedniej roli. Właściwość CheckBox AutoPostBack jest obecnie ustawiona na true, co powoduje, że po powrocie zwrotne w dowolnym momencie pole wyboru w repeaterze jest zaznaczone lub niezaznaczone. Krótko mówiąc, musimy utworzyć procedurę obsługi zdarzeń dla zdarzenia CheckBox CheckChanged . Ponieważ Pole wyboru znajduje się w kontrolce Repeater, musimy ręcznie dodać instalację kanalizającą programu obsługi zdarzeń. Zacznij od dodania procedury obsługi zdarzeń do klasy kod-behind jako protected metody, w następujący sposób:

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 

}

Wrócimy do pisania kodu dla tej procedury obsługi zdarzeń w ciągu chwili. Najpierw ukończmy obsługę instalacji hydraulicznej. W polu CheckBox w elemencie Repeater ItemTemplatedodaj OnCheckedChanged="RoleCheckBox_CheckChanged"element . Ta składnia podłącza procedurę RoleCheckBox_CheckChanged obsługi zdarzeń do RoleCheckBoxzdarzenia .s CheckedChanged .

<asp:CheckBox runat="server" ID="RoleCheckBox" 
     AutoPostBack="true" 
     Text='<%# Container.DataItem %>' 
     OnCheckedChanged="RoleCheckBox_CheckChanged" />

Naszym ostatnim zadaniem jest ukończenie procedury obsługi zdarzeń RoleCheckBox_CheckChanged . Musimy zacząć od odwoływania się do kontrolki CheckBox, która wywołała zdarzenie, ponieważ to wystąpienie CheckBox informuje nas, jaka rola została sprawdzona lub niezaznaczone za pośrednictwem jej Text właściwości i Checked . Korzystając z tych informacji wraz z userName wybranego użytkownika, dodajemy lub usuwamy użytkownika z roli za pośrednictwem Roles klasy AddUserToRole lub RemoveUserFromRole metody.

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 
     // Reference the CheckBox that raised this event 
     CheckBox RoleCheckBox = sender as CheckBox; 

     // Get the currently selected user and role 
     string selectedUserName = UserList.SelectedValue; 

     string roleName = RoleCheckBox.Text; 

     // Determine if we need to add or remove the user from this role 
     if (RoleCheckBox.Checked) 
     { 
          // Add the user to the role 
          Roles.AddUserToRole(selectedUserName, roleName); 
          // Display a status message 
          ActionStatus.Text = string.Format("User {0} was added to role {1}.", selectedUserName, roleName); 
     } 
     else 
     { 
          // Remove the user from the role 
          Roles.RemoveUserFromRole(selectedUserName, roleName); 
          // Display a status message 
          ActionStatus.Text = string.Format("User {0} was removed from role {1}.", selectedUserName, roleName); 

     } 
}

Powyższy kod rozpoczyna się od programowego odwoływania się do kontrolki CheckBox, która wywołała zdarzenie, które jest dostępne za pośrednictwem parametru wejściowego sender . Jeśli pole wyboru jest zaznaczone, wybrany użytkownik zostanie dodany do określonej roli, w przeciwnym razie zostaną one usunięte z roli. W obu przypadkach etykieta ActionStatus wyświetla komunikat podsumowujący właśnie wykonaną akcję.

Poświęć chwilę, aby przetestować tę stronę za pośrednictwem przeglądarki. Wybierz użytkownika Tito, a następnie dodaj Tito do ról Administratorzy i Nadzorcy.

Tito został dodany do ról administratorów i nadzorców

Rysunek 3. Tito został dodany do ról administratorów i nadzorców (kliknij, aby wyświetlić obraz pełnowymiarowy)

Następnie wybierz użytkownika Bruce'a z listy rozwijanej. Istnieje postback, a pola CheckBoxes repeatera są aktualizowane za pośrednictwem elementu CheckRolesForSelectedUser. Ponieważ Bruce nie należy jeszcze do żadnych ról, dwa pola wyboru są niezaznaczone. Następnie dodaj Bruce'a do roli Nadzorcy.

Bruce został dodany do roli nadzorców

Rysunek 4. Bruce został dodany do roli nadzorców (kliknij, aby wyświetlić obraz pełnowymiarowy)

Aby dokładniej sprawdzić funkcjonalność CheckRolesForSelectedUser metody, wybierz użytkownika innego niż Tito lub Bruce. Zwróć uwagę, że pola wyboru są automatycznie niezaznaczone, co oznacza, że nie należą do żadnych ról. Wróć do Tito. Należy zaznaczyć pola wyboru Administratorzy i Nadzorcy.

Krok 2. Kompilowanie interfejsu użytkownika "Według ról"

W tym momencie ukończyliśmy interfejs "by users" i jesteśmy gotowi do rozpoczęcia walki z interfejsem "według ról". Interfejs "według ról" monituje użytkownika o wybranie roli z listy rozwijanej, a następnie wyświetla zestaw użytkowników należących do tej roli w siatce.

Dodaj kolejną kontrolkę UsersAndRoles.aspx DropDownList do strony. Umieść ten element pod kontrolką Repeater, nadaj jej RoleListnazwę i ustaw jej AutoPostBack właściwość na true. Poniżej tego dodaj element GridView i nadaj mu nazwę RolesUserList. Ten element GridView wyświetli listę użytkowników należących do wybranej roli. Ustaw właściwość GridView AutoGenerateColumns na wartość False, dodaj wartość TemplateField do kolekcji siatki Columns i ustaw jej HeaderText właściwość na "Użytkownicy". Zdefiniuj pole szablonu ItemTemplate tak, aby wyświetlało wartość wyrażenia Container.DataItem powiązania danych we Text właściwości Etykiety o nazwie UserNameLabel.

Po dodaniu i skonfigurowaniu kontrolki GridView znacznik deklaratywny interfejsu "by role" powinien wyglądać podobnie do następującego:

<h3>Manage Users By Role</h3> 
<p> 
     <b>Select a Role:</b> 

     <asp:DropDownList ID="RoleList" runat="server" AutoPostBack="true"></asp:DropDownList> 
</p> 
<p>      <asp:GridView ID="RolesUserList" runat="server" AutoGenerateColumns="false" 

          EmptyDataText="No users belong to this role."> 
          <Columns> 
               <asp:TemplateField HeaderText="Users"> 
                    <ItemTemplate> 
                         <asp:Label runat="server" id="UserNameLabel" 
                              Text='<%# Container.DataItem %>'></asp:Label> 

                    </ItemTemplate> 
               </asp:TemplateField> 
          </Columns> 
     </asp:GridView> </p>

Musimy wypełnić Listę RoleList rozwijaną zestawem ról w systemie. Aby to osiągnąć, zaktualizuj metodę BindRolesToList tak, aby wiązała tablicę ciągów zwróconą przez Roles.GetAllRoles metodę do RolesList listy DropDownList (a także UsersRoleList repeater).

private void BindRolesToList() 
{ 
     // Get all of the roles 

     string[] roles = Roles.GetAllRoles(); 
     UsersRoleList.DataSource = roles; 
     UsersRoleList.DataBind(); 

     RoleList.DataSource = roles; 
     RoleList.DataBind(); 
}

Dodano dwa ostatnie wiersze metody w BindRolesToList celu powiązania zestawu ról z kontrolką RoleList DropDownList. Rysunek 5 przedstawia wynik końcowy wyświetlany za pośrednictwem przeglądarki — listę rozwijaną wypełnioną rolami systemu.

Role są wyświetlane na liście rozwijanej RoleList

Rysunek 5. Role są wyświetlane na liście rozwijanej RoleList (kliknij, aby wyświetlić obraz pełnowymiarowy)

Wyświetlanie użytkowników należących do wybranej roli

Po pierwszym załadowaniu strony lub wybraniu RoleList nowej roli z listy rozwijanej musimy wyświetlić listę użytkowników należących do tej roli w elemecie GridView. Utwórz metodę o nazwie DisplayUsersBelongingToRole przy użyciu następującego kodu:

private void DisplayUsersBelongingToRole() 
{ 
     // Get the selected role 
     string selectedRoleName = RoleList.SelectedValue; 

     // Get the list of usernames that belong to the role 
     string[] usersBelongingToRole = Roles.GetUsersInRole(selectedRoleName); 

     // Bind the list of users to the GridView 
     RolesUserList.DataSource = usersBelongingToRole; 
     RolesUserList.DataBind(); 
}

Ta metoda rozpoczyna się od pobrania wybranej roli z listy rozwijanej RoleList . Następnie używa Roles.GetUsersInRole(roleName) metody , aby pobrać tablicę ciągów userNames użytkowników należących do tej roli. Ta tablica jest następnie powiązana z elementem RolesUserList GridView.

Ta metoda musi być wywoływana w dwóch okolicznościach: gdy strona zostanie początkowo załadowana, a wybrana rola w liście rozwijanej RoleList zmieni się. W związku z tym zaktualizuj procedurę Page_Load obsługi zdarzeń tak, aby ta metoda jest wywoływana po wywołaniu metody .CheckRolesForSelectedUser Następnie utwórz procedurę obsługi zdarzeń dla RoleListzdarzenia i SelectedIndexChanged wywołaj tę metodę.

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 

          // Check the selected user's roles 
          CheckRolesForSelectedUser(); 

          // Display those users belonging to the currently selected role 
          DisplayUsersBelongingToRole(); 
     } 
} 

... 

protected void RoleList_SelectedIndexChanged(object sender, EventArgs e) 
{ 
     DisplayUsersBelongingToRole(); 
}

W tym kodzie element RolesUserList GridView powinien wyświetlać tych użytkowników, którzy należą do wybranej roli. Jak pokazano na rysunku 6, rola Nadzorcy składa się z dwóch członków: Bruce'a i Tito.

Obiekt GridView wyświetla listę tych użytkowników, którzy należą do wybranej roli

Rysunek 6. Widok GridView wyświetla listę użytkowników należących do wybranej roli (kliknij, aby wyświetlić obraz pełnowymiarowy)

Usuwanie użytkowników z wybranej roli

Rozszerzmy element GridView, RolesUserList aby zawierał kolumnę przycisków "Usuń". Kliknięcie przycisku "Usuń" dla określonego użytkownika spowoduje usunięcie ich z tej roli.

Zacznij od dodania pola przycisku Usuń do kontrolki GridView. Ustaw to pole jako najbardziej złożone po lewej stronie i zmień jego DeleteText właściwość z "Usuń" (wartość domyślna) na "Usuń".

Zrzut ekranu przedstawiający sposób dodawania przycisku

Rysunek 7. Dodawanie przycisku "Usuń" do widoku GridView (kliknij, aby wyświetlić obraz pełnowymiarowy)

Po kliknięciu przycisku "Usuń" zostanie wyświetlony komunikat zwrotny, a zdarzenie GridView RowDeleting zostanie podniesione. Musimy utworzyć procedurę obsługi zdarzeń dla tego zdarzenia i napisać kod, który usuwa użytkownika z wybranej roli. Utwórz procedurę obsługi zdarzeń, a następnie dodaj następujący kod:

protected void RolesUserList_RowDeleting(object sender, GridViewDeleteEventArgs e) 
{ 
     // Get the selected role 
     string selectedRoleName = RoleList.SelectedValue; 

     // Reference the UserNameLabel 
     Label UserNameLabel = RolesUserList.Rows[e.RowIndex].FindControl("UserNameLabel") as Label; 

     // Remove the user from the role 
     Roles.RemoveUserFromRole(UserNameLabel.Text, selectedRoleName); 

     // Refresh the GridView 
     DisplayUsersBelongingToRole(); 

     // Display a status message 
     ActionStatus.Text = string.Format("User {0} was removed from role {1}.", UserNameLabel.Text, selectedRoleName); 
}

Kod rozpoczyna się od określenia wybranej nazwy roli. Następnie programowo odwołuje się do UserNameLabel kontrolki z wiersza, którego przycisk "Usuń" został kliknięty w celu określenia userName użytkownika do usunięcia. Użytkownik zostanie następnie usunięty z roli za pomocą wywołania metody Roles.RemoveUserFromRole . Element RolesUserList GridView jest następnie odświeżany, a komunikat jest wyświetlany za pośrednictwem kontrolki ActionStatus Etykieta.

Uwaga

Przycisk "Usuń" nie wymaga żadnego potwierdzenia od użytkownika przed usunięciem użytkownika z roli. Zapraszam do dodania pewnego poziomu potwierdzenia użytkownika. Jednym z najprostszych sposobów potwierdzenia akcji jest okno dialogowe potwierdzania po stronie klienta. Aby uzyskać więcej informacji na temat tej techniki, zobacz Dodawanie Client-Side potwierdzenia podczas usuwania.

Rysunek 8 przedstawia stronę po usunięciu użytkownika Tito z grupy Nadzorcy.

Niestety, Tito nie jest już nadzorcą

Rysunek 8. Niestety, Tito nie jest już nadzorcą (kliknij, aby wyświetlić obraz pełnowymiarowy)

Dodawanie nowych użytkowników do wybranej roli

Oprócz usuwania użytkowników z wybranej roli odwiedzający tę stronę powinien również mieć możliwość dodania użytkownika do wybranej roli. Najlepszy interfejs dodawania użytkownika do wybranej roli zależy od liczby oczekiwanych kont użytkowników. Jeśli witryna internetowa będzie zawierać tylko kilka tuzinów kont użytkowników lub mniej, możesz użyć listy rozwijanej tutaj. Jeśli mogą istnieć tysiące kont użytkowników, warto dołączyć interfejs użytkownika, który umożliwia odwiedzającym stronicowanie za pośrednictwem kont, wyszukiwanie określonego konta lub filtrowanie kont użytkowników w inny sposób.

Na tej stronie użyjemy bardzo prostego interfejsu, który działa niezależnie od liczby kont użytkowników w systemie. Na przykład użyjemy pola TextBox z monitem o wpisanie nazwy użytkownika użytkownika, który chce dodać do wybranej roli. Jeśli żaden użytkownik o tej nazwie nie istnieje lub jeśli użytkownik jest już członkiem roli, zostanie wyświetlony komunikat w ActionStatus obszarze Etykieta. Jeśli jednak użytkownik istnieje i nie jest członkiem roli, dodamy je do roli i odświeżymy siatkę.

Dodaj pole tekstowe i przycisk poniżej kontrolki GridView. Ustaw wartości TextBox IDUserNameToAddToRole na i ustaw odpowiednio właściwości i Text przycisk ID na AddUserToRoleButton i "Dodaj użytkownika do roli".

<p> 
     <b>UserName:</b> 
     <asp:TextBox ID="UserNameToAddToRole" runat="server"></asp:TextBox> 
     <br /> 
     <asp:Button ID="AddUserToRoleButton" runat="server" Text="Add User to Role" /> 

</p>

Następnie utwórz procedurę Click obsługi zdarzeń dla elementu AddUserToRoleButton i dodaj następujący kod:

protected void AddUserToRoleButton_Click(object sender, EventArgs e) 
{ 
     // Get the selected role and username 

     string selectedRoleName = RoleList.SelectedValue; 
     string userNameToAddToRole = UserNameToAddToRole.Text; 

     // Make sure that a value was entered 
     if (userNameToAddToRole.Trim().Length == 0) 
     { 
          ActionStatus.Text = "You must enter a username in the textbox."; 
          return; 
     } 

     // Make sure that the user exists in the system 
     MembershipUser userInfo = Membership.GetUser(userNameToAddToRole); 
     if (userInfo == null) 
     { 
          ActionStatus.Text = string.Format("The user {0} does not exist in the system.", userNameToAddToRole); 

          return; 
     } 

     // Make sure that the user doesn't already belong to this role 
     if (Roles.IsUserInRole(userNameToAddToRole, selectedRoleName)) 
     { 
          ActionStatus.Text = string.Format("User {0} already is a member of role {1}.", userNameToAddToRole, selectedRoleName); 
          return; 
     } 

     // If we reach here, we need to add the user to the role 
     Roles.AddUserToRole(userNameToAddToRole, selectedRoleName); 

     // Clear out the TextBox 
     UserNameToAddToRole.Text = string.Empty; 

     // Refresh the GridView 
     DisplayUsersBelongingToRole(); 

     // Display a status message 

     ActionStatus.Text = string.Format("User {0} was added to role {1}.", userNameToAddToRole, selectedRoleName); }

Większość kodu w procedurze Click obsługi zdarzeń wykonuje różne kontrole poprawności. Gwarantuje to, że odwiedzający podał nazwę użytkownika w polu UserNameToAddToRole TextBox, że użytkownik istnieje w systemie i że nie należy jeszcze do wybranej roli. Jeśli którykolwiek z tych testów zakończy się niepowodzeniem, zostanie wyświetlony ActionStatus odpowiedni komunikat i program obsługi zdarzeń zostanie zakończona. Jeśli wszystkie testy przejdą, użytkownik zostanie dodany do roli za pomocą Roles.AddUserToRole metody . Następnie właściwość TextBox Text zostanie wyczyszczone, widok GridView zostanie odświeżony, a etykieta ActionStatus wyświetli komunikat wskazujący, że określony użytkownik został pomyślnie dodany do wybranej roli.

Uwaga

Aby upewnić się, że określony użytkownik nie należy jeszcze do wybranej roli, użyjemy Roles.IsUserInRole(userName, roleName) metody , która zwraca wartość logiczną wskazującą, czy userName jest członkiem roleName. Ta metoda zostanie ponownie użyta w następnym samouczku, gdy przyjrzymy się autoryzacji opartej na rolach.

Odwiedź stronę za pośrednictwem przeglądarki i wybierz rolę Nadzorcy z listy rozwijanej RoleList . Spróbuj wprowadzić nieprawidłową nazwę użytkownika — powinien zostać wyświetlony komunikat wyjaśniający, że użytkownik nie istnieje w systemie.

Nie można dodać użytkownika nieistniejącego do roli

Rysunek 9. Nie można dodać użytkownika nieistniejącego do roli (kliknij, aby wyświetlić obraz pełnowymiarowy)

Teraz spróbuj dodać prawidłowego użytkownika. Przejdź do przodu i ponownie dodaj Tito do roli Nadzorcy.

Tito jest po raz kolejny przełożonym!

Rysunek 10. Tito jest po raz kolejny przełożonym! (Kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Krok 3. Krzyżowe aktualizowanie interfejsów "Według użytkownika" i "Według roli"

Strona UsersAndRoles.aspx oferuje dwa odrębne interfejsy do zarządzania użytkownikami i rolami. Obecnie te dwa interfejsy działają niezależnie od siebie, więc istnieje możliwość, że zmiana w jednym interfejsie nie zostanie odzwierciedlona natychmiast w drugiej. Załóżmy na przykład, że odwiedzający stronę wybiera rolę Nadzorcy z listy Rozwijanej RoleList , która wyświetla listę Bruce'a i Tito jako członków. Następnie odwiedzający wybierze pozycję Tito z listy rozwijanej UserList , która sprawdza pola wyboru Administratorzy i nadzorcy w UsersRoleList repeaterze. Jeśli gość usunie zaznaczenie roli Nadzorca z repeater, Tito zostanie usunięty z roli Nadzorcy, ale ta modyfikacja nie zostanie odzwierciedlona w interfejsie "według roli". Funkcja GridView nadal będzie pokazywać Tito jako członka roli Nadzorcy.

Aby rozwiązać ten problem, musimy odświeżyć kontrolkę GridView za każdym razem, gdy rola jest zaznaczona lub nie jest zaznaczona z elementu UsersRoleList Repeater. Podobnie musimy odświeżyć repeater za każdym razem, gdy użytkownik zostanie usunięty lub dodany do roli z interfejsu "by role".

Moduł powtarzający w interfejsie "by user" jest odświeżany przez wywołanie CheckRolesForSelectedUser metody . Interfejs "by role" można zmodyfikować w RolesUserList procedurze obsługi zdarzeń usługi GridView RowDeleting i AddUserToRoleButton procedurze obsługi zdarzeń przycisku Click . Dlatego musimy wywołać metodę CheckRolesForSelectedUser z każdej z tych metod.

protected void RolesUserList_RowDeleting(object sender, GridViewDeleteEventArgs e) 
{ 
     ... Code removed for brevity ... 

     // Refresh the "by user" interface 
     CheckRolesForSelectedUser(); 
} 

protected void AddUserToRoleButton_Click(object sender, EventArgs e) 
{ 
     ... Code removed for brevity ... 


     // Refresh the "by user" interface 
     CheckRolesForSelectedUser(); 
}

Podobnie element GridView w interfejsie "by role" jest odświeżany przez wywołanie DisplayUsersBelongingToRole metody, a interfejs "by user" jest modyfikowany za pośrednictwem procedury obsługi zdarzeń RoleCheckBox_CheckChanged . W związku z tym musimy wywołać metodę DisplayUsersBelongingToRole z tej procedury obsługi zdarzeń.

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 
     ... Code removed for brevity... 

     // Refresh the "by role" interface 
     DisplayUsersBelongingToRole(); 
}

Dzięki tym drobnym zmianom kodu interfejsy "by user" i "by role" są teraz poprawnie aktualizowane krzyżowo. Aby to sprawdzić, odwiedź stronę za pośrednictwem przeglądarki i wybierz odpowiednio pozycje Tito i Nadzorcy z UserList listy rozwijanej i RoleList Rozwijanej. Pamiętaj, że po usunięciu zaznaczenia roli Nadzorcy dla Tito z repeater w interfejsie "by user" Tito jest automatycznie usuwany z kontrolki GridView w interfejsie "by role". Dodanie Tito z powrotem do roli Nadzorcy z interfejsu "by role" automatycznie ponownie sprawdza pole wyboru Nadzorcy w interfejsie "by user".

Krok 4. Dostosowywanie elementu CreateUserWizard w celu uwzględnienia kroku "Określanie ról"

W samouczku Tworzenie kont użytkowników zobaczyliśmy, jak za pomocą kontrolki CreateUserWizard Web udostępnić interfejs do tworzenia nowego konta użytkownika. Kontrolka CreateUserWizard może być używana na jeden z dwóch sposobów:

  • Jako środek dla odwiedzających tworzenie własnego konta użytkownika w witrynie i
  • Jako środek dla administratorów do tworzenia nowych kont

W pierwszym przypadku użycia odwiedzający przychodzi do witryny i wypełnia wartość CreateUserWizard, wprowadzając informacje w celu zarejestrowania się w witrynie. W drugim przypadku administrator tworzy nowe konto dla innej osoby.

Gdy konto jest tworzone przez administratora dla innej osoby, może być przydatne zezwolenie administratorowi na określenie ról, do których należy nowe konto użytkownika. W samouczku Przechowywaniedodatkowych informacji o użytkowniku zobaczyliśmy, jak dostosować element CreateUserWizard przez dodanie dodatkowego WizardStepselementu . Przyjrzyjmy się, jak dodać dodatkowy krok do elementu CreateUserWizard w celu określenia ról nowego użytkownika.

CreateUserWizardWithRoles.aspx Otwórz stronę i dodaj kontrolkę CreateUserWizard o nazwie RegisterUserWithRoles. Ustaw właściwość kontrolki ContinueDestinationPageUrl na "~/Default.aspx". Ponieważ chodzi tutaj o to, że administrator będzie używać tej kontrolki CreateUserWizard do tworzenia nowych kont użytkowników, ustaw właściwość kontrolki LoginCreatedUser na False. Ta LoginCreatedUser właściwość określa, czy gość jest automatycznie zalogowany jako właśnie utworzony użytkownik, i domyślnie ma wartość True. Ustawiliśmy go na wartość Fałsz, ponieważ gdy administrator tworzy nowe konto, chcemy, aby był zalogowany jako sam.

Następnie wybierz pozycję "Dodaj/Usuń WizardSteps..." opcja z tagu inteligentnego CreateUserWizard i dodaj nowy WizardStepelement , ustawiając wartość ID na SpecifyRolesStep. Przenieś element SpecifyRolesStep WizardStep tak, aby był dostępny po kroku "Zarejestruj się w nowym koncie", ale przed krokiem "Complete" (Ukończ). WizardStepUstaw właściwość "sTitle" na "Określ role", jej StepType właściwość na Step, a jej AllowReturn właściwość na Wartość False.

Zrzut ekranu przedstawiający wybrane właściwości Określ role w oknie Kreator kolekcji kroków.

Rysunek 11. Dodawanie "Określ role" WizardStep do elementu CreateUserWizard (kliknij, aby wyświetlić obraz pełnowymiarowy)

Po tej zmianie znacznik deklaratywny createUserWizard powinien wyglądać następująco:

<asp:CreateUserWizard ID="RegisterUserWithRoles" runat="server" 
     ContinueDestinationPageUrl="~/Default.aspx" LoginCreatedUser="False"> 

     <WizardSteps> 
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server"> 
          </asp:CreateUserWizardStep> 
          <asp:WizardStep ID="SpecifyRolesStep" runat="server" StepType="Step" 

               Title="Specify Roles" AllowReturn="False"> 
          </asp:WizardStep> 
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server"> 
          </asp:CompleteWizardStep> 
     </WizardSteps> 

</asp:CreateUserWizard>

W obszarze "Określ role" WizardStepdodaj element CheckBoxList o nazwie RoleList. Ta lista CheckBoxList wyświetli listę dostępnych ról, umożliwiając osobie odwiedzającej stronę sprawdzenie, do jakich ról należy nowo utworzony użytkownik.

Pozostajemy z dwoma zadaniami kodowania: najpierw musimy wypełnić RoleList listę CheckBoxList rolami w systemie. Po drugie musimy dodać utworzonego użytkownika do wybranych ról, gdy użytkownik przejdzie z kroku "Określ role" do kroku "Ukończono". Możemy wykonać pierwsze zadanie w procedurze obsługi zdarzeń Page_Load . Poniższy kod programowo odwołuje się do kontrolki RoleList CheckBox podczas pierwszej wizyty na stronie i wiąże role w systemie z nim.

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Reference the SpecifyRolesStep WizardStep 
          WizardStep SpecifyRolesStep = RegisterUserWithRoles.FindControl("SpecifyRolesStep") as WizardStep; 

          // Reference the RoleList CheckBoxList 
          CheckBoxList RoleList = SpecifyRolesStep.FindControl("RoleList") as CheckBoxList; 

          // Bind the set of roles to RoleList 
          RoleList.DataSource = Roles.GetAllRoles(); 
          RoleList.DataBind(); 
     } 
}

Powyższy kod powinien wyglądać znajomo. W samouczku Przechowywaniedodatkowych informacji o użytkowniku użyliśmy dwóch FindControl instrukcji, aby odwołać się do kontrolki sieci Web z poziomu niestandardowego WizardStepelementu . Kod, który wiąże role z listą CheckBoxList, został pobrany z wcześniejszej wersji tego samouczka.

Aby wykonać drugie zadanie programistyczne, musimy wiedzieć, kiedy krok "Określ role" został ukończony. Pamiętaj, że zdarzenie CreateUserWizard jest ActiveStepChanged uruchamiane za każdym razem, gdy odwiedzający przechodzi od jednego kroku do drugiego. W tym miejscu możemy określić, czy użytkownik osiągnął krok "Ukończono"; jeśli tak, musimy dodać użytkownika do wybranych ról.

Utwórz procedurę obsługi zdarzeń ActiveStepChanged dla zdarzenia i dodaj następujący kod:

protected void RegisterUserWithRoles_ActiveStepChanged(object sender, EventArgs e) 
{ 
     // Have we JUST reached the Complete step? 
     if (RegisterUserWithRoles.ActiveStep.Title == "Complete") 
     { 
          // Reference the SpecifyRolesStep WizardStep 
          WizardStep SpecifyRolesStep = RegisterUserWithRoles.FindControl("SpecifyRolesStep") as WizardStep; 

          // Reference the RoleList CheckBoxList 
          CheckBoxList RoleList = SpecifyRolesStep.FindControl("RoleList") as CheckBoxList; 

          // Add the checked roles to the just-added user 
          foreach (ListItem li in RoleList.Items) 

          { 
               if (li.Selected) 
                    Roles.AddUserToRole(RegisterUserWithRoles.UserName, li.Text); 
          } 
     } 
}

Jeśli użytkownik właśnie osiągnął krok "Ukończono", program obsługi zdarzeń wylicza elementy RoleList CheckBoxList i właśnie utworzony użytkownik zostanie przypisany do wybranych ról.

Odwiedź tę stronę za pośrednictwem przeglądarki. Pierwszym krokiem w artykule CreateUserWizard jest standardowy krok "Zarejestruj się na nowe konto", który wyświetla monit o nazwę użytkownika, hasło, adres e-mail i inne informacje o kluczu. Wprowadź informacje, aby utworzyć nowego użytkownika o nazwie Wanda.

Tworzenie nowego użytkownika o nazwie Wanda

Rysunek 12. Tworzenie nowego użytkownika o nazwie Wanda (kliknij, aby wyświetlić obraz pełnowymiarowy)

Kliknij przycisk "Utwórz użytkownika". Element CreateUserWizard wewnętrznie wywołuje metodę Membership.CreateUser , tworząc nowe konto użytkownika, a następnie przechodzi do następnego kroku "Określ role". W tym miejscu są wyświetlane role systemowe. Zaznacz pole wyboru Nadzorcy i kliknij przycisk Dalej.

Tworzenie Wanda członka roli nadzorców

Rysunek 13. Utwórz Wanda członka roli nadzorców (kliknij, aby wyświetlić obraz pełnowymiarowy)

Kliknięcie przycisku Dalej powoduje powrót i zaktualizowanie ActiveStep kroku "Ukończono". W programie obsługi zdarzeń ActiveStepChanged ostatnio utworzone konto użytkownika jest przypisywane do roli Nadzorcy. Aby to sprawdzić, wróć do UsersAndRoles.aspx strony i wybierz pozycję Nadzorcy z listy rozwijanej RoleList . Jak pokazano na rysunku 14, nadzorcy składają się teraz z trzech użytkowników: Bruce'a, Tito i Wandy.

Bruce, Tito i Wanda są wszystkimi przełożonymi

Rysunek 14. Bruce, Tito i Wanda to Wszyscy nadzorcy (kliknij, aby wyświetlić obraz pełnowymiarowy)

Podsumowanie

Struktura Role oferuje metody pobierania informacji o rolach i metodach określonego użytkownika w celu określenia, do czego należą użytkownicy do określonej roli. Ponadto istnieje wiele metod dodawania i usuwania co najmniej jednego użytkownika do co najmniej jednej roli. W tym samouczku skupiliśmy się tylko na dwóch z następujących metod: AddUserToRole i RemoveUserFromRole. Istnieją dodatkowe warianty służące do dodawania wielu użytkowników do jednej roli i przypisywania wielu ról do jednego użytkownika.

W tym samouczku przedstawiono również rozszerzenie kontrolki CreateUserWizard w celu uwzględnienia elementu w WizardStep celu określenia nowo utworzonych ról użytkownika. Taki krok może pomóc administratorowi usprawnić proces tworzenia kont użytkowników dla nowych użytkowników.

W tym momencie widzieliśmy, jak tworzyć i usuwać role oraz jak dodawać i usuwać użytkowników z ról. Ale musimy jeszcze przyjrzeć się zastosowaniu autoryzacji opartej na rolach. W poniższym samouczku przyjrzymy się zdefiniowaniu reguł autoryzacji adresów URL w oparciu o rolę, a także o tym, jak ograniczyć funkcjonalność na poziomie strony na podstawie aktualnie zalogowanych ról użytkownika.

Szczęśliwe programowanie!

Dalsze informacje

Aby uzyskać więcej informacji na temat tematów omówionych w tym samouczku, zapoznaj się z następującymi zasobami:

Informacje o autorze

Scott Mitchell, autor wielu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Scott można dotrzeć pod mitchell@4guysfromrolla.com adresem lub za pośrednictwem swojego bloga pod adresem http://ScottOnWriting.NET.

Specjalne podziękowania...

Ta seria samouczków została przejrzyona przez wielu przydatnych recenzentów. Głównym recenzentem tego samouczka była Teresa Murphy. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi linię na mitchell@4GuysFromRolla.com