Поделиться через


Сохранение дополнительных сведений о пользователе (C#)

Скотт Митчелл

Примечание

С момента написания этой статьи поставщики членства ASP.NET были заменены ASP.NET Identity. Мы настоятельно рекомендуем обновить приложения для использования платформы ASP.NET Identity , а не поставщиков членства, которые были представлены на момент написания этой статьи. ASP.NET Identity имеет ряд преимуществ по сравнению с системой членства ASP.NET, в том числе :

  • более высокая производительность;
  • Улучшенная расширяемость и тестируемость
  • Поддержка OAuth, OpenID Connect и двухфакторной проверки подлинности
  • Поддержка удостоверений на основе утверждений
  • Улучшенное взаимодействие с ASP.Net Core

Скачать код или скачать PDF-файл

В этом руководстве мы ответим на этот вопрос, создав очень зачаточные приложения гостевой книги. При этом мы рассмотрим различные варианты моделирования сведений о пользователях в базе данных, а затем узнаем, как связать эти данные с учетными записями пользователей, созданными платформой членства.

Введение

ASP. Платформа членства NET предлагает гибкий интерфейс для управления пользователями. API членства включает методы проверки учетных данных, получения сведений о вошедшего в систему пользователя, создания новой учетной записи пользователя и удаления учетной записи пользователя. Каждая учетная запись пользователя на платформе членства содержит только свойства, необходимые для проверки учетных данных и выполнения важных задач, связанных с учетной записью пользователя. Об этом свидетельствуют методы и свойства MembershipUser класса , который моделирует учетную запись пользователя на платформе членства. Этот класс имеет свойства, такие как UserName, Emailи IsLockedOut, и методы, такие как GetPassword и UnlockUser.

Часто приложениям требуется хранить дополнительные сведения о пользователях, не включенные в платформу членства. Например, интернет-магазину может потребоваться разрешить каждому пользователю хранить адреса доставки и выставления счетов, платежные сведения, предпочтения доставки и контактный номер телефона. Кроме того, каждый заказ в системе связан с определенной учетной записью пользователя.

Класс MembershipUser не включает такие свойства, как PhoneNumber или DeliveryPreferences .PastOrders Как же отслеживать сведения о пользователе, необходимые приложению, и интегрировать их с платформой членства? В этом руководстве мы ответим на этот вопрос, создав очень зачаточные приложения гостевой книги. При этом мы рассмотрим различные варианты моделирования сведений о пользователях в базе данных, а затем узнаем, как связать эти данные с учетными записями пользователей, созданными платформой членства. Приступим к работе!

Шаг 1. Создание модели данных приложения Гостевой книги

Существует множество методов, которые можно использовать для сбора сведений о пользователях в базе данных и их связывания с учетными записями пользователей, созданными платформой членства. Чтобы проиллюстрировать эти методы, необходимо дополнить учебное веб-приложение, чтобы оно записывало какие-то данные, связанные с пользователями. (В настоящее время модель данных приложения содержит только таблицы служб приложений, необходимые для SqlMembershipProvider.)

Давайте создадим очень простое приложение гостевой книги, в котором пользователь, прошедший проверку подлинности, может оставить комментарий. В дополнение к хранению комментариев гостевой книги, давайте разрешим каждому пользователю хранить свой родной город, домашнюю страницу и подпись. Если это указано, то родной город, домашняя страница и подпись пользователя будут отображаться в каждом сообщении, оставленном в гостевой книге.

GuestbookCommentsДобавление таблицы

Чтобы записать комментарии гостевой книги, необходимо создать таблицу базы данных с именем GuestbookComments , которая содержит такие столбцы, как CommentId, Subject, Bodyи CommentDate. Нам также нужно, чтобы каждая запись в GuestbookComments таблице ссылались на пользователя, который оставил комментарий.

Чтобы добавить эту таблицу в базу данных, перейдите к Обозреватель базы данных в Visual Studio и изучите SecurityTutorials базу данных. Щелкните правой кнопкой мыши папку Таблицы и выберите команду Добавить новую таблицу. Откроется интерфейс, позволяющий определить столбцы для новой таблицы.

Добавление новой таблицы в базу данных SecurityTutorials

Рис. 1. Добавление новой таблицы в SecurityTutorials базу данных (щелкните для просмотра полноразмерного изображения)

Затем определите GuestbookCommentsстолбцы . Начните с добавления столбца с именем CommentId типа uniqueidentifier. Этот столбец будет уникальным образом идентифицировать каждый комментарий в гостевой книге, поэтому запретить NULL s и пометить его как первичный ключ таблицы. Вместо того чтобы указывать значение для CommentId поля в каждом INSERT, можно указать, что новое uniqueidentifier значение должно быть автоматически создано для этого поля в , INSERT задав для столбца значение NEWID()по умолчанию . После добавления этого первого поля, помечая его как первичный ключ и задав его значение по умолчанию, ваш экран должен выглядеть так же, как на снимке экрана, показанном на рисунке 2.

Добавление основного столбца с именем CommentId

Рис. 2. Добавление основного столбца с именем CommentId (щелкните для просмотра полноразмерного изображения)

Затем добавьте столбец с именем Subject типа nvarchar(50) и столбец с именем Body типа nvarchar(MAX), запретив NULL s в обоих столбцах. После этого добавьте столбец с именем CommentDate типа datetime. Запретить NULL и задать CommentDate для столбца значение getdate()по умолчанию .

Остается только добавить столбец, который связывает учетную запись пользователя с каждым комментарием гостевой книги. Одним из вариантов является добавление столбца с именем UserName типа nvarchar(256). Это подходящий вариант при использовании поставщика членства, отличного от SqlMembershipProvider. Но при использовании SqlMembershipProvider, как это описано в этой серии руководств, UserName столбец в aspnet_Users таблице не гарантируется, что он будет уникальным. Первичный aspnet_Users ключ таблицы имеет UserId тип uniqueidentifier. Поэтому для GuestbookComments таблицы требуется столбец с именем UserId типа uniqueidentifier (запретить NULL значения). Добавьте этот столбец.

Примечание

Как мы обсуждали в учебнике Создание схемы членства в SQL Server, платформа членства предназначена для предоставления нескольким веб-приложениям с разными учетными записями пользователей совместно использовать одно и то же хранилище пользователей. Это делается путем секционирования учетных записей пользователей по разным приложениям. И хотя каждое имя пользователя гарантированно будет уникальным в пределах приложения, одно и то же имя пользователя может использоваться в разных приложениях, использующих одно и то же хранилище пользователей. В таблице есть составное UNIQUE ограничение aspnet_Users для UserName полей и ApplicationId , но не для одного UserName только поля. Следовательно, в таблице aspnet_Users может быть две (или более) записи с одинаковым UserName значением. Однако UNIQUE есть ограничение на aspnet_Users поле таблицы UserId (так как оно является первичным ключом). Ограничение UNIQUE важно, так как без него невозможно установить ограничение внешнего ключа между GuestbookComments таблицами и aspnet_Users .

После добавления столбца UserId сохраните таблицу, щелкнув значок Сохранить на панели инструментов. Назовите новую таблицу GuestbookComments.

У нас есть последняя проблема с таблицей GuestbookComments : необходимо создать ограничение внешнего ключа между столбцом GuestbookComments.UserId и столбцом aspnet_Users.UserId . Для этого щелкните значок Связь на панели инструментов, чтобы открыть диалоговое окно Связи внешних ключей. (Кроме того, можно запустить это диалоговое окно, перейдя в меню Таблица Designer и выбрав Связи.)

Нажмите кнопку Добавить в левом нижнем углу диалогового окна Связи внешних ключей. Это добавит новое ограничение внешнего ключа, хотя нам по-прежнему нужно определить таблицы, участвующие в связи.

Использование диалогового окна Связи внешних ключей для управления ограничениями внешнего ключа таблицы

Рис. 3. Использование диалогового окна "Связи внешних ключей" для управления ограничениями внешнего ключа таблицы (щелкните для просмотра полноразмерного изображения)

Затем щелкните значок с многоточием в строке "Спецификации таблиц и столбцов" справа. Откроется диалоговое окно Таблицы и столбцы, в котором можно указать таблицу и столбец первичного GuestbookComments ключа, а также столбец внешнего ключа из таблицы. В частности, выберите aspnet_Users и UserId в качестве таблицы и столбца первичного GuestbookComments ключа, а UserId в таблице — столбец внешнего ключа (см. рис. 4). Определив таблицы и столбцы первичного и внешнего ключей, нажмите кнопку ОК, чтобы вернуться в диалоговое окно Связи внешних ключей.

Установка ограничения внешнего ключа между таблицами aspnet_Users и GuesbookComments

Рис. 4. Установка ограничения внешнего ключа между aspnet_Users таблицами и GuesbookComments (щелкните для просмотра полноразмерного изображения)

На этом этапе установлено ограничение внешнего ключа. Наличие этого ограничения обеспечивает реляционную целостность между двумя таблицами, гарантируя, что запись гостевой книги никогда не будет ссылаться на несуществующую учетную запись пользователя. По умолчанию ограничение внешнего ключа запрещает удаление родительской записи при наличии соответствующих дочерних записей. То есть, если пользователь делает один или несколько комментариев гостевой книги, а затем мы попытаемся удалить ее учетную запись, удаление завершится ошибкой, если его комментарии гостевой книги не будут удалены первым.

Ограничения внешнего ключа можно настроить для автоматического удаления связанных дочерних записей при удалении родительской записи. Другими словами, мы можем настроить это ограничение внешнего ключа, чтобы записи гостевой книги пользователя автоматически удалялись при удалении учетной записи пользователя. Для этого разверните раздел "Спецификация INSERT and UPDATE" и задайте для свойства "Удалить правило" значение Каскад.

Настройка ограничения внешнего ключа для каскадных удалений

Рис. 5. Настройка ограничения внешнего ключа для каскадных удалений (щелкните для просмотра полноразмерного изображения)

Чтобы сохранить ограничение внешнего ключа, нажмите кнопку Закрыть, чтобы выйти из связи внешнего ключа. Затем щелкните значок Сохранить на панели инструментов, чтобы сохранить таблицу и эту связь.

Хранение домашней страницы, домашней страницы и подписи пользователя

В GuestbookComments таблице показано, как хранить информацию, которая использует отношение "один ко многим" с учетными записями пользователей. Так как каждая учетная запись пользователя может иметь произвольное количество связанных комментариев, эта связь моделировается путем создания таблицы для хранения набора примечаний, включающего столбец, который связывает каждый комментарий с конкретным пользователем. При использовании SqlMembershipProviderэту связь лучше всего установить, создав столбец с именем UserId типа uniqueidentifier и ограничение внешнего ключа между этим столбцом и aspnet_Users.UserId.

Теперь нам нужно связать три столбца с каждой учетной записью пользователя, чтобы сохранить родной город, домашнюю страницу и подпись пользователя, которые будут отображаться в комментариях к гостевой книге. Это можно сделать несколькими способами.

  • Добавление новых столбцов вaspnet_UsersИлиaspnet_MembershipТаблицы. Я бы не рекомендовал этот подход, так как он изменяет схему, используемую .SqlMembershipProvider Это решение может вернуться, чтобы преследовать вас вниз по дороге. Например, что делать, если в будущей версии ASP.NET используется другая SqlMembershipProvider схема. Корпорация Майкрософт может включить средство для переноса данных ASP.NET 2.0 SqlMembershipProvider в новую схему, но если вы изменили схему ASP.NET 2.0 SqlMembershipProvider , такое преобразование может оказаться невозможным.

  • Используйте ASP. Платформа профилей NET, определяющая свойство профиля для родного города, домашней страницы и подписи. ASP.NET включает платформу профилей, предназначенную для хранения дополнительных пользовательских данных. Как и платформа членства, платформа профилей создается на основе модели поставщика. Платформа .NET Framework поставляется с SqlProfileProvider sthat хранит данные профиля в базе данных SQL Server. Фактически в базе данных уже есть таблица, используемая SqlProfileProvider (aspnet_Profile), так как она была добавлена при добавлении служб приложений в учебнике Создание схемы членства в SQL Server.
    Main преимущество платформы профилей заключается в том, что она позволяет разработчикам определять свойства профиля в Web.config . Не нужно писать код для сериализации данных профиля в базовое хранилище данных и из него. Короче говоря, невероятно легко определить набор свойств профиля и работать с ними в коде. Однако система профилей оставляет желать лучшего, когда дело доходит до управления версиями, поэтому если у вас есть приложение, в которое вы ожидаете, что позже будут добавлены новые пользовательские свойства или существующие свойства будут удалены или изменены, то платформа профилей может быть не лучшим вариантом. Кроме того, свойства SqlProfileProvider профиля хранятся в строго денормализованном режиме, что делает практически невозможным выполнение запросов непосредственно к данным профиля (например, количество пользователей в родном городе Нью-йорк).
    Дополнительные сведения о платформе профилей см. в разделе "Дополнительные сведения" в конце этого руководства.

  • Добавьте эти три столбца в новую таблицу в базе данных и установите связь "один к одному" между этой таблицей иaspnet_Users. Этот подход включает в себя немного больше работы, чем с платформой профилей, но обеспечивает максимальную гибкость в модели дополнительных свойств пользователей в базе данных. Это параметр, который мы будем использовать в этом руководстве.

Мы создадим таблицу с именем UserProfiles , чтобы сохранить родной город, домашнюю страницу и подпись для каждого пользователя. Щелкните правой кнопкой мыши папку Таблицы в окне Обозреватель базы данных и выберите создать таблицу. Присвойте первому столбцу UserIduniqueidentifierимя и задайте для его типа значение . Запретить NULL значения и пометить столбец как первичный ключ. Затем добавьте столбцы с именами: HomeTown типа nvarchar(50); HomepageUrl типа nvarchar(100); и сигнатура типа nvarchar(500). Каждый из этих трех столбцов может принимать NULL значение.

Создание таблицы UserProfiles

Рис. 6. Создание UserProfiles таблицы (щелкните для просмотра полноразмерного изображения)

Сохраните таблицу и назовите ее UserProfiles. Наконец, установите ограничение внешнего ключа между полем UserProfilesUserId таблицы и полем aspnet_Users.UserId . Как и в случае с ограничением внешнего ключа между GuestbookComments таблицами и aspnet_Users , это ограничение каскадно удаляет. UserId Так как поле в UserProfiles является первичным ключом, это гарантирует, что в UserProfiles таблице будет не более одной записи для каждой учетной записи пользователя. Этот тип связи называется "один к одному".

Теперь, когда у нас есть модель данных, мы готовы использовать ее. На шагах 2 и 3 мы рассмотрим, как вошедший в систему пользователь может просматривать и изменять сведения о родном городе, домашней странице и подписи. На шаге 4 мы создадим интерфейс для пользователей, прошедших проверку подлинности, для отправки новых комментариев в гостевую книгу и просмотра существующих.

Шаг 2. Отображение родного города пользователя, домашней страницы и подписи

Существует множество способов, позволяющих вошедшего в систему пользователя просматривать и изменять свой родной город, домашнюю страницу и сведения о подписях. Можно вручную создать пользовательский интерфейс с элементами управления TextBox и Label или использовать один из веб-элементов управления данными, например Элемент управления DetailsView. Чтобы выполнить базу данных SELECT и UPDATE инструкции, можно написать ADO.NET код в классе кода программной части страницы или использовать декларативный подход с SqlDataSource. В идеале наше приложение должно содержать многоуровневую архитектуру, которую можно вызвать программным способом из класса кода программной части страницы или декларативно с помощью элемента управления ObjectDataSource.

Так как эта серия руководств посвящена проверке подлинности на основе форм, авторизации, учетным записям пользователей и ролям, подробного обсуждения этих различных вариантов доступа к данным и причин, почему многоуровневая архитектура предпочтительнее, чем выполнение инструкций SQL непосредственно на странице ASP.NET. Я собираюсь ознакомиться с использованием DetailsView и SqlDataSource — самого быстрого и простого варианта, но обсуждаемые понятия, безусловно, можно применить к альтернативным веб-элементам управления и логике доступа к данным. Дополнительные сведения о работе с данными в ASP.NET см. в статье Работа с данными в ASP.NET 2.0 .

Откройте страницу в папке Membership и добавьте элемент управления DetailsView на страницу, задав для его ID свойства значение UserProfile и очистив его Width свойства и Height .AdditionalUserInfo.aspx Разверните смарт-тег DetailsView и привяжите его к новому элементу управления источником данных. Откроется мастер настройки DataSource (см. рис. 7). На первом шаге необходимо указать тип источника данных. Так как мы собираемся подключиться напрямую к SecurityTutorials базе данных, щелкните значок База данных, указав в ID качестве UserProfileDataSource.

Добавление нового элемента управления SqlDataSource с именем UserProfileDataSource

Рис. 7. Добавление нового элемента управления SqlDataSource с именем UserProfileDataSource (щелкните для просмотра полноразмерного изображения)

На следующем экране появится запрос на использование базы данных. Мы уже определили строку подключения в Web.config для SecurityTutorials базы данных. Это имя строки подключения — SecurityTutorialsConnectionString должно находиться в раскрывающемся списке. Выберите этот параметр и нажмите кнопку Далее.

Выберите SecurityTutorialsConnectionString в списке Drop-Down

Рис. 8. Выбор SecurityTutorialsConnectionString из списка Drop-Down (щелкните, чтобы просмотреть полноразмерное изображение)

На следующем экране нам будет предлагаться указать таблицу и столбцы для запроса. Выберите таблицу UserProfiles из раскрывающегося списка и проверка все столбцы.

Возврат всех столбцов из таблицы UserProfiles

Рис. 9. Возврат всех столбцов из UserProfiles таблицы (щелкните для просмотра полноразмерного изображения)

Текущий запрос на рис. 9 возвращает все записи в UserProfiles, но нас интересует только текущая запись пользователя. Чтобы добавить WHERE предложение, нажмите кнопку WHERE , чтобы открыть диалоговое окно Добавление WHERE предложения (см. рис. 10). Здесь можно выбрать столбец для фильтрации, оператор и источник параметра фильтра. Выберите UserId в качестве столбца и "=" в качестве оператора.

К сожалению, нет встроенного источника параметров для возврата значения текущего UserId вошедшего в систему пользователя. Нам потребуется захватить это значение программным способом. Поэтому задайте для раскрывающегося списка Источник значение Нет, нажмите кнопку Добавить, чтобы добавить параметр, а затем нажмите кнопку ОК.

Добавление параметра фильтра в столбец UserId

Рис. 10. Добавление параметра фильтра в UserId столбец (щелкните для просмотра полноразмерного изображения)

После нажатия кнопки ОК вы вернеться на экран, показанный на рис. 9. Однако на этот раз SQL-запрос в нижней части экрана должен содержать WHERE предложение . Нажмите кнопку Далее, чтобы перейти к экрану "Тестовый запрос". Здесь можно выполнить запрос и просмотреть результаты. Чтобы завершить работу мастера, нажмите кнопку Готово.

После завершения работы мастера настройки DataSource Visual Studio создает элемент управления SqlDataSource на основе параметров, указанных в мастере. Кроме того, он вручную добавляет BoundFields в DetailsView для каждого столбца, возвращаемого sqlDataSource SelectCommand. Нет необходимости отображать UserId поле в DetailsView, так как пользователю не нужно знать это значение. Это поле можно удалить непосредственно из декларативной разметки элемента управления DetailsView или щелкнув ссылку "Изменить поля" в смарт-теге.

На этом этапе декларативная разметка страницы должна выглядеть примерно так:

<asp:DetailsView ID="UserProfile" runat="server"
     AutoGenerateRows="False" DataKeyNames="UserId"
     DataSourceID="UserProfileDataSource">
     <Fields>
          <asp:BoundField DataField="HomeTown" HeaderText="HomeTown"
               SortExpression="HomeTown" />
          <asp:BoundField DataField="HomepageUrl" HeaderText="HomepageUrl"
               SortExpression="HomepageUrl" />
          <asp:BoundField DataField="Signature" HeaderText="Signature"
               SortExpression="Signature" />
     </Fields>
</asp:DetailsView>
<asp:SqlDataSource ID="UserProfileDataSource" runat="server"
          ConnectionString="<%$ ConnectionStrings:SecurityTutorialsConnectionString %>"
          SelectCommand="SELECT [UserId], [HomeTown], [HomepageUrl], [Signature] FROM
          [UserProfiles] WHERE ([UserId] = @UserId)">
     <SelectParameters>
          <asp:Parameter Name="UserId" Type="Object" />
     </SelectParameters>
</asp:SqlDataSource>

Перед выбором данных необходимо программно задать для параметра элемента управления UserId SqlDataSource значение текущего пользователя UserId , выполнившего вход. Это можно сделать, создав обработчик событий для события SqlDataSource Selecting и добавив в него следующий код:

protected void UserProfileDataSource_Selecting(object sender, 
          SqlDataSourceSelectingEventArgs e)
{
     // Get a reference to the currently logged on user
     MembershipUser currentUser = Membership.GetUser();
 
     // Determine the currently logged on user's UserId value
     Guid currentUserId = (Guid)currentUser.ProviderUserKey;
 
     // Assign the currently logged on user's UserId to the @UserId parameter
     e.Command.Parameters["@UserId"].Value = currentUserId;
}

Приведенный выше код начинается с получения ссылки на текущего пользователя, выполнившего вход в систему, путем вызова Membership метода класса GetUser . MembershipUser Возвращает объект , свойство которого ProviderUserKey содержит UserIdобъект . Затем UserId значение присваивается параметру SqlDataSource @UserId .

Примечание

Метод Membership.GetUser() возвращает сведения о вошедшего в систему пользователя. Если анонимный пользователь посещает страницу, он возвращает значение null. В этом случае при попытке чтения свойства в следующей строке ProviderUserKey кода будет NullReferenceException возникать . Конечно, нам не нужно беспокоиться о Membership.GetUser() возврате null значения на странице, так как мы настроили авторизацию URL-адреса в AdditionalUserInfo.aspx предыдущем руководстве, чтобы только прошедшие проверку подлинности пользователи могли получить доступ к ASP.NET ресурсам в этой папке. Если вам нужно получить доступ к сведениям о вошедшего в систему пользователя на странице, на которой разрешен анонимный доступ, перед ссылкой на его свойства обязательно проверка, что из метода возвращается объект, отличныйnull MembershipUser от GetUser() объекта .

Если вы перейдете на страницу AdditionalUserInfo.aspx через браузер, вы увидите пустую страницу, так как мы еще не добавили строки в таблицу UserProfiles . На шаге 6 мы рассмотрим, как настроить элемент управления CreateUserWizard для автоматического добавления новой строки в UserProfiles таблицу при создании новой учетной записи пользователя. Однако сейчас необходимо вручную создать запись в таблице.

Перейдите к Обозреватель базы данных в Visual Studio и разверните папку Таблицы. Щелкните таблицу правой aspnet_Users кнопкой мыши и выберите пункт "Показать данные таблицы", чтобы просмотреть записи в таблице. Сделайте то же самое для UserProfiles таблицы. На рисунке 11 показаны эти результаты при вертикальном расположении плитки. В моей базе данных в настоящее aspnet_Users время есть записи для Брюса, Фреда и Тито, но нет записей в UserProfiles таблице.

Отображается содержимое таблиц aspnet_Users и UserProfiles.

Рис. 11. Содержимое aspnet_Users и UserProfiles таблицы отображаются (щелкните для просмотра полноразмерного изображения)

Добавьте новую запись в таблицу UserProfiles , вручную введя значения для HomeTownполей , HomepageUrlи Signature . Самый простой способ получить допустимое UserId значение в новой UserProfiles записи — выбрать UserId поле из определенной учетной записи пользователя в aspnet_Users таблице и скопировать и вставить его в UserId поле в UserProfiles. На рисунке 12 показана UserProfiles таблица после добавления новой записи для Брюса.

Запись добавлена в UserProfiles для Брюса

Рис. 12. Запись была добавлена UserProfiles в для Брюса (щелкните, чтобы просмотреть полноразмерное изображение)

Вернитесь на страницу AdditionalUserInfo.aspx , вошедший в систему под учетной записью Брюса. Как показано на рисунке 13, отображаются параметры Брюса.

Для текущего посещаемого пользователя отображаются его параметры

Рис. 13. Для текущего посещающего пользователя отображаются его параметры (щелкните для просмотра полноразмерного изображения)

Примечание

Добавьте записи в таблицу UserProfiles для каждого пользователя членства вручную. На шаге 6 мы рассмотрим, как настроить элемент управления CreateUserWizard для автоматического добавления новой строки в UserProfiles таблицу при создании новой учетной записи пользователя.

Шаг 3. Разрешение пользователю изменять свой родной город, домашнюю страницу и подпись

На этом этапе вошедший в систему пользователь может просматривать свой родной город, домашнюю страницу и параметры подписи, но пока не может изменить их. Давайте обновим элемент управления DetailsView, чтобы данные можно было редактировать.

Первое, что нам нужно сделать, — это добавить UpdateCommand для SqlDataSource, указав выполняемую инструкцию UPDATE и соответствующие параметры. Выберите SqlDataSource и в окне Свойства щелкните многоточие рядом со свойством UpdateQuery, чтобы открыть диалоговое окно Редактор команд и параметров. Введите в текстовое поле следующую UPDATE инструкцию:

UPDATE UserProfiles SET
     HomeTown = @HomeTown,
     HomepageUrl = @HomepageUrl,
     Signature = @Signature
WHERE UserId = @UserId

Затем нажмите кнопку "Обновить параметры", которая создаст параметр в коллекции элемента управления UpdateParameters SqlDataSource для каждого из параметров в инструкции UPDATE . Оставьте источник для всех параметров равным Нет и нажмите кнопку ОК, чтобы завершить диалоговое окно.

Указание команд updateCommand и UpdateParameters sqlDataSource

Рис. 14. Укажите sqlDataSource UpdateCommand и UpdateParameters (щелкните для просмотра полноразмерного изображения)

Из-за добавлений, внесенных в элемент управления SqlDataSource, элемент управления DetailsView теперь может поддерживать редактирование. В смарт-теге DetailsView проверка флажок "Включить редактирование". При этом commandField добавляется в коллекцию элемента управления Fields со свойством ShowEditButton True. При этом отрисовывается кнопка Изменить, когда DetailsView отображается в режиме только для чтения, и кнопки Обновить и Отмена при отображении в режиме редактирования. Вместо того, чтобы пользователь нажимал кнопку Изменить, мы можем настроить отрисовку DetailsView в состоянии "всегда редактируемый", задав для свойства элемента управления DefaultMode DetailsView значение Edit.

После этих изменений декларативная разметка элемента управления DetailsView должна выглядеть примерно так:

<asp:DetailsView ID="UserProfile" runat="server"
          AutoGenerateRows="False" DataKeyNames="UserId"
          DataSourceID="UserProfileDataSource" DefaultMode="Edit">
     <Fields>
          <asp:BoundField DataField="HomeTown" HeaderText="HomeTown"
               SortExpression="HomeTown" />
          <asp:BoundField DataField="HomepageUrl" HeaderText="HomepageUrl"
               SortExpression="HomepageUrl" />
          <asp:BoundField DataField="Signature" HeaderText="Signature"
               SortExpression="Signature" />
          <asp:CommandField ShowEditButton="True" />
     </Fields>
</asp:DetailsView>

Обратите внимание на добавление CommandField и DefaultMode свойства .

Протестируйте эту страницу в браузере. При посещении с пользователем, у которого есть соответствующая запись в UserProfiles, параметры пользователя отображаются в редактируемом интерфейсе.

DetailsView отрисовывает редактируемый интерфейс

Рис. 15. DetailsView отрисовывает редактируемый интерфейс (щелкните, чтобы просмотреть полноразмерное изображение)

Попробуйте изменить значения и нажать кнопку Обновить. Похоже, ничего не происходит. Существует обратная связь, и значения сохраняются в базе данных, но нет визуальной обратной связи о том, что сохранение произошло.

Чтобы устранить эту проблему, вернитесь в Visual Studio и добавьте элемент управления Метка над DetailsView. Задайте для свойства ID значение SettingsUpdatedMessage, для свойства Text — значение "Ваши параметры были обновлены", а для свойств Visible и EnableViewState — значение false.

<asp:Label ID="SettingsUpdatedMessage" runat="server"
     Text="Your settings have been updated."
     EnableViewState="false"
     Visible="false"></asp:Label>

Метка должна отображаться SettingsUpdatedMessage при каждом обновлении DetailsView. Для этого создайте обработчик событий для события DetailsView ItemUpdated и добавьте следующий код:

protected void UserProfile_ItemUpdated(object sender, DetailsViewUpdatedEventArgs e)
{
     SettingsUpdatedMessage.Visible = true;
}

Вернитесь на страницу AdditionalUserInfo.aspx через браузер и обновите данные. На этот раз отображается полезное сообщение о состоянии.

При обновлении параметров отображается короткое сообщение

Рис. 16. При обновлении параметров отображается короткое сообщение (щелкните для просмотра полноразмерного изображения)

Примечание

Интерфейс редактирования элемента управления DetailsView оставляет желать лучшего. В нем используются текстовые поля стандартного размера, но поле Подпись, вероятно, должно быть многострочное текстовое поле. Следует использовать RegularExpressionValidator, чтобы URL-адрес домашней страницы, если он был введен, начинался с "http://" или "https://". Кроме того, так как свойство элемента управления DetailsView имеет DefaultMode значение Edit, кнопка Отмена ничего не делает. Его следует удалить или перенаправить пользователя на другую страницу (например ~/Default.aspx, ). Я оставляю эти улучшения как упражнение для читателя.

В настоящее время на веб-сайте нет ссылок на страницу AdditionalUserInfo.aspx . Единственный способ связаться с ним — ввести URL-адрес страницы непосредственно в адресной строке браузера. Давайте добавим ссылку на эту страницу на Site.master странице master.

Напомним, что страница master содержит веб-элемент управления LoginView в contentPlaceHolderLoginContent, который отображает различные разметки для прошедших проверку подлинности и анонимных посетителей. Обновите элемент управления LoggedInTemplate LoginView, чтобы включить ссылку на страницу AdditionalUserInfo.aspx . После внесения этих изменений декларативная разметка элемента управления LoginView должна выглядеть примерно так:

<asp:LoginView ID="LoginView1" runat="server">
     <LoggedInTemplate>
          Welcome back,
          <asp:LoginName ID="LoginName1" runat="server" />.
          <br />
          <asp:HyperLink ID="lnkUpdateSettings" runat="server" 
               NavigateUrl="~/Membership/AdditionalUserInfo.aspx">
               Update Your Settings</asp:HyperLink>
     </LoggedInTemplate>
     <AnonymousTemplate>
          Hello, stranger.
     </AnonymousTemplate>
</asp:LoginView>

Обратите внимание на добавление lnkUpdateSettings элемента управления HyperLink в LoggedInTemplate. Используя эту ссылку, пользователи, прошедшие проверку подлинности, могут быстро перейти на страницу, чтобы просмотреть и изменить параметры своего родного города, домашней страницы и подписи.

Шаг 4. Добавление новых комментариев гостевой книги

На Guestbook.aspx этой странице пользователи, прошедшие проверку подлинности, могут просмотреть гостевую книгу и оставить комментарий. Начнем с создания интерфейса для добавления новых комментариев гостевой книги.

Откройте страницу Guestbook.aspx в Visual Studio и создайте пользовательский интерфейс, состоящий из двух элементов управления TextBox: один для темы нового комментария, а второй — для текста. Задайте для свойства первого элемента управления TextBox значение , а для его Columns свойства — значение 40, для второго IDTextModeMultiLineBody— значение , а Width для свойств и Rows — значение "95%" и 8 соответственно.SubjectID Чтобы завершить работу с пользовательским интерфейсом, добавьте веб-элемент управления Button с именем PostCommentButton и задайте для его Text свойства значение "Опубликовать комментарий".

Так как для каждого комментария гостевой книги требуется тема и текст, добавьте RequiredFieldValidator для каждого элемента TextBoxes. Присвойте свойству ValidationGroup этих элементов управления значение EnterComment; аналогичным образом задайте PostCommentButton для свойства элемента управления ValidationGroup значение EnterComment. Дополнительные сведения об ASP. Элементы управления проверки NET, проверка проверку формы в ASP.NET.

После создания пользовательского интерфейса декларативная разметка страницы должна выглядеть примерно так:

<h3>Leave a Comment</h3>
<p>
     <b>Subject:</b>
     <asp:RequiredFieldValidator ID="SubjectReqValidator" runat="server"
          ErrorMessage="You must provide a value for Subject"
          ControlToValidate="Subject" ValidationGroup="EnterComment">
     </asp:RequiredFieldValidator><br/>
     <asp:TextBox ID="Subject" Columns="40" runat="server"></asp:TextBox>
</p>
<p>
     <b>Body:</b>
     <asp:RequiredFieldValidator ID="BodyReqValidator" runat="server"
          ControlToValidate="Body"
          ErrorMessage="You must provide a value for Body" ValidationGroup="EnterComment">
     </asp:RequiredFieldValidator><br/>
     <asp:TextBox ID="Body" TextMode="MultiLine" Width="95%"
          Rows="8" runat="server"></asp:TextBox>
</p>
<p>
     <asp:Button ID="PostCommentButton" runat="server" 
          Text="Post Your Comment"
          ValidationGroup="EnterComment" />
</p>

После завершения пользовательского интерфейса наша следующая задача — вставить новую запись в таблицу GuestbookComments при щелчке PostCommentButton . Это можно сделать несколькими способами: мы можем написать ADO.NET код в обработчике событий Button Click ; добавить элемент управления SqlDataSource на страницу, настроить его InsertCommand, а затем вызвать его Insert метод из Click обработчика событий; или создать средний уровень, отвечающий за вставку новых комментариев гостевой книги, и вызвать эту функцию из Click обработчика событий. Так как мы рассмотрели использование SqlDataSource на шаге 3, давайте используем ADO.NET код здесь.

Примечание

Классы ADO.NET, используемые для программного доступа к данным из базы данных Microsoft SQL Server, находятся в System.Data.SqlClient пространстве имен . Может потребоваться импортировать это пространство имен в класс кода программной части страницы (т. е. using System.Data.SqlClient;).

Создайте обработчик событий для PostCommentButtonClick события и добавьте следующий код:

protected void PostCommentButton_Click(object sender, EventArgs e)
{
     if (!Page.IsValid)
          return;
 
     // Determine the currently logged on user's UserId
     MembershipUser currentUser = Membership.GetUser();
     Guid currentUserId = (Guid)currentUser.ProviderUserKey;
 
     // Insert a new record into GuestbookComments
     string connectionString = 
          ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
     string insertSql = "INSERT INTO GuestbookComments(Subject, Body, UserId) VALUES(@Subject,
               @Body, @UserId)";
 
     using (SqlConnection myConnection = new SqlConnection(connectionString))
     {
          myConnection.Open();
          SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
          myCommand.Parameters.AddWithValue("@Subject", Subject.Text.Trim());
          myCommand.Parameters.AddWithValue("@Body", Body.Text.Trim());
          myCommand.Parameters.AddWithValue("@UserId", currentUserId);
          myCommand.ExecuteNonQuery();
          myConnection.Close();
     }
 
     // "Reset" the Subject and Body TextBoxes
     Subject.Text = string.Empty;
     Body.Text = string.Empty;
}

