ASP.NET MVC 2 和 SQL 表配置文件提供程序

发布于 2024-09-06 23:12:00 字数 3829 浏览 3 评论 0原文

我正在尝试从 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 的自定义提供程序需要 web.config 中 元素上的“inherits”属性,该属性阻止使用具有相同配置文件字段名称的 构造。
  • 示例 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() 似乎为 null。我还尝试使用模型中的用户名。

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 配置文件属性仍会导致消息 无法为匿名用户设置此属性。

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

有什么想法吗?

I'm trying to add the sample table profile provider from http://www.asp.net/downloads/sandbox/table-profile-provider-samples to a new MVC 2 site.

After a bit of research and fiddling around, I've arrived at a profile class that looks like this.

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;
        }
    }
}

And a web.config like

<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>

Things I think I've found out along the way are

  • Using a custom provider with MVC requires the "inherits" attribute on the <profile> element in web.config, which precludes the use of a <properties><add ....> construct with the same profile field name.
  • The sample SQL table profile provider needs the CustomProviderData attribute and, because of the above, it cannot appear in the web.config file, so needs to be added as an attribute to the properties in the profile class.

It all seems to work OK once a user is logged in. However, I want to capture some profile data as part of the new user registration process, and I cannot seem to access the profile object until the user has logged in.

I've tried adding a call to save profile data in the new user registration section of the MVC template code:

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

However it seems that Membership.GetUser() is null until the user actually logs in. I also tried using the user's name from the model.

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

This gets a bit further, but fails when trying to set the FirstName profile field, with an error message along the lines of "trying to set an attribute as an anonymous user, but this is not allowed" (sorry, don't have access to the exact message as I'm typing this).

Is there any way round this? It looks like the FormsServer.SignIn method does not actually log the user in as far as forms authentication is concerned, and it needs a round trip to be fully logged in, presumably needing the cookie to be submitted back to the server.

If there's no easy way round this I could populate the profile table directly using data access methods (insert into aspnet_UserProfiles ....). Is this a bridge too far, or is it a viable solution?


Hasn't anyone got this problem? No? Just me then!

Just to update, I've tried the suggestion Franci Penov makes in his answer to this posting.

So, now my code looks like this.

            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");

Now, at least the call to Membership.GetUser() returns a valid MembershipUser object, but trying to set the FirstName profile property still results in the message This property cannot be set for anonymous users.

So, the user is logged on as far as Membership is concerned, but the Profile system still thinks not.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

山色无中 2024-09-13 23:12:00

欢呼!

阅读此发布 更仔细地说,我想我应该尝试显式调用配置文件初始化方法,并且它有效!

注册操作方法的最终完整代码是:

[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);
}

希望这有帮助。

道格

Hurrah!

Reading this posting even more closely, I thought I'd try calling the profile Initialize method explicitly, and it worked!

Final full code for the register action method is:

[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);
}

Hope this helps.

Doug

雨巷深深 2024-09-13 23:12:00

我对这个问题有一个稍微简单的方法。

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

您可能应该检查任何字段中是否存在特定用户的信息,然后再在登录时进行不必要的设置,或者仅更新那些需要更改的字段。

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

I have a slightly simpler approach to the problem.

I set the following in my web.config file:

<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>

To update it in my AccountController class, I used the following:

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();

Instead of using string keys, you could create a dynamic wrapper and initialize it with the profile variable.

This works fine for me. It updates the standard aspnet_Profile database for the user indicated. I am converting from one login system to the standard login, so I have the extra InfoID field (it links to another database). I do this at login to transfer the information over.

You should probably check to see if the information for the specific user exists for any of the fields before unnecessarily setting them upon login or update only those fields that need changing.

NOTE: you must initialize the profile FIRST, or any changes will cause a yellow screen error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文