Хранение дополнительных сведений о пользователе (VB)

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

Замечание

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

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

Скачать код или Скачать PDF

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

Введение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Замечание

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

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

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

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

Использование диалогового окна

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

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

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

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

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

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

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

Рис. 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, который хранит данные профиля в базе данных SQL Server. На самом деле, наша база данных уже содержит таблицу, используемую SqlProfileProvider (aspnet_Profile), так как она была добавлена, когда мы добавили службы приложений в учебнике «Создание схемы членства в SQL Server».
    Основное преимущество платформы профилей заключается в том, что разработчики могут определять свойства профиля в Web.config, и при этом не требуется писать код для сериализации данных профиля в базовое хранилище данных и обратно. Короче говоря, невероятно легко определить набор свойств профиля и работать с ними в коде. Однако система профилей оставляет желать многое, когда дело доходит до управления версиями, поэтому если у вас есть приложение, в котором вы ожидаете, что новые свойства, относящиеся к пользователю, будут добавлены позже, или существующие, которые будут удалены или изменены, то платформа профилей может оказаться не лучшим вариантом. Кроме того, SqlProfileProvider свойства профиля хранятся в сильно денормализованной форме, что делает практически невозможным выполнение запросов непосредственно к данным профиля (например, сколько пользователей имеют домашний город Нью-Йорк).
    Дополнительные сведения о платформе профилей см. в разделе "Дополнительные чтения" в конце этого руководства.

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

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

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

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

Сохраните таблицу и присвойте ей UserProfilesимя. Наконец, установите ограничение внешнего ключа между UserProfiles полем таблицы UserId и полем 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 .

AdditionalUserInfo.aspx Откройте страницу в папке Membership и добавьте на страницу элемент управления DetailsView, установив для него ID свойство в UserProfile и очистив его свойства Width и Height. Разверните смарт-тег DetailsView и привязите его к новому элементу управления источниками данных. Откроется мастер настройки источника данных (см. рис. 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 возвращает все записи, но нам нужна только запись пользователя, который в данный момент вошел в систему. Чтобы добавить предложение, нажмите WHERE кнопку, чтобы открыть диалоговое окно "Добавить WHEREWHERE предложение" (см. рис. 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 Sub UserProfileDataSource_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceSelectingEventArgs) Handles UserProfileDataSource.Selecting
     ' Get a reference to the currently logged on user
     Dim currentUser As MembershipUser = Membership.GetUser()

     ' Determine the currently logged on user's UserId value
     Dim currentUserId As Guid = CType(currentUser.ProviderUserKey, Guid)

     ' Assign the currently logged on user's UserId to the @UserId parameter
     e.Command.Parameters("@UserId").Value = currentUserId
End Sub

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

Замечание

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

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

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

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

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

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

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

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

Вернитесь к AdditionalUserInfo.aspx page, вошедшего в систему как Брюс. Параметры Брюса отображаются, как показано на рисунке 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 . Оставьте источник во всех параметрах на "None" и нажмите кнопку "ОК", чтобы закрыть диалоговое окно.

Укажите UpdateCommand и UpdateParameters для SqlDataSource

Рис. 14. Укажите SqlDataSource и UpdateCommandUpdateParameters (Нажмите, чтобы просмотреть изображение в полном размере)

Из-за добавлений, внесенных в элемент управления SqlDataSource, элемент управления DetailsView теперь может поддерживать редактирование. В смарт-теге DetailsView установите флажок "Включить редактирование". При этом элемент CommandField добавляется в коллекцию элемента управления Fields со свойством ShowEditButton, установленным в True. Эта кнопка "Редактировать" отображается, когда DetailsView находится в режиме только для чтения, а кнопки "Обновить" и "Отмена" отображаются, когда DetailsView находится в режиме редактирования. Вместо того чтобы требовать от пользователя нажатия кнопки "Изменить", мы можем настроить DetailsView в режиме постоянного редактирования, установив свойство элемента управления DefaultMode в значение 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 и добавьте элемент управления Label над 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 Sub UserProfile_ItemUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs) Handles UserProfile.ItemUpdated
     SettingsUpdatedMessage.Visible = True
