How do I manage profiles using SimpleMembership?
Asked Answered
C

4

19

I have an ASP.NET MVC 4 site based off the internet template. I am using the SimpleMembership which i set up with that template.

I can modify the Users table which has been creted for me but I am unsure as to the "correct" way to modify the extra fields I have added. I want Fullname, Email etc and have added them to the user table but there appears no way to update through the SimpleMembership WebSecurity.* static methods.

Are you supposed to just update those properties yourself using EF outside of the SimpleMembership API?

Copeck answered 10/9, 2012 at 12:56 Comment(0)
Z
22

1 - You need to enable migrations, prefereably with EntityFramework 5

2 - Move your

WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "EmailAddress", autoCreateTables: true); 

to your Seed method in your YourMvcApp/Migrations/Configuration.cs class

    protected override void Seed(UsersContext context)
    {
        WebSecurity.InitializeDatabaseConnection(
            "DefaultConnection",
            "UserProfile",
            "UserId",
            "UserName", autoCreateTables: true);

        if (!Roles.RoleExists("Administrator"))
            Roles.CreateRole("Administrator");

        if (!WebSecurity.UserExists("lelong37"))
            WebSecurity.CreateUserAndAccount(
                "lelong37",
                "password",
                new {Mobile = "+19725000000", IsSmsVerified = false});

        if (!Roles.GetRolesForUser("lelong37").Contains("Administrator"))
            Roles.AddUsersToRoles(new[] {"lelong37"}, new[] {"Administrator"});
    }

Now EF5 will be in charge of creating your UserProfile table, after doing so you will call the WebSecurity.InitializeDatabaseConnection to only register SimpleMembershipProvider with the already created UserProfile table, also tellling SimpleMembershipProvider which column is the UserId and UserName. I am also showing an example of how you can add Users, Roles and associating the two in your Seed method with custom UserProfile properties/fields e.g. a user's Mobile (number) and IsSmsVerified.

3 - Now when you run update-database from Package Manager Console, EF5 will provision your table with all your custom properties

For additional references please refer to this article with sourcecode: http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/

Zimmermann answered 28/9, 2012 at 17:45 Comment(4)
Nice... this really helped me solve a really difficult situation. :) More on this matter here: weblogs.asp.net/jgalloway/archive/2012/08/29/…Curse
this assumes you're using the DEMOWARE code from the Internet template. In a real world app, you'd have your EF dependencies in a data access project, and you probably wouldn't want that to take a dependency on the WebMatrix assemblies or any of System.Web.Surrounding
I agree, but how do you get around using Webmatrix in your data access project?Iraqi
I have a question please, I did everything and I sucessfully create roles and users but when I try to affect users to roles I get exception because Users table is empty and my users data goes to UserTable so what's wrong exactlyFoulk
D
15

They made it easy to modify the profile with SimpleMembership. SimpleMembership is using the code first EF model and the user profile is defined in the file AccountModels.cs that is generated as part of the Internet template for MVC 4. Just modify the class UserProfile and add the new fields in the class definition. For example, adding a field for email would look something like this:

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string Email { get; set; }
}

Here is an example on how you would access the email field:

var context = new UsersContext();
var username = User.Identity.Name;
var user = context.UserProfiles.SingleOrDefault(u => u.UserName == username);
var email = user.Email;

Here is what the database looks like after adding the email field.

enter image description here

There is a good blog that describes some of the changes in SimpleMembership here. You can also find more detailed information on customizing and seeding SimpleMembership here.

Dispersoid answered 10/9, 2012 at 14:39 Comment(10)
two questions from that though. 1) does adding a property here changed the DB automatically? and how to get the currently logged in user's email from the API? (assuming the properties above)Vibrate
It will change the DB schema on creation so you will need to remove any existing DB for this to work. I updated the answer to show you would access the email. It is not an API like the old MembershipProvider.Dispersoid
Now I updated that UserProfile class and deleted my database tables but upon recreation the new fields did not appear?Copeck
Also when I decompile the WebSecurity.InitializeDatabaseConnection then I can see it only does UserName and UserId. There is no code in ther to do extra columns. I think you must have to create them yourself.Copeck
It automatically creates the new column in the database for me by just modifying the UserProfile class as you can see in my updated answer. What version of MVC 4 and VS are you using? This was done using the latest release of MVC 4 (not beta or RC) running on the latest release of VS 2012.Dispersoid
Also note that SimpleMembership uses a different database than the one created by the ASP.NET Web Site Administration Tool previously used for user profile information.Dispersoid
i am using latest VS 2012 and build in MVC 4, start new project using internet template and default AccountController. After adding new property to AccountModel's UserProfile class, the database didn't generate the field for my new property. I have deleted the database many times and repeat the process, but the new property i added never get created in my databaseVidda
suhendri - Are you sure you are looking at the correct database. The are two, one for the standard ASP.NET security, and the other for SimpleMembership. Hard to tell what is going on for you without code examples and screen shots. You may want to open your own QA with the details to get some assistance.Dispersoid
Somebody can help to update the Manage.cshtml view + controller so that the user can edit his own email as per example above?Craving
Look at this blog post [kevin-junghans.blogspot.com/2013/02/… which shows how to add email confirmation to the registration process. This will show you how to capture the email in Register.cshtml. The same concepts would apply to Manage.cshtml.Dispersoid
V
4

if you look right around line 273 of the accountcontroller you'll find this line

db.UserProfiles.Add(new UserProfile { UserName = model.UserName });

Looks like even OOTB they (MS) are doing just as you suggested and using EF to update.

I too, am looking for the "correct" way of updating and accessing these properties.

Edit:

Here's my solution (I'm happy if someone says there's an OOTB way to do this).

wrap UserProfile (the .net Entity from SimpleMembership) in a session class.

public static class sessionHelpers {
     public static UserProfile userProfile
        {
            get
            {
                if (HttpContext.Current.Session["userProfile"] != null)
                {
                    return HttpContext.Current.Session["userProfile"] as UserProfile; 
                }
                else
                {
                    using (UsersContext db = new UsersContext())
                    {
                        HttpContext.Current.Session["userInfo"] =
                        db.UserProfiles.Where(x => x.UserName == 
                            HttpContext.Current.User.Identity.Name).FirstOrDefault();

                   return db.UserProfiles.Where(x => x.UserName == 
                       HttpContext.Current.User.Identity.Name).FirstOrDefault();
                    }
                }
            }
            set { HttpContext.Current.Session["userProfile"] = value; }
        }
}

From this you can access the profile table by doing

string foo = sessionHelpers.userProfile.FIELDNAME;

where sessionHelpers is my wrapper class. The if block just ensures that if it hasn't been set in the current session that accessing it will attempt to get it.

Vibrate answered 10/9, 2012 at 13:21 Comment(4)
hmmm...i sense some serious code smell here...you're co-mingling DB access code with web code. I would highly recommend refactoring ALL entity framework references into an isolated Data Access project, then using the repository pattern to allow callers to retrieve data for the app.Surrounding
With this pattern, how do you ensure that changes to the profile are written back to the database?Bombe
I would cast what's in the session to UserProfile rather than use the as keyword. If you accidentally put some other type in there, your getter will just return null. It's better to fail immediately than try and diagnose downstream problems caused by a null UserProfile.Bombe
The code queries the DB twice with the same query. Although the query is probably cached, it's still extra load.Bombe
S
1

You need to add them to your Database ( done according to description )

add them to the view ( edit , add , delete , and view ) unless modified

add them to your model in UserProfiles

Then it will work.

Swarm answered 19/7, 2013 at 20:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.