ASP.NET MVC 2 и поставщик профилей таблиц SQL - PullRequest
3 голосов
/ 22 июня 2010

Я пытаюсь добавить образец профиля провайдера таблицы из http://www.asp.net/downloads/sandbox/table-profile-provider-samples на новый сайт MVC 2.

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

namespace MyNamespace.Models
{
    public class UserProfile : ProfileBase
    {
        [SettingsAllowAnonymous(false),CustomProviderData("FirstName;nvarchar")]
        public string FirstName
        {
            get { return base["FirstName"] as string; }
            set { base["FirstName"] = value; }
        }

        [SettingsAllowAnonymous(false),CustomProviderData("LastName;nvarchar")]
        public string LastName
        {
            get { return base["LastName"] as string; }
            set { base["LastName"] = value; }
        }

        public static UserProfile GetUserProfile(string username)
        {
            return Create(username,false) as UserProfile;
        }

        public static UserProfile GetUserProfile()
        {
            return Create(Membership.GetUser().UserName,true) as UserProfile;
        }
    }
}

И web.config вроде

<profile enabled="true" defaultProvider="TableProfileProvider" inherits="MyNamespace.Models.UserProfile">
  <providers>
    <clear />
    <add name="TableProfileProvider" type="Microsoft.Samples.SqlTableProfileProvider" connectionStringName="ContentDB" table="aspnet_UserProfiles" applicationName="/"/>
  </providers>
</profile>

Вещи, которые я думаю, я обнаружил на этом пути:

  • Для использования собственного провайдера с MVC требуется атрибут «наследует» для элемента <profile> в файле web.config, что исключает использование конструкции <properties><add ....> с тем же именем поля профиля.
  • Пример SQLПровайдеру табличного профиля необходим атрибут CustomProviderData, и поэтому он не может отображаться в файле web.config, поэтому его необходимо добавить в качестве атрибута к свойствам в классе профиля.

Кажется, все работает нормально , как только пользователь вошел в систему .Однако я хочу получить некоторые данные профиля как часть нового процесса регистрации пользователя, и я не могу получить доступ к объекту профиля, пока пользователь не вошел в систему.

Я попытался добавить вызов, чтобы сохранить профильданные в разделе регистрации нового пользователя кода шаблона MVC:

FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
UserProfile profile = UserProfile.GetUserProfile(Membership.GetUser().UserName);
profile.FirstName = "Doug";
Profile.Save();
return RedirectToAction("Index", "Home");

Однако кажется, что Membership.GetUser() является нулевым, пока пользователь фактически не войдет в систему. Я также пытался использовать имя пользователя из модели.

FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
UserProfile profile = UserProfile.GetUserProfile(model.UserName);
profile.FirstName = "Doug";
profile.Save();
return RedirectToAction("Index", "Home");

Это идет немного дальше, но не удается при попытке установить поле профиля FirstName, с сообщением об ошибке в виде строки "попытка установить атрибут как анонимного пользователя, но это не разрешено"(извините, у меня нет доступа к точному сообщению, так как я его печатаю).

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

Если нет простого способа обойти это, я мог бы заполнить таблицу профилей напрямую, используя методы доступа к данным (вставить в aspnet_UserProfiles ....).Это мост слишком далеко или это жизнеспособное решение?


Ни у кого не было этой проблемы?Нет?Только я тогда!

Просто чтобы обновить, я попробовал предложение, которое Франци Пенов делает в своем ответе на эту публикацию .

Итак, теперь мой код выглядит так.

            FormsService.SignIn(model.UserName, false /* createPersistentCookie */);

            GenericIdentity id = new GenericIdentity(model.UserName);
            HttpContext.User = new GenericPrincipal(id, null);

            UserProfile profile = UserProfile.GetUserProfile(Membership.GetUser().UserName) as UserProfile;
            profile.FirstName = "Doug";
            profile.Save();

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

Теперь, по крайней мере, вызов Membership.GetUser () возвращает действительный объект MembershipUser, но попытка установить свойство профиля FirstName по-прежнему приводит к сообщению This property cannot be set for anonymous users.

Итак, пользователь вошел в систему с точки зрения членства, но система профилей по-прежнему считает, что нет.

Есть идеи?

Ответы [ 2 ]

4 голосов
/ 23 июня 2010

Ура!

Читая эту публикацию еще точнее, я подумал, что попробую явно вызвать метод Initialize профиля, и это сработало!

Окончательный полный код метода действия регистра:

[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)
        {
            FormsService.SignIn(model.UserName, false /* createPersistentCookie */);

            GenericIdentity id = new GenericIdentity(model.UserName);
            HttpContext.User = new GenericPrincipal(id, null);

            UserProfile profile = UserProfile.GetUserProfile(Membership.GetUser().UserName) as UserProfile;
            profile.Initialize(Membership.GetUser().UserName, true);
            profile.FirstName = "Doug";
            profile.Save();

            return RedirectToAction("Index", "Home");
        }
        else
        {
            ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
        }
    }

    // If we got this far, something failed, redisplay form
    ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
    return View(model);
}

Надеюсь, это поможет.

Doug

0 голосов
/ 24 июля 2014

У меня немного более простой подход к проблеме.

Я установил следующее в моем файле web.config:

<profile enabled="true">
  <providers>
    <clear />
    <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
  </providers>
  <properties>
    <add name="InfoID" />
    <add name="FirstName" />
    <add name="LastName" />
    <add name="Address" />
    <add name="City" />
    <add name="State" />
    <add name="PostalCode" />
    <add name="Country" />
    <add name="Phone" />
  </properties>
</profile>

Чтобы обновить его в своем классе AccountController, я использовал следующее:

var user = db.UserInformations.FirstOrDefault(u => u.InfoID == infoID);
var profile = Request.RequestContext.HttpContext.Profile;
profile.Initialize(register.UserName, true);
profile.SetPropertyValue("InfoID", user.InfoID.ToString());
profile.SetPropertyValue("LastName", user.LastName);
profile.SetPropertyValue("FirstName", user.FirstName);
profile.SetPropertyValue("Address", user.Address);
profile.SetPropertyValue("City", user.City);
profile.SetPropertyValue("State", user.State);
profile.SetPropertyValue("Country", user.Country);
profile.SetPropertyValue("PostalCode", user.PostalCode);
profile.SetPropertyValue("Phone", user.Phone);
profile.Save();

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

Это прекрасно работает для меня. Он обновляет стандартную базу данных aspnet_Profile для указанного пользователя. Я конвертирую из одной системы входа в стандартную учетную запись, поэтому у меня есть дополнительное поле InfoID (оно ссылается на другую базу данных). Я делаю это при входе в систему, чтобы передать информацию.

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

ПРИМЕЧАНИЕ: вы должны инициализировать профиль FIRST, иначе любые изменения приведут к ошибке желтого экрана.

...