End Sub

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

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

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

Замечание

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

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

Помните, что главная страница содержит элемент управления "LoginView" в ContentPlaceHolder LoginContent, который отображает различные разметки для аутентифицированных и анонимных посетителей. Обновите элемент управления LoginView LoggedInTemplate, чтобы добавить ссылку на страницу 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 свойство ID в значение Subject, а его свойство Columns — в 40; установите у второго элемент управления TextBox свойство ID в значение Body, его свойство TextMode — в MultiLine, а свойства Width и Rows — в "95%" и 8 соответственно. Чтобы завершить пользовательский интерфейс, добавьте веб-элемент управления Button с именем PostCommentButton и задайте для его Text свойства значение "Post Your Comment".

Так как для каждого комментария гостевой книги требуется заголовок и текст, добавьте валидатор обязательного поля для каждого из текстовых полей. 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 код в обработчике событий кнопки Click ; можно добавить элемент управления SqlDataSource на страницу, настроить его InsertCommand, а затем вызвать его Insert метод из Click обработчика событий; или создать средний уровень, отвечающий за вставку новых комментариев гостевой книги, и вызвать эту функцию из Click обработчика событий. Так как мы рассмотрели использование SqlDataSource на шаге 3, давайте будем использовать ADO.NET код здесь.

Замечание

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

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

Protected Sub PostCommentButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles PostCommentButton.Click
     If Not Page.IsValid Then Exit Sub

     ' Determine the currently logged on user's UserId
     Dim currentUser As MembershipUser = Membership.GetUser()
     Dim currentUserId As Guid = CType(currentUser.ProviderUserKey, Guid)

     ' Insert a new record into GuestbookComments
     Dim connectionString As String = 
          ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString
     Dim insertSql As String = "INSERT INTO GuestbookComments(Subject, Body, UserId)
          VALUES(@Subject, @Body, @UserId)"

     Using myConnection As New SqlConnection(connectionString)

          myConnection.Open()
          Dim myCommand As 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()
     End Using

     ' "Reset" the Subject and Body TextBoxes

     Subject.Text = String.Empty
     Body.Text = String.Empty
End Sub

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

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

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

После нажатия кнопки 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 см. в записи блога Скотта Guthrie, asp:ListView Control и моей статьи , отображение данных с помощью элемента управления ListView.

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

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

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

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

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

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

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

После завершения мастера настройки источника данных на шаге 2 коллекция элемента управления Fields DetailsView была обновлена, чтобы включить BoundField для каждого столбца, возвращаемого элементом SelectCommand. Однако ListView остается неизменным; Нам по-прежнему нужно определить его макет. Макет ListView можно создать вручную с помощью декларативной разметки или из параметра Configure 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 всего десятью комментариями гостевой книги на страницу (по умолчанию) и отрисовывает интерфейс разбиения на страницы.

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

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

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

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

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

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

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

Замечание

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

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

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

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

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

Сначала рассмотрим, как добавить новую строку 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 Sub NewUserWizard_CreatedUser(ByVal sender As Object, ByVal e As System.EventArgs) Handles NewUserWizard.CreatedUser
     ' Get the UserId of the just-added user
     Dim newUser As MembershipUser = Membership.GetUser(NewUserWizard.UserName)
     Dim newUserId As Guid = CType(newUser.ProviderUserKey, Guid)

     ' Insert a new record into UserProfiles
     Dim connectionString As String = 

          ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString
     Dim insertSql As String = "INSERT INTO UserProfiles(UserId, HomeTown, HomepageUrl,
          Signature) VALUES(@UserId, @HomeTown, @HomepageUrl, @Signature)"

     Using myConnection As New SqlConnection(connectionString)
          myConnection.Open()
          Dim myCommand As 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()
     End Using
End Sub

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

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