Обработчик Click событий начинается с проверки допустимости предоставленных пользователем данных. Если это не так, обработчик событий завершает работу перед вставкой записи. При условии, что предоставленные данные являются допустимыми, текущее значение пользователя UserId , вошедшего в систему, извлекается и сохраняется в локальной переменной currentUserId . Это значение необходимо, так как необходимо указать UserId значение при вставке записи в GuestbookComments.

После этого строка подключения для SecurityTutorials базы данных извлекается из Web.config и INSERT указывается инструкция SQL. SqlConnection Затем создается и открывается объект . SqlCommand Затем создается объект и назначаются значения для параметров, используемых в запросеINSERT. Затем INSERT выполняется инструкция и соединение закрывается. В конце обработчика событий свойства и Body TextBoxes Text очищаются, Subject чтобы значения пользователя не сохранялись во время обратной передачи.

Протестируйте эту страницу в браузере. Так как эта страница находится в папке Membership , она недоступна анонимным посетителям. Поэтому необходимо сначала войти в систему (если это еще не сделано). Введите значение в Subject и Body TextBoxes и нажмите кнопку PostCommentButton . Это приведет к добавлению новой записи в GuestbookComments. При обратной отправке указанные тема и текст удаляются из textBoxes.

После нажатия кнопки PostCommentButton визуальный отзыв о добавлении комментария в гостевую книгу отсутствует. Нам по-прежнему нужно обновить эту страницу для отображения существующих комментариев гостевой книги, что мы сделаем на шаге 5. После этого только что добавленный комментарий появится в списке комментариев, обеспечивая адекватную визуальную обратную связь. На данный момент убедитесь, что комментарий гостевой книги сохранен, изучив содержимое GuestbookComments таблицы.

