Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Если провайдер членства помогает системе определить, что это за пользователь, его идентифицировать, провайдер ролей указывает системе на статус пользователя и наделяет его определенные правами доступа, то провайдер профилей определят набор дополнительных свойств пользователя. К подобным дополнительным свойствам могут относиться, например, рост, возраст, вес, должность и т.д.
Использовать профили очень просто:
// получение ViewBag.Name = HttpContext.Profile["Name"]; // установка string name = "Bill Gates"; HttpContext.Profile["Name"]=name;
Однако если вы так напишите в приложении, то скорее всего получите ошибку, так как перед использованием свойство Name должно быть определено. Теперь посмотрим, как все это должно быть определено и как все это использовать.
При использовании универсальных провайдеров (например, в проектах по шаблону Basic) у нас в файле web.config уже подключен стандартный провайдер профилей:
<profile defaultProvider="DefaultProfileProvider"> <providers> <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" /> </providers> </profile>
Добавим в узел profile определение профиля, изменив данный узел следующим образом:
<profile defaultProvider="DefaultProfileProvider"> <providers> <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" /> </providers> <properties> <add name="FirstName" type="System.String" /> <add name="LastName" type="System.String" /> <add name="Age" type="System.Int32"/> <group name="Contact"> <add name="Website" type="System.String"/> <add name="Email" type="System.String"/> </group> </properties> </profile>
Определение свойств профиля помещается в узел properties
. Определение свойства заключается в использовании элемента add
,
в котором мы определяем название свойства через атрибут name и его тип через атрибут type. В качестве типа могут выступать примитивные типы .NET.
Здесь также мы можем определить подгруппу свойств с помощью элемента group
. В дальнейшем мы можем использовать данные свойства профиля:
[Authorize] public class HomeController : Controller { public string Index() { HttpContext.Profile["FirstName"] = "Иван"; HttpContext.Profile["LastName"] = "Петров"; return "Добро пожаловать, " + HttpContext.Profile["FirstName"] + " " + HttpContext.Profile["LastName"]; } }
Определив в файле web.config свойства профиля, мы можем к ним обратиться, например присвоить: HttpContext.Profile["FirstName"]
.
Причем до присвоения эти свойства ничего не несут. А затем мы обратно можем получить.
Возникает вопрос, а куда это все сохраняется? При работе с универсальными провайдерами у нас создается в базе данных автоматически набор таблиц, одна из которых предназначена для хранения профилей - Profiles.
Перед использованием профилей она пуста и ничего в ней нет. Но после присвоения в ней появляются соответствующие данные. Например, в моем случае это будут следующие данные:
Названия установленных свойств у нас оказываются в поле PropertyNames, а их значения - в поле PropertyValueStrings. Кроме того, в таблице еще есть ряд столбцов, из которых хотелось бы выделить UserId. Это поле содержит ключ пользователя, которое имеет по этому полю связано с другими таблицами. А в качестве пользователя выступает текущий залогинившийся пользователь, который вошел в систему и обратился к методу Index контроллера Home.
Чтобы обратиться к свойствам, которые указаны в группе, мы обращаемся к ним через эту группу:
HttpContext.Profile.GetProfileGroup("Contact")["Email"] = "ivpetrov5@mail.ru"; ViewBag.Email = HttpContext.Profile.GetProfileGroup("Contact")["Email"];
В данном случае мы продолжим работу с проектом, где мы переопределяли универсальные провайдеры членства и ролей. Для начала добавим модель, которая будет содержать все свойства профиля. Пусть эта модель будет называться Profile:
public class Profile { public int Id { get; set; } // Внешний ключ для связи с пользователем public int UserId { get; set; } public virtual User User { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public DateTime LastUpdateDate { get; set; } }
И изменим класс контекста данных, чтобы он мог получать данные профилей:
public class UserContext : DbContext { public DbSet<User> Users { get; set; } public DbSet<Role> Roles { get; set; } public DbSet<Profile> Profiles { get; set; } }
Теперь нам нужно место, где мы будем хранить данные профилей. Для этого в базе данных создадим таблицу Profiles со следующим определением:
CREATE TABLE [dbo].[Profiles] ( [Id] INT NOT NULL PRIMARY KEY IDENTITY, [UserId] INT NOT NULL, [FirstName] NVARCHAR(50) NULL, [LastName] NVARCHAR(50) NULL, [Age] INT NULL, [LastUpdateDate] DATETIME NULL, CONSTRAINT [FK_Profiles_ToUsers] FOREIGN KEY ([UserId]) REFERENCES [Users]([Id]) ON DELETE CASCADE )
Таким образом, основной таблице у нас является Users, где находятся данные id, логина и пароля пользователей. Чтобы связать профиль с определенным пользователем в таблице профилей, мы определяем поле UserId. И это поле будет хранить значение столбца id из таблицы Users.
А теперь к самому интересному. Добавим в папку Providers класс провайдера профилей (назовем его CustomProfileProvider), который будет иметь следующее определение:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Profile; using System.Configuration; using CustomAuthorization.Models; using System.Data; namespace CustomAuthorization.Providers { public class CustomProfileProvider : ProfileProvider { public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection) { // коллекция, которая возвращает значения свойств профиля SettingsPropertyValueCollection result = new SettingsPropertyValueCollection(); if (collection == null || collection.Count < 1 || context == null) { return result; } // получаем из контекста имя пользователя - логин в системе string username = (string)context["UserName"]; if (String.IsNullOrEmpty(username)) return result; UserContext db = new UserContext(); // получаем id пользователя из таблицы Users по логину int userId = db.Users.Where(u => u.Email.Equals(username)).FirstOrDefault().Id; // по этому id извлекаем профиль из таблицы профилей Profile profile = db.Profiles.Where(u => u.UserId==userId).FirstOrDefault(); if (profile != null) { foreach (SettingsProperty prop in collection) { SettingsPropertyValue svp = new SettingsPropertyValue(prop); svp.PropertyValue = profile.GetType().GetProperty(prop.Name).GetValue(profile, null); result.Add(svp); } } else { foreach (SettingsProperty prop in collection) { SettingsPropertyValue svp = new SettingsPropertyValue(prop); svp.PropertyValue = null; result.Add(svp); } } return result; } public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) { // получаем логин пользователя string username = (string)context["UserName"]; if (username == null || username.Length < 1 || collection.Count < 1) return; UserContext db = new UserContext(); // получаем id пользователя из таблицы Users по логину int userId = db.Users.Where(u => u.Email.Equals(username)).FirstOrDefault().Id; // по этому id извлекаем профиль из таблицы профилей Profile profile = db.Profiles.Where(u => u.UserId == userId).FirstOrDefault(); // если такой профиль уже есть изменяем его if (profile != null) { foreach (SettingsPropertyValue val in collection) { profile.GetType().GetProperty(val.Property.Name).SetValue(profile, val.PropertyValue); } profile.LastUpdateDate = DateTime.Now; db.Entry(profile).State = EntityState.Modified; } else { // если нет, то создаем новый профиль и добавляем его profile = new Profile(); foreach (SettingsPropertyValue val in collection) { profile.GetType().GetProperty(val.Property.Name).SetValue(profile, val.PropertyValue); } profile.LastUpdateDate = DateTime.Now; profile.UserId = userId; db.Profiles.Add(profile); } db.SaveChanges(); } public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate) { throw new NotImplementedException(); } public override int DeleteProfiles(string[] usernames) { throw new NotImplementedException(); } public override int DeleteProfiles(ProfileInfoCollection profiles) { throw new NotImplementedException(); } public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate) { throw new NotImplementedException(); } public override string ApplicationName { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } } }
Класс провайдера наследуется от класса ProfileProvider и содержит определения ряда его методов. Так как у нас будет самый примитивный провайдер профилей, то мы реализуем всего два его метода: SetPropertyValues и GetPropertyValues.
Метод GetPropertyValues
принимает два параметра - контекст (откуда мы можем получить разные данные типа логина пользователя) и
коллекцию свойств профиля, которые будут использоваться. На выходе мы возвращаем объект SettingsPropertyValueCollection
, который
содержит названия свойств и их значения. Важно в любом случае передать названия свойств, даже если свойства не несут никакого значения,
иначе среда не сможет определить свойство и присвоить ему значение (например, HttpContext.Profile["FirstName"] = "Vova";
).
В самом методе мы получаем пользователя, его id, профиль и из профиля передаем значение в выходную коллекцию.
Метод SetPropertyValues
берет установленные данные и уже через контекст передает их в базу данных.
Теперь подключим провайдер в файле web.config, добавив после определения провайдера ролей следующие строки:
<profile enabled="true" defaultProvider="MyProfileProvider"> <providers> <add name="MyProfileProvider" type="CustomAuthorization.Providers.CustomProfileProvider"/> </providers> <properties> <add name="FirstName" type="System.String" /> <add name="LastName" type="System.String" /> <add name="Age" type="System.Int32"/> </properties> </profile>
И в завершении мы можем его протестировать, например, прописав в контроллере Home следующий метод:
public string ViewProfile() { HttpContext.Profile["FirstName"] = "Vova"; HttpContext.Profile["LastName"] = "Pupkin"; HttpContext.Profile.SetPropertyValue("Age", 28); return "Имя Фамилия: " + HttpContext.Profile["FirstName"].ToString() + " " + HttpContext.Profile["LastName"].ToString() + " возраст: "+ HttpContext.Profile["Age"].ToString(); }
Установка свойств может происходить как напрямую (HttpContext.Profile["FirstName"] = "Vova"
), так и с помощью метода
SetPropertyValue
. После установки данные профиля появятся в таблице Profiles в БД, и затем мы сможем их оттуда получать и использовать в приложении.