EnhancedCreateUserWizard.aspx Посетите страницу через браузер и создайте новую учетную запись пользователя. После этого вернитесь в Visual Studio и изучите содержимое aspnet_Users таблиц и UserProfiles таблиц (как и на рис. 12). Вы должны увидеть новую учетную запись пользователя aspnet_Users и соответствующую строку UserProfiles (со значениями NULL для HomeTown, 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, щелкните на ссылке "Добавить/удалить WizardStep" в смарт-теге, чтобы запустить редактор коллекции WizardStep. Оттуда можно добавить, удалить или изменить последовательность шагов в мастере. Это подход, который мы будем использовать для этого руководства.

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

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

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

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

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

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

Рис. 21. Рабочий процесс CreateUserWizard при наличии дополнительных WizardStep перед CreateUserWizardStep (щелкните, чтобы увеличить изображение)

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

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

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

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

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

В смарт-теге элемента управления CreateUserWizard выберите "Добавить/Удалить WizardStep" , что откроет диалоговое окно редактора коллекций WizardStep. Добавьте новый WizardStep, задав для него значение ID `UserSettings`, значение Title "Параметры" и значение StepType `Step`. Затем поместите его так, чтобы оно появилось после 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> элемент. Нам нужно добавить пользовательский интерфейс для сбора информации о домашнем городе, домашней странице и подписи нового пользователя здесь. Это содержимое можно ввести в декларативном синтаксисе или конструкторе. Чтобы использовать конструктор, выберите шаг "Параметры" в раскрывающемся списке в смарт-теге, чтобы просмотреть шаг конструктора.

Замечание

При выборе шага в раскрывающемся списке Смарт-тега обновляется свойство элемента управления ActiveStepIndexCreateUserWizard, указывающее индекс начального шага. Таким образом, если вы используете этот раскрывающийся список для изменения шага "Параметры" в конструкторе, обязательно задайте для него значение "Регистрация для новой учетной записи", чтобы этот шаг отображается при первом посещении 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 учетная запись пользователя создается в framework членства, и запускается обработчик событий CreatedUser, который добавляет новую строку в UserProfiles, но со значением базы данных NULL для HomeTown, HomepageUrl, и Signature. Значения, введенные для домашнего города, домашней страницы и подписи, никогда не используются. Чистый результат — это новая учетная запись пользователя с записьюUserProfiles, для которой поля HomeTown, HomepageUrl и Signature еще не указаны.

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

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

Protected Sub NewUserWizard_ActiveStepChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles NewUserWizard.ActiveStepChanged
     ' Have we JUST reached the Complete step?
     If NewUserWizard.ActiveStep.Title = "Complete" Then
          Dim UserSettings As WizardStep = CType(NewUserWizard.FindControl("UserSettings"),WizardStep)

          ' Programmatically reference the TextBox controls
          Dim HomeTown As TextBox = CType(UserSettings.FindControl("HomeTown"), TextBox)
          Dim HomepageUrl As TextBox = CType(UserSettings.FindControl("HomepageUrl"), TextBox)
          Dim Signature As TextBox = CType(UserSettings.FindControl("Signature"), TextBox)

          ' Update the UserProfiles record for this user
          ' Get the UserId of the just-added user
          Dim newUser As MembershipUser = Membership.GetUser(NewUserWizard.UserName)
          Dim newUserId As Guid = CType(newUser.ProviderUserKey, Guid)

          ' Insert a new record into UserProfiles
          Dim connectionString As String = ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString

          Dim updateSql As String = "UPDATE UserProfiles SET HomeTown = @HomeTown, HomepageUrl
               = @HomepageUrl, Signature = @Signature WHERE UserId = @UserId"

          Using myConnection As New SqlConnection(connectionString)
               myConnection.Open()
               Dim myCommand As 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()
          End Using
     End If
End Sub

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

В таком случае необходимо программно ссылаться на элементы управления TextBox в пределах UserSettings WizardStep. Для этого сначала используется метод FindControl для программной ссылки на UserSettings WizardStep, а затем снова для ссылки на текстовые поля изнутри 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.

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

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

Дальнейшее чтение

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

Сведения о авторе

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

Особое спасибо...

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