На рисунке 17 показано содержимое GuestbookComments таблицы после того, как остались два комментария.

Вы можете просмотреть комментарии гостевой книги в таблице GuestbookComments

Рис. 17. Вы можете просмотреть примечания гостевой книги GuestbookComments в таблице (щелкните, чтобы просмотреть полноразмерное изображение)

Примечание

Если пользователь пытается вставить комментарий гостевой книги, содержащий потенциально опасную разметку, например HTML, ASP.NET вызовет HttpRequestValidationExceptionисключение . Дополнительные сведения об этом исключении, причинах его возникновения и о том, как разрешить пользователям отправлять потенциально опасные значения, см. в техническом документе По запросу проверки.

Шаг 5. Перечисление существующих комментариев гостевой книги

Помимо примечаний, пользователь, посещающий страницу Guestbook.aspx , также должен иметь возможность просматривать существующие комментарии гостевой книги. Для этого добавьте элемент управления ListView с именем CommentList в нижнюю часть страницы.

Примечание

Элемент управления ListView является новым для ASP.NET версии 3.5. Он предназначен для отображения списка элементов в очень настраиваемом и гибком макете, но по-прежнему предлагает встроенные функции редактирования, вставки, удаления, разбиения по страницам и сортировки, такие как GridView. Если вы используете ASP.NET 2.0, вам потребуется использовать элемент управления DataList или Repeater. Дополнительные сведения об использовании ListView см. в записи блога Скотта Гатри, Элемент управления asp:ListView и моей статье Отображение данных с помощью элемента управления ListView.

