Simplemembership – adding email field and use as login-name

Simplemembership – adding email field and use as login-name

I am trying to do two things here:

1. Adding an email field to the (default)UserProfile table.
Works like a charm.
Users can register both a username and email.

2. Change the login to use the email instead of username, this does also works like a charm.

Here is the problem. The above only works when i seperate them, as soon as I use both of them the registration process fails with the following error message:

Cannot insert the value NULL into column 'UserName', table 'opdb.dbo.UserProfile'; column does not allow nulls. INSERT fails.

WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { Email = model.Email 
WebSecurity.Login(model.Email, model.Password);

I am more or less following the
guide found here,
In the comments section I see others having the same problem, however, the solution is not to set the UserName field to allow nulls as stated in the replies.

The strange thing is that everything works as long as I don’t use both together. Any ideas? This drives me crazy!

Thanks in advance

Edit: Could it be the order of columns in the database? That the field used for identification needs to be the first column in the table? So if I want email as ident that need to be the first column in the table?

It is not the column order. I think you haven’t set your WebSecurity.InitializeDatabaseConnection up properly. It sounds like when you add the email field, it is treated as the email field (and not the natural key for the users), and when you change the login to use the email, you are actually inserting the email into the UserName column?

Either way, it is simple to make work. Assuming you already have your email column in the database and you are using the standard Internet Application template, do the following:

  1. Change your UserProfile model to add an Email property, do the same to the RegisterModel and change the Login model from UserName to Email
  2. Update the InitializeSimpleMembershipAttribute to use Email instead of UserName as the natural key for the users
  3. Update the AccountController Login and Register actions so you capture a UserName and an Email on registration, and use the Email on login
  4. Update the views

So, the actual changes to make are:

  • Models/AccountModels.cs changes
    • class UserProfile: add the property public string Email { get; set; }
    • class LoginModel: change the property name from UserName to Email
    • class RegisterModel: add the property public string Email { get; set; } and set its attributes to Required, set the Display(Name etc. (max length if you want to enforce that as well
  • AccountController changes

    • Login method:

      • Change model.UserName to model.Email in the line if (ModelState.IsValid && WebSecurity.Login(model.UserName ...
    • Register method:

      • Change WebSecurity.CreateUserAndAccount(model.UserName, model.Password); to WebSecurity.CreateUserAndAccount(model.Email, model.Password, new { UserName = model.UserName });
      • EDIT – missed a change:
        Change WebSecurity.Login(model.UserName, model.Password); to WebSecurity.Login(model.Email, model.Password);
  • Filters/InitializeSimpleMembershipAttribute.cs changes
    • Change "UserName" to "Email" in WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
  • Views/Account/Login.cshtml
    • Change the three usages of m.UserName to m.Email
  • Views/Account/Register.cshtml
    • Copy and paste the UserName <li> section and change the duplicates m.UserName to m.Email

In a vanilla Internet Application MVC 4 project, these changes will work perfectly (in a true vanilla project you may have to apply migrations if you want to use these and you aren’t editing the database to add the Email column).

I am not sure if Andy Browns suggestion will work because the WebSecurity in namespace WebMatrix.WebData references will not work correctly as a result. They are specifically looking at the UserName field to perform their actions. I could be wrong, but that’s my perception. If you want a separate field, create another username field (Name) and run your own code to update that to reflect to the user.

I chose to set up a registration view that renamed the UserName to User Email

@Html.Label("Email Address:")
@Html.TextBoxFor(m => m.UserName)

and then in the Login and Register model simply required the user name entered as an email format using:

[Display(Name = "UserEmail")]
public string UserName { get; set; } 

Maybe too simplistic, but it works for me.