How to load the profile of a newly-logged-in user before the redirect
Asked Answered
E

2

6

I started an ASP.NET MVC 2 project and I am building off of the code that was generated automatically.

The problem that I am experiencing is that after a user is logged in, it appears that the profile of the newly-logged-in user is not loaded into the HttpContext, so I get a ProviderException with the message "This property cannot be set for anonymous users" when attempting to set a property value in the current user's profile.

For the POST-only LogOn action, Visual Web Developer 2010 Express basically generated:

    [HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            if (MembershipService.ValidateUser(model.UserName, model.Password))
            {
                FormsService.SignIn(model.UserName, model.RememberMe);
        //...

where FormsService is a property of the controller of type FormsAuthenticationService (also generated):

public class FormsAuthenticationService : IFormsAuthenticationService
{
    public void SignIn(string userName, bool createPersistentCookie)
    {
        if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");

        FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
    }

    public void SignOut()
    {
        FormsAuthentication.SignOut();
    }
}

After the FormsService.SignIn(model.UserName, model.RememberMe) line I was assuming that information for the newly-logged-in account would be immediately available to the controller, but this does not appear to be the case. If, for example, I add profile.SetPropertyValue("MyProfileProperty", "test") below the call to FormsService#SignIn, then I get the ProviderException "This property cannot be set for anonymous users".

How do I load the newly-logged-in user's profile into the HttpContext so that I can set a property value in his or her profile before the next request?

Emersen answered 19/1, 2011 at 15:48 Comment(0)
B
7

The naming of the function is counter intuitive, but ProfileBase.Create(username) will load the existing profile for an existing user or create a new profile if none exists.

var profile = ProfileBase.Create(userName);

This will not load the profile into ControllerContext.HttpContext.Profile but at least you can access or alter the user profile.

Burgrave answered 19/1, 2011 at 16:8 Comment(3)
No, you're wrong to assume that, it will load an existing profile. Try it out.Burgrave
"It took some time until I realized that calling ProfileBase.Create() with a username as argument performs a lookup against TableStorage and actually retrieves the data associated with that username. As far as I'm concerned, calling this method Create() is misleading, I would expect Load() or Get()." see the answer to this question: #1127219Burgrave
This worked like a charm! Thank you Steven! (To anyone who might read this seeking a similar solution, be sure to call Save on the profile object if you make changes.)Emersen
H
1

The "raw" Forms authentication built into the MVC template does not automatically load the profile. All it does is validate the user against the Membership tables and set the login cookie. If you want profile data persisted in Session state on login, you'll have to do that explicitly:

[HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            if (MembershipService.ValidateUser(model.UserName, model.Password))
            {
                FormsService.SignIn(model.UserName, model.RememberMe);
                LoadProfile(model.UserName);
            }
     }

     private void LoadProfile(string UserName)
     {
          MyModelContext ctx = new MyModelContext(); //EF or LINQ2SQL context
          var user = ctx.Users.Where(u => u.UserName == UserName).FirstOrDefault();
          Session.Add("CurrentUser", user);
     }

UPDATE:

I misunderstood the original question. You have to create and save a profile of type ProfileCommon for anonymous users. See this post:

http://forums.asp.net/p/1150958/2619264.aspx

Hoodwink answered 19/1, 2011 at 15:56 Comment(4)
I'm assuming the profile then is loaded into Session when the "next" page is loaded after logging in. Is that correct?Whitewash
@Nick: In this implementation, the profile is loaded into session immediately upon validation, before the redirect.Hoodwink
This may be a dumb question, but how does this load the profile (ControllerContext.HttpContext.Profile) of the newly-logged-in user?Emersen
@Daniel: I'm assuming that the OP is connecting to the Membership tables in a SQL database. The sample code above demonstrates the idea of using an Entity Framework or LINQ2SQL context to connect to that database and load the profile. If the profile is being stored somewhere else, a different method would be used to load it.Hoodwink

© 2022 - 2024 — McMap. All rights reserved.