Откройте смарт-тег ListView и в раскрывающемся списке Выбор источника данных привяжите элемент управления к новому источнику данных. Как мы видели на шаге 2, запустится мастер настройки источника данных. Щелкните значок База данных, присвойте результирующее имя SqlDataSource CommentsDataSourceи нажмите кнопку ОК. Затем выберите SecurityTutorialsConnectionString строку подключения из раскрывающегося списка и нажмите кнопку Далее.

На этом этапе на шаге 2 мы указали данные для запроса, выбрав таблицу UserProfiles из раскрывающегося списка и выбрав возвращаемые столбцы (см. рис. 9). Однако на этот раз мы хотим создать инструкцию SQL, которая извлекает не только записи из GuestbookComments, но и родной город, домашнюю страницу, подпись и имя пользователя комментатора. Поэтому установите переключатель "Указать пользовательскую инструкцию SQL или хранимую процедуру" и нажмите кнопку Далее.

Откроется экран "Определение пользовательских инструкций или хранимых процедур". Нажмите кнопку Построитель запросов, чтобы выполнить графическую сборку запроса. Построитель запросов начинается с запроса на указание таблиц, из которого требуется выполнить запрос. GuestbookCommentsВыберите таблицы , UserProfilesи aspnet_Users и нажмите кнопку ОК. Это приведет к добавлению всех трех таблиц в область конструктора. Так как в GuestbookCommentsтаблицах , UserProfilesи aspnet_Users существуют ограничения внешнего ключа, построитель запросов автоматически создает JOIN эти таблицы.

