• Статья
  • Чтение занимает 40 мин

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

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

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

Введение

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

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

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

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

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

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

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

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

добавить новую таблицу в базу данных Секурититуториалс

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

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

добавить первичный столбец с именем Комментид

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

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

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

Note

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

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

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

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

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

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

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

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

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

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

Ограничения внешнего ключа можно настроить на автоматическое удаление связанных дочерних записей при удалении родительской записи. Иными словами, можно настроить ограничение внешнего ключа таким образом, чтобы записи гостевой книги пользователя автоматически удалялись при удалении учетной записи пользователя. Для этого разверните раздел «Вставка и обновление спецификации» и задайте для свойства «удалить правило» значение 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 .
    Основным преимуществом платформы Profile Framework является то, что он позволяет разработчикам определять свойства профиля в Web.config — не требуется написание кода для сериализации данных профиля в базовое хранилище данных и из него. Вкратце, чрезвычайно просто определить набор свойств профиля и работать с ними в коде. Тем не менее система профиля остается очень необходимой, когда дело доходит до управления версиями, поэтому, если у вас есть приложение, в котором вы предполагаете добавить новые свойства для конкретного пользователя позднее, или удалить или изменить существующие, то платформа профиля может не быть наилучший вариант. Более того, SqlProfileProvider сохраняет свойства профиля в сильно денормализованном виде, делая их более невозможными для выполнения запросов непосредственно по данным профиля (например, количество пользователей в дом Нью-Йорк).
    Дополнительные сведения о структуре профиля см. в разделе «дополнительные считывания» в конце этого руководства.

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

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

создания таблицы UserProfiles

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

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

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

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

выберите Секурититуториалсконнектионстринг из раскрывающегося списка.

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

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

вернуть все столбцы из таблицы UserProfiles

Рис. 9. возврат всех столбцов из таблицы UserProfiles (щелкните, чтобы просмотреть изображение с полным размером)

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

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

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

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

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

После завершения работы мастера настройки источника данных Visual Studio создает элемент управления SqlDataSource на основе параметров, заданных в мастере. Более того, он вручную добавляет BoundFields к элементу DetailsView для каждого столбца, возвращаемого SelectCommandом SqlDataSource. Нет необходимости показывать поле 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 текущего пользователя. Это можно сделать, создав обработчик событий для события Selecting SqlDataSource и добавив следующий код:

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;
}

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

Note

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

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

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

отображается содержимое таблиц aspnet_Users и UserProfile

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

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

запись была добавлена к профилям пользователя для Брюс

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

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

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

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

Note

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

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

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

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

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

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

указать UpdateCommand и UpdateParameters для SqlDataSource

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

Из-за дополнений к элементу управления SqlDataSource элемент управления DetailsView теперь может поддерживать редактирование. В смарт-теге DetailsView установите флажок «Разрешить изменение». При этом в коллекцию Fields элемента управления добавляется CommandField со свойством 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 и добавьте элемент управления Label над элементом DetailsView. Задайте для его ID значение SettingsUpdatedMessage, его свойству Text значение «ваши параметры обновлены», а для свойств Visible и EnableViewStatefalse.

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

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

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

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

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

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

Note

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

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

Вспомним, что Главная страница содержит веб-элемент управления LoginView в его LoginContent ContentPlaceHolder, который отображает различную разметку для прошедших проверку подлинности и анонимных посетителей. Обновите 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>

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

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

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

Поскольку каждому комментарию гостевой книги требуется тема и текст, добавьте RequiredFieldValidator для каждого из текстовых полей. Задайте для свойства ValidationGroup этих элементов управления значение «Ентеркоммент». Аналогичным образом задайте для свойства ValidationGroup элемента управления PostCommentButton значение «Ентеркоммент». Дополнительные сведения о ASP. Элементы управления проверки в сети, изучите проверку формы в ASP.NET, которая разбила элементы управления проверки в ASP.NET 2,0, а также учебник по элементам управления сервера проверки в W3Schools.

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

<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.

Note

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

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

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 локальной переменной. Это значение требуется, поскольку при вставке записи в GuestbookCommentsнеобходимо указать значение UserId.

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

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

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

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

вы видите комментарии к гостевой книге в таблице Гуестбуккомментс

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

Note

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

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

Note

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

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

построенный запрос объединяет таблицы Гуестбуккомментс, UserProfile и aspnet_Users

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

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

После завершения работы мастера настройки источника данных на шаге 2 связанная коллекция Fields элемента управления DetailsView была обновлена для включения 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помещается в элемент управления itemPlaceholder LayoutTemplate. В дополнение к itemPlaceholder``LayoutTemplate включает элемент управления DataPager, который ограничивает ListView отображением всего 10 комментариев гостевой книги на страницу (по умолчанию) и отображает интерфейс разбиения по страницам.

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

Уделите время просмотру страницы в браузере. Вы должны увидеть комментарии, добавленные в книгу гостевой книги на шаге 5, показанном здесь.

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

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

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

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

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

Note

В настоящее время страница 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. Мы можем создать обработчик событий для этого события, получить UserId для только что созданного пользователя, а затем вставить запись в таблицу UserProfiles со значениями по умолчанию для столбцов HomeTown, HomepageUrlи Signature. Более того, можно запросить у пользователя эти значения, настроив интерфейс элемента управления CreateUserWizard для включения дополнительных текстовых полей.

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

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

