3

我正在尝试将来自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 ....)。这是一座太远的桥梁,还是一个可行的解决方案?


没有人遇到这个问题吗?不?那就只有我了!

只是为了更新,我已经尝试了 Franci Penov 在他对这个帖子的回答中提出的建议。

所以,现在我的代码看起来像这样。

            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.

因此,就会员资格而言,用户已登录,但配置文件系统仍然认为没有。

有任何想法吗?

4

2 回答 2

4

欢呼!

更仔细地阅读这篇文章,我想我会尝试显式调用配置文件 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);
}

希望这可以帮助。

道格

于 2010-06-23T13:04:41.100 回答
0

我有一个稍微简单的方法来解决这个问题。

我在 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 字段(它链接到另一个数据库)。我在登录时执行此操作以传输信息。

在登录时不必要地设置它们或仅更新需要更改的字段之前,您可能应该检查是否存在任何字段的特定用户的信息。

注意:您必须首先初始化配置文件,否则任何更改都会导致黄屏错误。

于 2014-07-24T16:00:25.430 回答