Остается только указать возвращаемые столбцы. GuestbookComments В таблице выберите Subjectстолбцы , Bodyи CommentDate ; возвращает HomeTownстолбцы , HomepageUrlи Signature из UserProfiles таблицы; возвращается UserName из aspnet_Users. Кроме того, добавьте "ORDER BY CommentDate DESC" в конец SELECT запроса, чтобы в первую очередь возвращались самые последние записи. После выбора этих элементов интерфейс построителя запросов должен выглядеть примерно так, как на снимке экрана на рис. 18.

Созданный запрос JOIN таблиц GuestbookComments, UserProfiles и aspnet_Users

Рис. 18. Созданный запрос JOINGuestbookCommentsс таблицами , UserProfilesи aspnet_Users (щелкните для просмотра полноразмерного изображения)

Нажмите кнопку ОК, чтобы закрыть окно построителя запросов и вернуться к экрану "Определение пользовательских инструкций или хранимых процедур". Нажмите кнопку Далее, чтобы перейти к экрану "Тестовый запрос", где можно просмотреть результаты запроса, нажав кнопку Тестировать запрос. Когда все будет готово, нажмите кнопку Готово, чтобы завершить работу мастера настройки источника данных.

Когда мы завершили работу мастера настройки источника данных на шаге 2, коллекция связанного элемента управления DetailsView была обновлена Fields , чтобы включить BoundField для каждого столбца, возвращаемого SelectCommandобъектом . ListView, однако, остается без изменений; Нам по-прежнему нужно определить его макет. Макет ListView можно создать вручную с помощью декларативной разметки или из параметра "Настроить ListView" в смарт-теге. Я обычно предпочитаю определять разметку вручную, но использовать любой метод является наиболее естественным для вас.

В итоге я использовал следующие LayoutTemplate, ItemTemplateи ItemSeparatorTemplate для элемента управления ListView:

<asp:ListView ID="CommentList" runat="server" DataSourceID="CommentsDataSource">
     <LayoutTemplate>
          <span ID="itemPlaceholder" runat="server" />
          <p>
               <asp:DataPager ID="DataPager1" runat="server">
                    <Fields>
                         <asp:NextPreviousPagerField ButtonType="Button" 
                              ShowFirstPageButton="True"
                              ShowLastPageButton="True" />
                    </Fields>
               </asp:DataPager>
          </p>
     </LayoutTemplate>
     <ItemTemplate>
          <h4><asp:Label ID="SubjectLabel" runat="server" 
               Text='<%# Eval("Subject") %>' /></h4>
          <asp:Label ID="BodyLabel" runat="server" 
               Text='<%# Eval("Body").ToString().Replace(Environment.NewLine, "<br />") %>' />
          <p>
               ---<br />
               <asp:Label ID="SignatureLabel" Font-Italic="true" runat="server"
                    Text='<%# Eval("Signature") %>' />
               <br />
               <br />
               My Home Town:
               <asp:Label ID="HomeTownLabel" runat="server" 
                    Text='<%# Eval("HomeTown") %>' />
               <br />
               My Homepage:
               <asp:HyperLink ID="HomepageUrlLink" runat="server" 
                    NavigateUrl='<%# Eval("HomepageUrl") %>' 
                    Text='<%# Eval("HomepageUrl") %>' />
          </p>
          <p align="center">
               Posted by
               <asp:Label ID="UserNameLabel" runat="server" 
                    Text='<%# Eval("UserName") %>' /> on
               <asp:Label ID="CommentDateLabel" runat="server" 
                    Text='<%# Eval("CommentDate") %>' />
          </p>
     </ItemTemplate>
     <ItemSeparatorTemplate>
          <hr />
     </ItemSeparatorTemplate>
