Я реализовал пользовательский объект Profile в коде, как описано здесь Джоэлом:
Как назначить значения профиля?
Однако я не могу заставить его работать, когда создаю нового пользователя. Когда я это сделаю:
Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyRole");
пользователь создается и добавляется к роли в базе данных, но HttpContext.Current.User
все еще пуст, а Membership.GetUser()
возвращает null, поэтому это (из кода Джоэла) не работает:
static public AccountProfile CurrentUser
{
get { return (AccountProfile)
(ProfileBase.Create(Membership.GetUser().UserName)); }
}
AccountProfile.CurrentUser.FullName = "Snoopy";
Я пробовал вызвать Membership.GetUser(userName)
и таким образом установить свойства профиля, но установленные свойства остаются пустыми, а вызов AccountProfile.CurrentUser(userName).Save()
ничего не помещает в базу данных. Я также пытался указать, что пользователь действителен и вошел в систему, вызывая Membership.ValidateUser
, FormsAuthentication.SetAuthCookie
и т. Д., Но текущий пользователь по-прежнему является нулевым или анонимным (в зависимости от состояния файлов cookie моего браузера).
РЕШЕНО (ДАЛЕЕ ОТредактировано, СМ. НИЖЕ): Основываясь на объяснении Фрэнси Пенов и некоторых других экспериментах, я выяснил проблему. Код Джоэла и варианты, которые я пробовал, будут работать только с существующим профилем. Если профиль не существует, ProfileBase.Create(userName)
будет возвращать новый пустой объект при каждом вызове; вы можете устанавливать свойства, но они не будут «закрепляться», потому что каждый раз, когда вы обращаетесь к нему, возвращается новый экземпляр. Установка для HttpContext.Current.User
нового GenericPrincipal
даст вам объект "Пользователь", но не объект "Профиль", и ProfileBase.Create(userName)
и HttpContext.Current.Profile
по-прежнему будут указывать на новые пустые объекты.
Если вы хотите создать Профиль для вновь созданного Пользователя в том же запросе, вам необходимо позвонить HttpContext.Current.Profile.Initialize(userName, true)
. Затем вы можете заполнить инициализированный профиль и сохранить его, и он будет доступен в будущих запросах по имени, так что код Джоэла будет работать. Я только использую HttpContext.Current.Profile
для внутренних целей, когда мне нужно создать / получить доступ к профилю сразу после создания. По любым другим запросам я использую ProfileBase.Create(userName)
, и я выставил только эту версию как общедоступную.
Обратите внимание, что Фрэнси прав: если вы хотите создать пользователя (и роли) и установить его как аутентифицированный в первом круговом обходе, а затем попросить пользователя войти в систему, вы сможете получить доступ к профилю намного проще. с помощью кода Джоэла при последующем запросе. Что меня поразило, так это то, что роли доступны сразу после создания пользователя без какой-либо инициализации, а профиль - нет.
Мой новый код AccountProfile:
public static AccountProfile CurrentUser
{
get
{
if (Membership.GetUser() != null)
return ProfileBase.Create(Membership.GetUser().UserName) as AccountProfile;
else
return null;
}
}
internal static AccountProfile NewUser
{
get { return System.Web.HttpContext.Current.Profile as AccountProfile; }
}
Создание нового пользователя:
MembershipUser user = Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyBasicUserRole");
AccountProfile.NewUser.Initialize(userName, true);
AccountProfile.NewUser.FullName = "Snoopy";
AccountProfile.NewUser.Save();
Последующий доступ:
if (Membership.ValidateUser(userName, password))
{
string name = AccountProfile.CurrentUser.FullName;
}
Кроме того, спасибо Фрэнси за объяснение жизненного цикла аутентификации - я вызываю FormsAuthentication.SetAuthCookie в своей функции проверки, но возвращаю логическое значение, указывающее на успех, потому что User.Identity.IsAuthenticated не будет истинным до следующего запроса.
ПЕРЕСМОТРЕНО. Я идиот. Приведенное выше объяснение работает в узком случае, но не решает основную проблему: вызов CurrentUser каждый раз возвращает новый экземпляр объекта, независимо от того, существует ли это Профиль или нет. Поскольку это определено как свойство, я не думал об этом и написал:
AccountProfile.CurrentUser.FullName = "Snoopy";
AccountProfile.CurrentUser.OtherProperty = "ABC";
AccountProfile.CurrentUser.Save();
что (конечно) не работает. Должен быть:
AccountProfile currentProfile = AccountProfile.CurrentUser;
currentProfile.FullName = "Snoopy";
currentProfile.OtherProperty = "ABC";
currentProfile.Save();
Я сам виноват в том, что полностью упустил из виду этот основной момент, но я считаю, что объявление CurrentUser как свойства подразумевает, что это объект, которым можно манипулировать. Вместо этого он должен быть объявлен как GetCurrentUser()
.