Всемогущий, Google, найди мне чего-нибудь!

четверг, 11 февраля 2010 г.

Профиль пользователя в ASP.NET MVC приложении

Сегодня я расскажу вам как в ASP.NET приложении использовать провайдер профилей. Для начала я буду считать, что вы уже умеете пользоваться такими инструментами, как Visual Studio 2005/2008 и вы прочитали мою предыдущую статью про настройку базы данных для работы с ASP.NET приложениями. 
Теперь, после вступления, приступим к работе. Для начала необходимо настроить сам провайдер и указать какие поля будут использоваться при отображении или создании профилей пользователей. Перейдем в файл Web.config и включим провайдер профилей:
<profile defaultProvider="AspNetSqlProfileProvider" enabled="true" automaticSaveEnabled="false">
 <providers>
  <clear />
  <add name="AspNetSqlProfileProvider"
type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ApplicationServices"
applicationName="SoftCollector"/>
 </providers>
</profile>
Теперь укажем какие поля будем использовать. Например, нам необходимо от пользователя его имя, фамилия (опционально), пол, телефон(опционально) и адрес (опционально):
<profile defaultProvider="AspNetSqlProfileProvider" enabled="true" automaticSaveEnabled="false">
 <properties>
  <clear />
  <add name="FirstName" type="string" />
  <add name="SecondName" type="string"/>
  <add name="Gender" type="string"/>
  <add name="Telephone" type="string"/>
  <add name="Address" type="string"/>
 </properties>
 <providers>
  <clear />
  <add name="AspNetSqlProfileProvider"
type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ApplicationServices"
applicationName="SoftCollector"/>
 </providers>
</profile>
Мы описали внутреннюю работу, теперь необходимо создать страницу регистрации и страницу профиля. Я буду показывать загрузку профиля на уровне UI-приложения, но любую работу с базой данных лучше прятать в другие сборки. При создании любого ASP.NET MVC приложения по умолчанию создается контроллер для работы с пользователями (AccountController) и соответствующие страницы для работы с оным (Register.aspx, LogOn.aspx и др.). Для начала необходимо переделать форму регистрации под нужды профиля. Пример страницы для работы с полями профилей, описанными нами в файле Web.config, указан на рисунке 1:

 Рис. 1. Форма регистрации с полями профиля

Я использую ASP.NET MVC 2.0, а эта версия по-умолчанию создает модели для работы с пользователями, в частности RegisterModel (хранится в файле AccountModels.cs в папке Models в корне веб-приложения). Если используете 1.0 версию, то можете создать свою модель. Переделаем её для наших нужд:
[PropertiesMustMatch("Password", "ConfirmPassword", ErrorMessage = "Пароли должны совпадать.")]
public class RegisterModel
{
 [Required]
 [DisplayName("Пользователь")]
 public string UserName { get; set; }

 [Required]
 [DataType(DataType.EmailAddress)]
 [DisplayName("Email")]
 public string Email { get; set; }

 [Required]
 [ValidatePasswordLength]
 [DataType(DataType.Password)]
 [DisplayName("Пароль")]
 public string Password { get; set; }

 [Required]
 [DataType(DataType.Password)]
 [DisplayName("Подтвердить пароль")]
 public string ConfirmPassword { get; set; }

 [Required]
 [DisplayName("Имя")]
 public string FirstName { get; set; }

 [DisplayName("Фамилия")]
 public string SecondName { get; set; } 

 [DisplayName("Пол")]
 public string Gender { get; set; } 

 [DisplayName("Телефон")]
 [DataType(DataType.PhoneNumber)]
 public string Telephone { get; set; }

 [DisplayName("Адрес")]
 public string Address { get; set; }
}
Теперь необходимо слегка переделать функцию регистрации пользователей. Переходим в содержимое контроллера AccountController и ищем действие Register с аттрибутом [HttpPost] (2.0) или [AcceptVerbs(HttpVerbs.Post)] (1.0). Вот новая версия функции:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
 if (ModelState.IsValid)
 {
  // Attempt to register the user
  MembershipCreateStatus createStatus = MembershipService.CreateUser(model.UserName, model.Password, model.Email);

  if (createStatus == MembershipCreateStatus.Success)
  {
   var profile = ProfileBase.Create(userName, true);
   profile.SetPropertyValue("FirstName", model.FirstName);
   profile.SetPropertyValue("SecondName", model.SecondName);
   profile.SetPropertyValue("Gender", model.Gender);
   profile.SetPropertyValue("Telephone", model.Telephone);
   profile.SetPropertyValue("Address", model.Address);
   profile.Save();

   return RedirectToAction("Index", "Home");
  }

  ModelState.AddModelError("", ErrorCodeToString(createStatus));
 }

 // If we got this far, something failed, redisplay form
 return View(model);
}

Теперь при регистрации для пользователя будет создан профиль и сохранен в базе данных.