</asp:ListView>

LayoutTemplate определяет разметку, выдаваемую элементом управления , в то время как ItemTemplate отрисовывает каждый элемент, возвращаемый sqlDataSource. Результирующая ItemTemplateразметка помещается в LayoutTemplateitemPlaceholder элемент управления . Помимо itemPlaceholder, LayoutTemplate включает элемент управления DataPager, который ограничивает ListView отображением только 10 комментариев гостевой книги на страницу (по умолчанию) и отображает интерфейс подкачки.

My ItemTemplate отображает тему каждого комментария гостевой книги в элементе с текстом <h4> , расположенным под темой. Обратите внимание, что синтаксис, используемый для отображения текста, принимает данные, возвращаемые оператором Eval("Body") привязки данных, преобразует их в строку и заменяет разрывы строк элементом <br /> . Это преобразование необходимо для отображения разрывов строк, введенных при отправке комментария, так как пробелы игнорируются HTML. Подпись пользователя отображается под текстом курсивом, за которым следует родной город пользователя, ссылка на его домашнюю страницу, дата и время создания комментария, а также имя пользователя, оставившего комментарий.

Просмотрите страницу в браузере. Здесь должны отобразиться комментарии, добавленные в гостевую книгу на шаге 5.

Guestbook.aspx Теперь отображает комментарии гостевой книги

Рис. 19. Guestbook.aspx Теперь отображаются комментарии гостевой книги (щелкните для просмотра полноразмерного изображения)

Попробуйте добавить новый комментарий в гостевую книгу. После нажатия кнопки PostCommentButton страница публикуется обратно, и комментарий добавляется в базу данных, но элемент управления ListView не обновляется для отображения нового комментария. Это можно исправить с помощью следующих способов:

  • PostCommentButton Обновление обработчика событий кнопки Click таким образом, чтобы он вызвал метод элемента управления DataBind() ListView после вставки нового комментария в базу данных;
  • Присвойтите EnableViewState свойству элемента управления ListView значение false. Этот подход работает потому, что, отключив состояние представления элемента управления, он должен повторно привязывать к базовым данным при каждой обратной отправке.

На веб-сайте руководства, который можно скачать из этого руководства, иллюстрируются оба метода. Свойство элемента управления EnableViewState ListView и false код, необходимый для программной повторной привязки данных к ListView, присутствует в обработчике Click событий, но закомментирован.

Примечание

В настоящее AdditionalUserInfo.aspx время страница позволяет пользователю просматривать и изменять параметры своего родного города, домашней страницы и подписи. Было бы неплохо обновить AdditionalUserInfo.aspx , чтобы отобразить комментарии вошедшего пользователя в гостевую книгу. То есть, помимо изучения и изменения информации, пользователь может посетить страницу AdditionalUserInfo.aspx , чтобы увидеть, какие комментарии гостевой книги он сделал в прошлом. Я оставляю это как упражнение для заинтересованного читателя.

Шаг 6. Настройка элемента управления CreateUserWizard для включения интерфейса для домашнего города, домашней страницы и подписи

Запрос SELECT , используемый страницей Guestbook.aspxINNER JOIN , использует для объединения связанных записей между GuestbookCommentsтаблицами , UserProfilesи aspnet_Users . Если пользователь, у которого нет записи в UserProfiles , делает комментарий гостевой книги, комментарий не будет отображаться в ListView, так как INNER JOIN возвращает GuestbookComments записи только при наличии совпадающих записей в UserProfiles и aspnet_Users. И, как мы видели на шаге 3, если у пользователя нет записи, UserProfiles он не сможет просматривать или изменять свои параметры на AdditionalUserInfo.aspx странице.

Излишне говорить, что из-за наших проектных решений важно, чтобы каждая учетная запись пользователя в системе членства была соответствующая запись в UserProfiles таблице. Нам нужно, чтобы соответствующая запись добавлялась UserProfiles в каждый раз, когда создается новая учетная запись участника с помощью CreateUserWizard.

Как описано в руководстве По созданию учетных записей пользователей, после создания новой учетной записи участника элемент управления CreateUserWizard вызывает событиеCreatedUser . Мы можем создать обработчик событий для этого события, получить Идентификатор пользователя для только что созданного пользователя, а затем вставить запись в таблицу UserProfiles со значениями по умолчанию для HomeTownстолбцов , HomepageUrlи Signature . Более того, можно заставить у пользователя эти значения, настроив интерфейс элемента управления CreateUserWizard для включения дополнительных элементов TextBoxes.

Давайте сначала рассмотрим, как добавить новую строку в таблицу UserProfiles в обработчике CreatedUser событий со значениями по умолчанию. После этого мы посмотрим, как настроить пользовательский интерфейс элемента управления CreateUserWizard, чтобы включить дополнительные поля формы для сбора сведений о родном городе, домашней странице и подписи нового пользователя.

Добавление строки по умолчанию вUserProfiles

В учебнике Создание учетных записей пользователей мы добавили элемент управления CreateUserWizard на страницу CreatingUserAccounts.aspx в папке Membership . Чтобы элемент управления CreateUserWizard добавлял запись в таблицу UserProfiles при создании учетной записи пользователя, необходимо обновить функциональные возможности элемента управления CreateUserWizard. Вместо того, чтобы вносить эти изменения на страницу CreatingUserAccounts.aspx , давайте добавим новый элемент управления CreateUserWizard на страницу EnhancedCreateUserWizard.aspx и внесите изменения для этого руководства.

Откройте страницу EnhancedCreateUserWizard.aspx в Visual Studio и перетащите элемент управления CreateUserWizard с панели элементов на страницу. Задайте для свойства элемента управления ID CreateUserWizard значение NewUserWizard. Как мы говорили в руководстве По созданию учетных записей пользователей , пользовательский интерфейс CreateUserWizard по умолчанию запрашивает у посетителя необходимые сведения. После того как эта информация будет предоставлена, элемент управления внутренне создает новую учетную запись пользователя на платформе членства, при этом нам не нужно писать ни одной строки кода.

Элемент управления CreateUserWizard вызывает ряд событий во время рабочего процесса. После того как посетитель отправит сведения о запросе и отправит форму, элемент управления CreateUserWizard изначально запускает своеCreatingUser событие. Если во время создания возникла проблема, CreateUserError событие запускается; однако в случае успешного создания CreatedUser пользователя возникает событие . В учебнике Создание учетных записей пользователей мы создали обработчик событий для CreatingUser события, чтобы убедиться, что указанное имя пользователя не содержит начальных или конечных пробелов, а имя пользователя не отображается в пароле.

Чтобы добавить строку в таблицу UserProfiles для только что созданного пользователя, необходимо создать обработчик CreatedUser события. К моменту CreatedUser возникновения события учетная запись пользователя уже была создана на платформе членства, что позволяет нам получить значение UserId учетной записи.

Создайте обработчик событий для NewUserWizardCreatedUser события и добавьте следующий код:

protected void NewUserWizard_CreatedUser(object sender, EventArgs e)
{
     // Get the UserId of the just-added user
     MembershipUser newUser = Membership.GetUser(NewUserWizard.UserName);
     Guid newUserId = (Guid)newUser.ProviderUserKey;
 
     // Insert a new record into UserProfiles
     string connectionString = 
          ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
     string insertSql = "INSERT INTO UserProfiles(UserId, HomeTown, HomepageUrl,
          Signature) VALUES(@UserId, @HomeTown, @HomepageUrl, @Signature)";
 
     using (SqlConnection myConnection = new SqlConnection(connectionString))
     {
          myConnection.Open();
          SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
          myCommand.Parameters.AddWithValue("@UserId", newUserId);
          myCommand.Parameters.AddWithValue("@HomeTown", DBNull.Value);
          myCommand.Parameters.AddWithValue("@HomepageUrl", DBNull.Value);
          myCommand.Parameters.AddWithValue("@Signature", DBNull.Value);
          myCommand.ExecuteNonQuery();
          myConnection.Close();
     }
}

Приведенный выше код создается путем получения Идентификатора пользователя только что добавленной учетной записи пользователя. Это достигается с помощью Membership.GetUser(username) метода для возврата сведений о конкретном пользователе, а затем с помощью ProviderUserKey свойства для получения идентификатора пользователя. Имя пользователя, введенное пользователем в элементе управления CreateUserWizard, доступно через его UserName свойство .

