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:
- Change your
UserProfile
model to add anEmail
property, do the same to theRegisterModel
and change theLogin
model fromUserName
toEmail
- Update the
InitializeSimpleMembershipAttribute
to use Email instead ofUserName
as the natural key for the users - Update the
AccountController
Login
andRegister
actions so you capture a UserName and an Email on registration, and use the Email on login - Update the views
So, the actual changes to make are:
- Models/AccountModels.cs changes
-
class UserProfile
: add the propertypublic string Email { get; set; }
-
class LoginModel
: change the property name fromUserName
toEmail
-
class RegisterModel
: add the propertypublic string Email { get; set; }
and set its attributes toRequired
, set theDisplay(Name
etc. (max length if you want to enforce that as well
-
-
AccountController
changes-
Login
method:- Change
model.UserName
tomodel.Email
in the lineif (ModelState.IsValid && WebSecurity.Login(model.UserName ...
- Change
-
Register
method:- Change
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
toWebSecurity.CreateUserAndAccount(model.Email, model.Password, new { UserName = model.UserName });
-
EDIT – missed a change:
ChangeWebSecurity.Login(model.UserName, model.Password);
toWebSecurity.Login(model.Email, model.Password);
- Change
-
- Filters/InitializeSimpleMembershipAttribute.cs changes
- Change
"UserName"
to"Email"
inWebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
- Change
- Views/Account/Login.cshtml
- Change the three usages of
m.UserName
tom.Email
- Change the three usages of
- Views/Account/Register.cshtml
- Copy and paste the UserName
<li>
section and change the duplicatesm.UserName
tom.Email
- Copy and paste the UserName
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
<li>
@Html.Label("Email Address:")
@Html.TextBoxFor(m => m.UserName)
</li>
and then in the Login and Register model simply required the user name entered as an email format using:
[Required]
[DataType(DataType.EmailAddress)]
[EmailAddress]
[Display(Name = "UserEmail")]
public string UserName { get; set; }
Maybe too simplistic, but it works for me.