Далее необходимо создать функцию для загрузки профиля из базы. Сперва создадим новое действие, например, Profile в контроллере AccountController:
public ActionResult Profile()
{
 var user = Membership.GetUser(User.Identity.Name);
 var profile = ProfileBase.Create(User.Identity.Name);

 var model = new ProfileModel
  {
   Email = user.Email,
   ProfileInfo = profileInfo,
   UserName = user.UserName
  };

 return View(model);
}
Класс ProfileModel было создан для отображения профиля пользователя и имеет следующий синтаксис:
public class ProfileModel
{
 [DisplayName("Пользователь")]
 public string UserName { get; set; }

 [DataType(DataType.EmailAddress)]
 [DisplayName("Email")]
 public string Email { get; set; }

 public ProfileBase ProfileInfo { get; set; }
}

Теперь, порядок действий таков:
  1. зарегистрироваться, заполнив все поля (рис. 2);
  2. войти на ваш сайт;
  3. перейти по ссылке /Account/Profile.
Рис. 2. Пример заполненной формы


Рис. 3. Пример заполненного профиля.

Проект можно скачать тут: Скачать.

12 комментариев:

Маша комментирует...

Спасибо!!
Очень интересно!

Unknown комментирует...

Всегда пожалуйста :)
Очень рад помочь.

Unknown комментирует...

А как у тебя поле "Gender" в DropDownListofor получилось?

Я сейчас просто тоже с MVC2 разбираюсь, правда я не использую "Membership" решил напрямую через базу делать на Linq.

Этот Membership посути тот же ORM над юзерами и ролями как я понял?

Да ещё я немного не понял куда теперь совать HtmlEncode? А то в базу проходят записи типа

Вышли пожалуйста проект, покопаюсь.
iFanKiLL@Gmail.com

Unknown комментирует...

"Gender" это обычный типизированный List. Вот как выглядит действие регистрации:

public ActionResult Register()
{
var model = new RegisterModel
{
GenderList = new SelectList(new List { "Male", "Female" })
};
return View(model);
}


А на странице пишу, указывая какую коллекцию ей давать:
<div class="editor-field">
<%= Html.DropDownList("Gender", Model.GenderList, new { @class = "text-long" })%>
<%= Html.ValidationMessage("Gender", "*") %>
</div>

Если делать не через втроенный Membership, то лучше хотя бы сделать наследника от него и добавить функции, которые хочешь использовать (или переопределить наследуемые). А в web.config вместо Membeship стандартного указать свой класс в качестве провайдера аккаунтов по умолчанию. И тогда умный .NET будет использовать твой класс вызывая функции стандартные, а ты сможешь отдельно вызывать свои.

Ща сформирую проект и вышлю. А то я он весит полный 1,5 Гб (файликов софта много).

Unknown комментирует...

По записи какого типа идет речь?
Если я правильно понял, теоретически ASP.NET при прохожидении страницей PostBack'a должен проверять страницу на предмет валидности и на наличие опасных тэгов. И если включена проверка на самой странице и на действии котнроллера, то не должно разрешить.

Unknown комментирует...

Не было времени посмотреть проект, в выходные гляну.

Да всё верно asp.net проверяет и выдаёт страницу с исключением, проверку можно отключить атрибутом на контролере или методе. Хотелось бы чтоб ошибка показывалась как при проверке на валидацию - возле контрола предупреждение. Перехватывать исключение? Или можно Html.Decode Html.Encode использовать?

Насчет DropDownList - просто его можно сделать через UI Helper Templating Support.

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

Unknown комментирует...

С MembershipProvider уже разобрался.
Методов дофига, все их переопределять замучаешься :)

Unknown комментирует...

Добрый день.
хорошая статья!
Вышли пожалуйста проект на nunjax@gmail.com
буду очень признателен.
заранее спасибо

Анонимный комментирует...

Привет, можешь прислать проект на temoxa@front.ru
Буду очень благодарен=)

Анонимный комментирует...

Доброй ночи!
Пришли пожалуйста на mig2202@yandex.ru проект.
Заранее благодарю )))

Unknown комментирует...

Начинаю разбираться с ASP.NET MVC3. Раньше для web ничего не писал. Разбираться надо на ходу - при написании в будущем крупного проекта, поэтому требуется сразу выбрать правильное направление, а не осознать в середине разработки, что пошел не в ту сторону...
И стоит такой вопрос: насколько просто и удобно в будущем будет пользоваться встроенными в ASP.NET профилями пользователей для взаимодействия с ними (например, сделать почтовую рассылку всем пользователям сайта и т.п.)? Или имеет смысл разрабатывать свою структуру в БД и в ней хранить логины, пароли, информацию профилей и т.п.?
И может кто-нибудь показать пример, как получить в SQL-запросе к БД список имен всех пользователей сайта?
А так же мучает вопрос, в каком месте и в какое время (какой командой) происходит отправка данных нового регистрирующегося пользователя в БД.

lestex комментирует...

Привет, можешь прислать проект на lestex@gmail.com