Затем строка подключения извлекается из Web.config и INSERT указывается оператор . Создаются необходимые ADO.NET объекты и выполняется команда . Код назначает DBNull экземпляр параметрам , @HomepageUrlи @Signature , что приводит к @HomeTownвставке значений базы данных NULL для HomeTownполей , HomepageUrlи Signature .

Перейдите на страницу EnhancedCreateUserWizard.aspx в браузере и создайте новую учетную запись пользователя. После этого вернитесь в Visual Studio и изучите содержимое aspnet_Users таблиц и UserProfiles (как это было на рис. 12). Вы увидите новую учетную запись пользователя в aspnet_Users и соответствующую UserProfiles строку (со значениями NULLHomeTown, HomepageUrlи Signature).

Добавлены новая учетная запись пользователя и userProfiles

Рис. 20. Добавлена новая учетная запись пользователя и UserProfiles запись (щелкните для просмотра полноразмерного изображения)

После того как посетитель предоставил сведения о своей новой учетной записи и нажал кнопку "Создать пользователя", создается учетная запись пользователя и в таблицу UserProfiles добавляется строка. Затем в createUserWizard отображается , CompleteWizardStepв котором отображается сообщение об успешном выполнении и кнопка Продолжить. Нажатие кнопки Продолжить приводит к обратной отправке, но никаких действий не выполняется, в результате чего пользователь зависает на EnhancedCreateUserWizard.aspx странице.

Можно указать URL-адрес для отправки пользователю при нажатии кнопки Продолжить с помощью свойства элемента управления ContinueDestinationPageUrlCreateUserWizard. Задайте для ContinueDestinationPageUrl свойства значение "~/Membership/AdditionalUserInfo.aspx". При этом новый пользователь перейдет в AdditionalUserInfo.aspx, где он может просматривать и обновлять свои параметры.

Настройка интерфейса CreateUserWizard для запроса домашнего города, домашней страницы и подписи нового пользователя

Интерфейса по умолчанию элемента управления CreateUserWizard достаточно для простых сценариев создания учетных записей, в которых необходимо собирать только основные сведения об учетной записи пользователя, такие как имя пользователя, пароль и электронная почта. Но что делать, если мы хотим предложить посетителю войти в ее родной город, домашнюю страницу, и подпись при создании ее учетной записи? Интерфейс элемента управления CreateUserWizard можно настроить для сбора дополнительных сведений при регистрации. Эти сведения можно использовать в CreatedUser обработчике событий для вставки дополнительных записей в базовую базу данных.

Элемент управления CreateUserWizard расширяет элемент управления мастер ASP.NET, который является элементом управления, который позволяет разработчику страниц определить ряд упорядоченных WizardSteps. Элемент управления "Мастер" отображает активный шаг и предоставляет интерфейс навигации, позволяющий посетителю пройти эти шаги. Элемент управления "Мастер" идеально подходит для разбиения длинной задачи на несколько коротких шагов. Дополнительные сведения об элементе управления "Мастер" см. в разделе Создание пошагового пользовательского интерфейса с помощью элемента управления мастера ASP.NET 2.0.

Разметка элемента управления CreateUserWizard по умолчанию определяет два WizardSteps: CreateUserWizardStep и CompleteWizardStep.

<asp:CreateUserWizard ID="NewUserWizard" runat="server"
     ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
     <WizardSteps>
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
          </asp:CreateUserWizardStep>
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
          </asp:CompleteWizardStep>
     </WizardSteps>
</asp:CreateUserWizard>

Первый WizardStep, CreateUserWizardStepотображает интерфейс, который запрашивает имя пользователя, пароль, адрес электронной почты и т. д. Когда посетитель предоставляет эти сведения и нажимает кнопку "Создать пользователя", ей отображается CompleteWizardStepсообщение об успешном выполнении и кнопка Продолжить.

Чтобы настроить интерфейс элемента управления CreateUserWizard для включения дополнительных полей формы, можно:

  • Создание одного или нескольких новыхWizardStep, чтобы содержать дополнительные элементы пользовательского интерфейса. Чтобы добавить новый WizardStep объект в CreateUserWizard, щелкните ссылку "Добавить/удалить WizardSteps" в смарт-теге, чтобы запустить редактор коллекций WizardStep . Оттуда можно добавить, удалить или изменить порядок действий в мастере. Это подход, который мы будем использовать в этом руководстве.

  • CreateUserWizardStep Преобразованиев редактируемый объектWizardStep. Это заменяет на CreateUserWizardStep эквивалентWizardStep, разметка которого определяет пользовательский интерфейс, соответствующий CreateUserWizardStep. Преобразовав в CreateUserWizardStep , WizardStep можно изменить положение элементов управления или добавить дополнительные элементы пользовательского интерфейса на этом шаге. Чтобы преобразовать CreateUserWizardStep или CompleteWizardStep в редактируемый WizardStep, щелкните ссылку "Настроить шаг создания пользователя" или "Настроить полный шаг" в смарт-теге элемента управления.

  • Используйте некоторое сочетание указанных выше двух вариантов.

Важно помнить, что элемент управления CreateUserWizard выполняет процесс создания учетной записи пользователя при нажатии кнопки "Создать пользователя" в его CreateUserWizardStep. Не имеет значения, есть ли дополнительные WizardStep после CreateUserWizardStep или нет.

При добавлении пользовательского в WizardStep элемент управления CreateUserWizard для сбора дополнительных пользовательских данных WizardStep пользователь может быть размещен до или после CreateUserWizardStep. Если он поставляется до CreateUserWizardStep , то для обработчика событий доступны дополнительные входные данные, собранные пользователем из пользовательского WizardStepCreatedUser объекта . Однако если пользователь WizardStep возникает после CreateUserWizardStep , то к тому времени, когда WizardStep пользователь отображается, новая учетная запись пользователя уже создана и CreatedUser событие уже сработало.

На рисунке 21 показан рабочий процесс, когда добавленный WizardStep предшествует CreateUserWizardStep. Так как к моменту CreatedUser возникновения события были собраны дополнительные сведения о пользователе, достаточно обновить CreatedUser обработчик событий, чтобы получить эти входные данные и использовать их для INSERT значений параметров инструкции (а не DBNull.Value).

Рабочий процесс CreateUserWizard, когда дополнительный шаг мастера предшествует шагу CreateUserWizardStep

Рис. 21. Рабочий процесс CreateUserWizard, когда перед элементом Additional WizardStep предшествует CreateUserWizardStep (щелкните для просмотра полноразмерного изображения)

Если пользователь WizardStep размещается послеCreateUserWizardStep, процесс создания учетной записи пользователя происходит до того, как пользователь может войти в свой родной город, домашнюю страницу или подпись. В этом случае эти дополнительные сведения необходимо вставить в базу данных после создания учетной записи пользователя, как показано на рисунке 22.

Рабочий процесс CreateUserWizard при появлении дополнительного шага wizardStep после шага CreateUserWizardStep

Рис. 22. Рабочий процесс CreateUserWizard При дополнительном WizardStep наступает после CreateUserWizardStep (щелкните для просмотра полноразмерного изображения)

Рабочий процесс, показанный на рис. 22, ожидает вставки записи в таблицу UserProfiles до завершения шага 2. Однако если посетитель закроет браузер после шага 1, мы достигли состояния, в котором была создана учетная запись пользователя, но запись не была добавлена в UserProfiles. Одним из обходных решений является вставка UserProfiles записи со значениями NULL или по умолчанию в CreatedUser обработчик событий (которая возникает после шага 1), а затем обновление этой записи после завершения шага 2. Это гарантирует, что UserProfiles запись будет добавлена для учетной записи пользователя, даже если пользователь завершит процесс регистрации в середине.

В этом руководстве давайте создадим новый WizardStep объект, который возникает после , CreateUserWizardStep но перед CompleteWizardStep. Давайте сначала настроим МастерШаг, а затем рассмотрим код.

В смарт-теге элемента управления CreateUserWizard выберите "Добавить/удалить WizardStep ", чтобы открыть диалоговое окно Редактор коллекций WizardStep . Добавьте новый WizardStepобъект , задав для нее ID значение UserSettings, а для Title параметра — значение "Ваши параметры" и значение StepTypeStep. Затем разместите его так, чтобы он располагал после CreateUserWizardStep ("Регистрация для новой учетной записи") и перед CompleteWizardStep ("Завершить"), как показано на рис. 23.

Добавление нового мастераШаг в элемент управления CreateUserWizard

Рис. 23. Добавление нового WizardStep элемента управления CreateUserWizard (щелкните для просмотра полноразмерного изображения)