В учебнике Создание учетных записей пользователей мы добавили элемент управления CreateUserWizard на страницу CreatingUserAccounts.aspx в папке Membership. Чтобы элемент управления CreateUserWizard мог добавить запись a в таблицу 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 учетной записи.

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

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();
     }
}

Приведенный выше код существ, извлекая идентификатор UserId только что добавленной учетной записи пользователя. Это достигается с помощью метода 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).

добавлены учетная запись пользователя, и добавлена запись UserProfile

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

После того как посетитель предоставил сведения о новой учетной записи и нащелкнул кнопку «создать пользователя», создается учетная запись пользователя и строка, добавленная в таблицу UserProfiles. Затем CreateUserWizard отображает его CompleteWizardStep, в котором отображается сообщение об успешном выполнении и кнопка Continue (продолжить). Нажатие кнопки Продолжить приводит к выполнению обратной передачи, но никакие действия не выполняются, при этом пользователь зависает на странице EnhancedCreateUserWizard.aspx.

Можно указать URL-адрес для отправки пользователю при нажатии кнопки continue через свойствоContinueDestinationPageUrlэлемента управления CreateUserWizard. Задайте для свойства ContinueDestinationPageUrl значение «~/мембершип/аддитионалусеринфо.аспкс». После этого новый пользователь будет AdditionalUserInfo.aspx, где он может просматривать и обновлять свои параметры.

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

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

Элемент управления CreateUserWizard расширяет Управление мастером ASP.NET, то есть элемент управления, позволяющий разработчику страницы определить ряд упорядоченных WizardSteps. Элемент управления мастера визуализирует активный шаг и предоставляет интерфейс навигации, позволяющий посетителю перемещаться по этим шагам. Элемент управления «Мастер» идеально подходит для разбиения длинной задачи на несколько коротких шагов. Дополнительные сведения об элементе управления Wizard см. в разделе Создание пошагового пользовательского интерфейса с помощью элемента управления мастера 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 s, чтобы они содержали дополнительные элементы пользовательского интерфейса. Чтобы добавить новый WizardStep в CreateUserWizard, щелкните ссылку «Добавить/удалить WizardSteps» из смарт-тега, чтобы открыть редактор коллекции WizardStep. Здесь можно добавить, удалить или изменить порядок шагов в мастере. Это подход, который мы будем использовать в этом руководстве.

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

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

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

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

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

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

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

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

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

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

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

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

В смарт-теге элемента управления CreateUserWizard выберите «Добавить/удалить WizardStep s», который открывает диалоговое окно Редактор коллекции WizardStep. Добавьте новый WizardStep, задав для его ID значение UserSettings, Title для параметров и StepType.Step Затем поместите его таким образом, чтобы он поступил после CreateUserWizardStep («зарегистрироваться для создания новой учетной записи») и до CompleteWizardStep («Complete»), как показано на рис. 23.

добавить новый WizardStep в элемент управления 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>. Чтобы получить домашний город, домашнюю страницу и подпись нового пользователя, необходимо добавить пользовательский интерфейс. Это содержимое можно ввести в декларативном синтаксисе или в конструкторе. Чтобы использовать конструктор, выберите в раскрывающемся списке в смарт-теге шаг «ваши параметры», чтобы просмотреть шаг в конструкторе.

Note

При выборе шага в раскрывающемся списке смарт-тега обновляется свойствоActiveStepIndexэлемента управления CreateUserWizard, которое указывает индекс начального шага. Поэтому, если вы используете этот раскрывающийся список для изменения шага «ваши параметры» в конструкторе, убедитесь, что для него установлен флажок «зарегистрироваться для использования новой учетной записи», чтобы этот шаг отображался при первом посещении пользователем страницы 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, но с NULL базы данных для HomeTown, HomepageUrlи Signature. Значения, указанные для домашнего города, домашней страницы и подписи, никогда не используются. В результате получается новая учетная запись пользователя с записью UserProfiles, для которой еще не заданы поля HomeTown, HomepageUrlи Signature.

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

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

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, а затем снова сослаться на текстовые поля из WizardStep. После ссылки на текстовые поля можно приступить к выполнению инструкции UPDATE. UPDATEная инструкция имеет то же количество параметров, что и инструкция INSERT в обработчике событий CreatedUser, но здесь мы используем значения домашнего города, домашней страницы и подписи, предоставленные пользователем.

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

Note

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

Сводка

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

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

Поздравляем с программированием!

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

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

  • Доступ к данным и их обновление в ASP.NET 2,0
  • Элемент управления мастера ASP.NET 2,0
  • Создание пошагового пользовательского интерфейса с помощью элемента управления мастера ASP.NET 2,0
  • Создание пользовательских параметров элемента управления DataSource
  • Настройка элемента управления CreateUserWizard
  • Краткие руководства по элементу управления DetailsView
  • Отображение данных с помощью элемента управления ListView
  • Которая разбила элементов управления проверки в ASP.NET 2,0
  • Изменение операций вставки и удаления данных
  • Проверка формы в ASP.NET
  • Сбор настраиваемых сведений о регистрации пользователя
  • Профили в ASP.NET 2,0
  • Элемент управления ASP: ListView
  • Краткое руководство по профилям пользователей

Об авторе

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

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

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