Нажмите кнопку ОК, чтобы закрыть диалоговое WizardStep окно Редактор коллекции. О новом WizardStep свидетельствует обновленная декларативная разметка элемента управления CreateUserWizard:

<asp:CreateUserWizard ID="NewUserWizard" runat="server"
     ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
     <WizardSteps>
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
          </asp:CreateUserWizardStep>
          <asp:WizardStep runat="server" ID="UserSettings" StepType="Step"
               Title="Your Settings">
          </asp:WizardStep>
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
          </asp:CompleteWizardStep>
     </WizardSteps>
</asp:CreateUserWizard>

Обратите внимание на новый <asp:WizardStep> элемент . Нам нужно добавить пользовательский интерфейс для сбора родного города, домашней страницы и подписи нового пользователя здесь. Это содержимое можно ввести в декларативном синтаксисе или с помощью Designer. Чтобы использовать Designer, выберите шаг "Параметры" в раскрывающемся списке смарт-тега, чтобы просмотреть этот шаг в Designer.

Примечание

При выборе шага в раскрывающемся списке Смарт-тега обновляется свойство элемента управления ActiveStepIndexCreateUserWizard, указывающее индекс начального шага. Поэтому если вы используете этот раскрывающийся список для изменения шага "Ваши параметры" в Designer, обязательно установите для него значение "Регистрация для новой учетной записи", чтобы этот шаг отображалось при первом посещении EnhancedCreateUserWizard.aspx страницы пользователями.

Создайте пользовательский интерфейс на шаге "Параметры", который содержит три элемента управления TextBox с именами HomeTown, HomepageUrlи Signature. После создания этого интерфейса декларативная разметка CreateUserWizard должна выглядеть примерно так:

<asp:CreateUserWizard ID="NewUserWizard" runat="server"
     ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
     <WizardSteps>
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
          </asp:CreateUserWizardStep>
          <asp:WizardStep runat="server" ID="UserSettings" StepType="Step"
               Title="Your Settings">
               <p>
                    <b>Home Town:</b><br />
                    <asp:TextBox ID="HomeTown" runat="server"></asp:TextBox>
               </p>
               <p>
                    <b>Homepage URL:</b><br />
                    <asp:TextBox ID="HomepageUrl" Columns="40" runat="server"></asp:TextBox>
               </p>
               <p>
                    <b>Signature:</b><br />
                    <asp:TextBox ID="Signature" TextMode="MultiLine" Width="95%"
                         Rows="5" runat="server"></asp:TextBox>
               </p>
          </asp:WizardStep>
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
          </asp:CompleteWizardStep>
     </WizardSteps>
</asp:CreateUserWizard>

Перейдите на эту страницу в браузере и создайте учетную запись пользователя, указав значения для родного города, домашней страницы и подписи. После завершения CreateUserWizardStep действия учетная запись пользователя создается на платформе членства и CreatedUser запускается обработчик событий, который добавляет новую строку в UserProfiles, но со значением HomeTownбазы данных NULL , HomepageUrlи Signature. Значения, введенные для родного города, домашней страницы и подписи, никогда не используются. Конечным результатом является новая учетная запись пользователя с записью UserProfiles , поля которой HomeTown, HomepageUrlи Signature еще не указаны.

Нам нужно выполнить код после шага "Параметры", который принимает значения родного города, honepage и сигнатуры, введенные пользователем, и обновляет соответствующую UserProfiles запись. Каждый раз, когда пользователь перемещается между шагами в элементе управления "Мастер"ActiveStepChanged, возникает событие мастера. Мы можем создать обработчик событий для этого события и обновить таблицу UserProfiles после завершения шага "Параметры".

Добавьте обработчик событий для события CreateUserWizard ActiveStepChanged и добавьте следующий код:

protected void NewUserWizard_ActiveStepChanged(object sender, EventArgs e)
{
     // Have we JUST reached the Complete step?
     if (NewUserWizard.ActiveStep.Title == "Complete")
     {
          WizardStep UserSettings = NewUserWizard.FindControl("UserSettings") as
          WizardStep;
 
          // Programmatically reference the TextBox controls
          TextBox HomeTown = UserSettings.FindControl("HomeTown") as TextBox;
          TextBox HomepageUrl = UserSettings.FindControl("HomepageUrl") as TextBox;
          TextBox Signature = UserSettings.FindControl("Signature") as TextBox;
 
          // Update the UserProfiles record for this user
          // Get the UserId of the just-added user
          MembershipUser newUser = Membership.GetUser(NewUserWizard.UserName);
          Guid newUserId = (Guid)newUser.ProviderUserKey;
 
          // Insert a new record into UserProfiles
          string connectionString = 
               ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
          string updateSql = "UPDATE UserProfiles SET HomeTown = @HomeTown, HomepageUrl
               = @HomepageUrl, Signature = @Signature WHERE UserId = @UserId";
 
          using (SqlConnection myConnection = new SqlConnection(connectionString))
          {
               myConnection.Open();
               SqlCommand myCommand = new SqlCommand(updateSql, myConnection);
               myCommand.Parameters.AddWithValue("@HomeTown", HomeTown.Text.Trim());
               myCommand.Parameters.AddWithValue("@HomepageUrl", HomepageUrl.Text.Trim());
               myCommand.Parameters.AddWithValue("@Signature", Signature.Text.Trim());
               myCommand.Parameters.AddWithValue("@UserId", newUserId);
               myCommand.ExecuteNonQuery();
               myConnection.Close();
          }
     }
}

Приведенный выше код начинается с определения того, достигли ли мы только что шага "Завершить". Так как шаг "Завершить" происходит сразу после шага "Ваши параметры", то, когда посетитель достигает шага "Завершить", это означает, что он только что завершил шаг "Ваши параметры".

В этом случае необходимо программно ссылаться на элементы управления TextBox в UserSettings WizardStep. Для этого сначала используется FindControl метод для программной ссылки на UserSettings WizardStep, а затем снова для ссылки на TextBoxes из WizardStep. После того как на TextBoxes будет указана ссылка, мы готовы выполнить инструкцию UPDATE . Оператор UPDATE имеет то же количество параметров, что INSERT и оператор в CreatedUser обработчике событий, но здесь мы используем значения родной город, домашняя страница и подпись, предоставленные пользователем.

С помощью этого обработчика событий перейдите на страницу EnhancedCreateUserWizard.aspx в браузере и создайте учетную запись пользователя, указав значения для родного города, домашней страницы и подписи. После создания новой учетной записи вы будете перенаправлены на AdditionalUserInfo.aspx страницу, где отображаются только что введенные сведения о родном городе, домашней странице и подписи.

Примечание

Сейчас на нашем веб-сайте есть две страницы, на которых посетитель может создать новую учетную запись: CreatingUserAccounts.aspx и EnhancedCreateUserWizard.aspx. Карта сайта и страница входа на веб-сайте указывают на CreatingUserAccounts.aspx страницу, но CreatingUserAccounts.aspx страница не запрашивает у пользователя сведения о родном городе, домашней странице и подписи и не добавляет соответствующую строку в UserProfiles. Поэтому либо обновите страницу CreatingUserAccounts.aspx , чтобы она предлагала эту функцию, либо обновите карту сайта и страницу входа на ссылку EnhancedCreateUserWizard.aspx вместо CreatingUserAccounts.aspx. Если вы выбрали последний вариант, обязательно обновите Membership файл папки Web.config , чтобы разрешить анонимным пользователям доступ к EnhancedCreateUserWizard.aspx странице.

Сводка

В этом руководстве мы рассмотрели методы моделирования данных, связанных с учетными записями пользователей на платформе членства. В частности, мы рассмотрели моделирование сущностей, которые совместно используют связь "один ко многим" с учетными записями пользователей, а также данные, которые имеют отношение "один к одному". Кроме того, мы узнали, как эти связанные сведения могут отображаться, вставляться и обновляться, в некоторых примерах используется элемент управления SqlDataSource, а другие — с помощью ADO.NET кода.

В этом руководстве мы завершаем работу с учетными записями пользователей. Начиная со следующего руководства мы рассмотрим роли. В следующих руководствах мы рассмотрим платформу ролей, узнаем, как создавать новые роли, как назначать роли пользователям, как определить, к каким ролям принадлежит пользователь, и как применить авторизацию на основе ролей.

Счастливое программирование!

Дополнительные материалы

Дополнительные сведения по темам, рассматриваемым в этом руководстве, см. в следующих ресурсах:

Об авторе

Скотт Митчелл (Scott Mitchell), автор нескольких книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часа. Скотт можно связаться по адресу mitchell@4guysfromrolla.com или через его блог по адресу http://ScottOnWriting.NET.

Отдельная благодарность...

Эта серия учебников была проверена многими полезными рецензентами. Хотите ознакомиться с моими предстоящими статьями MSDN? Если да, опустите мне строку в mitchell@4GuysFromRolla.com.