Profile.UserName is a readonly field. So, how do you change a
user’s name? Many use email address as user name (like us,
Pageflakes) and we want to allow users to change their email
address which in turn changes their user name. So, how do you do
it?
It looks like there’s no easy way to do it. You have to do the
following:
- Create a new user using the new email address
- Get the password of the old account and set it to the new
account. If you can’t get the old password via Membership provider,
then ask user. - Create a new profile for the new user account
- Copy all the properties from the old profile to the new profile
object. - Log out user from old account
- Auto sign in to the new account so that user does not notice
what an incredible thing just happened.
Here’s how I do it:
if (Profile.UserName !=
newUserName)
{
// Changing email address of user.
Delete current user account and create
// a new one using the new email address
but the same password
if ( null != Membership.GetUser(newUserName))
throw new ApplicationException( "There's another user with the same email. Please enter a different email.");
MembershipUser newUser = Membership.CreateUser(newUserName, currentPassword);
// Create profile for the new user and
copy all values from current profile
// to new profile
ProfileCommon newProfile = ProfileCommon.Create(newUserName, true) as ProfileCommon;
newProfile.IsInvited = Profile.IsInvited;
newProfile.IsRealUser = Profile.IsRealUser;
newProfile.Name = newUserName;
newProfile.Save();
if ( Membership.ValidateUser(newUserName, currentPassword))
{
FormsAuthentication.SignOut();
Session.Abandon();
// Delete the old profile and
user
ProfileManager.DeleteProfile(Profile.UserName);
Membership.DeleteUser(user.UserName);
//FormsAuthentication.SetAuthCookie(newUserName,
true);
FormsAuthentication.RedirectFromLoginPage(newUserName, true);
}
}
I ended up just going straight to the database level and changing each username within the database. You can easily do this in the aspnet_users table.
See:
jonswain.wordpress.com/…/renamingchanging-username-in-aspnet
Daniel,
I’ve used the approached you describe and it has worked just fine for me.
Cheers, Ben
i usee the query in this controlchange password
“select password into register where
email='”+changepassword1.Username+”‘”
then
it give massege for falier
if i use username field in username text the give success massege
but i want to control on email basies
Here’s a class that interfaces with the stored procedure I just mentioned. It inherits from System.Web.Security.MembershipUser, and I use it like this (VB.NET):
Dim myUser As cMembershipUser
myUser = Membership.GetUser(Me.OriginalUserName)
myUser.ChangeUserName(“NewUserNameHere”)
————————–
Imports Microsoft.VisualBasic
Imports System.Data.SqlClient
Public Class cMembershipUser
Inherits System.Web.Security.MembershipUser
Public Function ChangeUserName(ByVal NewUserName As String) As Boolean
Dim IsSuccsessful As Boolean = False
If IsUserNameValid(NewUserName) Then
Dim myConn As New SqlConnection(ConfigurationManager.ConnectionStrings(“pbv2005”).ToString)
Dim cmdChangeUserName As New SqlCommand()
With cmdChangeUserName
.CommandText = “dbo.aspnet_Membership_ChangeUserName”
.CommandType = Data.CommandType.StoredProcedure
.Connection = myConn
.Parameters.Add(“@ApplicationName”, Data.SqlDbType.NVarChar)
.Parameters.Add(“@OldUserName”, Data.SqlDbType.NVarChar)
.Parameters.Add(“@NewUserName”, Data.SqlDbType.NVarChar)
End With
cmdChangeUserName.Parameters(“@ApplicationName”).Value = ConfigurationManager.AppSettings(“AppKey”).ToString
cmdChangeUserName.Parameters(“@OldUserName”).Value = Me.UserName
cmdChangeUserName.Parameters(“@NewUserName”).Value = NewUserName
Try
myConn.Open()
cmdChangeUserName.ExecuteNonQuery()
myConn.Close()
IsSuccsessful = True
Catch ex As Exception
IsSuccsessful = False
End Try
Else
IsSuccsessful = False
End If
Return IsSuccsessful
End Function
Private Function IsUserNameValid(ByVal username As String) As Boolean
‘ Add whatever username requirement validation you want here, doesn’t
‘ the membership provider have some build in functionality for this?
If username.Length > 4 Then
Return True
Else
Return False
End If
End Function
End Class
After reading the discussion above I created the following stored procedure that seems to do the trick. Sorry if it got word-wrapped, but hopefully you get the idea. I’m surprised that Microsoft would have the foresight to distinguish between UserId and UserName, but not build in the ability to change the username. Why else would you have a seperate UserId value if not to let UserName change?
Working on something now that’ll allow this to be called in code along the lines of:
Membership.ChangeUserName(“OldName”, “NewName”)
Hope it helps!
————
CREATE PROCEDURE dbo.aspnet_Membership_ChangeUserName
@ApplicationName NVARCHAR(256),
@OldUserName NVARCHAR(256),
@NewUserName NVARCHAR(256)
AS
BEGIN
DECLARE @UserId AS UNIQUEIDENTIFIER
DECLARE @ApplicationId AS UNIQUEIDENTIFIER
— Lookup the ApplicationId
SELECT @ApplicationId = ApplicationId
FROM dbo.aspnet_Applications
WHERE LoweredApplicationName = LOWER(@ApplicationName)
— Lookup the UserId
SELECT @UserId = UserId
FROM aspnet_Users
WHERE ApplicationId = @ApplicationId AND LoweredUserName = LOWER(@OldUserName)
— Change the username
UPDATE dbo.aspnet_Users
SET UserName = @NewUserName, LoweredUserName = LOWER(@NewUserName)
WHERE ApplicationId = @ApplicationId AND UserId = @UserId
END
Hey folks, looks like I spoke too soon… a problem with my class above is Membership.GetUser() is designed to return a MembershipUser object. So when I try to do this:
Dim myUser As cMembershipUser
myUser = Membership.GetUser(Me.OriginalUserName)
it fails because myUser is the wrong type, and even when I try to cast the return result it doesn’t work. Anyone know how to use inheretance, but still let your modified class be used in this way? In the meantime as a workaround I created a static utility class with a method that lets me update the username interfacing with the stored procedure above. I’ve pasted it below, and you’d use it like this:
utils.ChangeUserName(“oldUserName”, “newUserName”)
—————-
Imports Microsoft.VisualBasic
Imports System.Data.SqlClient
Public Class utils
Public Shared Function ChangeUserName(ByVal oldUserName As String, ByVal newUserName As String) As Boolean
Dim IsSuccsessful As Boolean = False
If IsUserNameValid(NewUserName) Then
Dim myConn As New SqlConnection(ConfigurationManager.ConnectionStrings(“pbv2005”).ToString)
Dim cmdChangeUserName As New SqlCommand()
With cmdChangeUserName
.CommandText = “dbo.aspnet_Membership_ChangeUserName”
.CommandType = Data.CommandType.StoredProcedure
.Connection = myConn
.Parameters.Add(“@ApplicationName”, Data.SqlDbType.NVarChar)
.Parameters.Add(“@OldUserName”, Data.SqlDbType.NVarChar)
.Parameters.Add(“@NewUserName”, Data.SqlDbType.NVarChar)
End With
cmdChangeUserName.Parameters(“@ApplicationName”).Value = ConfigurationManager.AppSettings(“AppKey”).ToString
cmdChangeUserName.Parameters(“@OldUserName”).Value = oldUserName
cmdChangeUserName.Parameters(“@NewUserName”).Value = newUserName
Try
myConn.Open()
cmdChangeUserName.ExecuteNonQuery()
myConn.Close()
IsSuccsessful = True
Catch ex As Exception
IsSuccsessful = False
End Try
Else
IsSuccsessful = False
End If
Return IsSuccsessful
End Function
Private Shared Function IsUserNameValid(ByVal username As String) As Boolean
‘ Add whatever username requirement validation you want here, doesn’t
‘ the membership provider have some build in functionality for this?
If username.Length > 4 Then
Return True
Else
Return False
End If
End Function
End Class
Works like a charm Doug! Thanks. I added the following to your stored procedure cause I’m anal and I want everything to be consistent:
— Change the e-mail address
UPDATE dbo.aspnet_Membership
SET Email = @NewUserName, LoweredEmail = LOWER(@NewUserName)
WHERE ApplicationId = @ApplicationId AND UserId = @UserId
Like the addition, but I’m guessing you do this because your front end has the user log in with their e-mail address and password: making the e-mail behave as if it was the username. For those of us still using the “out of the box” behavior, this isn’t the case, so you you wouldn’t necessarily want to overwrite the e-mail address with a username change.
However I wonder if that’s a better way to go… probably easier for users to remember an e-mail address over a username, especially if they visit the site sporadically.
Membership Provider: changing the username
Where’s the ChangeUserName() function?
I recently built a site that uses the Microsoft ASP.NET Membership, Role and Profile providers (2.0 framework
http://gener4.com >golden valley cabin rentals
Hellons!
I stumbled upon this and thought was very useful. My only concern as someone already pointed out: updating all references to the old id.
In spite of this, still useful.
I also bookmarked it:
http://www.codebounce.com/ASPNET
Thanks to Omar, Doug Taylor and Thomas
Thomas, your code works great. Thanks!
Here is the VB version of Thomas' code…
1. Make sure New UserName is Unique
2. Update the aspnet_Users table directly
3. Execute to following code to change the username/cookie/identity without leaving the webpage…
' Obtains the name of the FormsAuthentication Cookie, uses that name to request the Cookie and Decrypts the Cookies information into a AuthTicket
Dim AuthTicket As FormsAuthenticationTicket = FormsAuthentication.Decrypt(HttpContext.Current.Request.Cookies(FormsAuthentication.FormsCookieName).Value)
' Instantiates a new user identity authenticated using forms authentication based on the FormsAuthenticationTicket.
' The FormsAuthenticationTicket has been created using the exact same parameters of the user with the Old Username except the Old Username has been updated with the New Username.
Dim NewFormsIdentity As New FormsIdentity(New FormsAuthenticationTicket(AuthTicket.Version, NewUsername, AuthTicket.IssueDate, AuthTicket.Expiration, AuthTicket.IsPersistent, AuthTicket.UserData))
' Parse out the AuthTicket's UserData into a string array of Roles
Dim Roles As String() = AuthTicket.UserData.Split(“|”.ToCharArray)
' Creates a new user that has the NewFormsIdentity and belongs to the array of Roles, if any, that was stored in the FormsAuthenticationTicket
Dim NewGenericPrincipal As New System.Security.Principal.GenericPrincipal(NewFormsIdentity, Roles)
' Sets the security information for the current HTTP request to the new user. The Username has now been changed (i.e. HttpContext.Current.User.Identity.Name = NewUsername, prior to this step is was the OldUsername)
HttpContext.Current.User = NewGenericPrincipal
' Removes the forms-authentication ticket from the browser
FormsAuthentication.SignOut()
' Cancels the current session
HttpContext.Current.Session.Abandon()
' Creates an authentication ticket for the supplied New Username and adds it to the cookies collection of the response or the URL
FormsAuthentication.SetAuthCookie(HttpContext.Current.User.Identity.Name, AuthTicket.IsPersistent)
4. Response.Redirect back to the same page if needed.
Here is a C# version of Doug's plus corrected some issues regarding finding the username because sometimes it could not be available in web.config.
///////////////////////
public class utils
{
public static bool ChangeUserName(string oldUserName,string newUserName)
{
bool IsSuccsessful = false;
string ApplicationName;
if(IsUserNameValid(newUserName))
{
if ((ConfigurationManager.ConnectionStrings[“applicationName”] == null) || String.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[“applicationName”].ToString()))
{ApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;}
else
{ ApplicationName = ConfigurationManager.ConnectionStrings[“applicationName”].ToString(); }
SqlConnection myConn = new SqlConnection(ConfigurationManager.ConnectionStrings[“ApplicationServices”].ToString());
SqlCommand cmdChangeUserName= new SqlCommand();
cmdChangeUserName.CommandText=”dbo.aspnet_Membership_ChangeUserName”;
cmdChangeUserName.CommandType = CommandType.StoredProcedure;
cmdChangeUserName.Connection = myConn;
cmdChangeUserName.Parameters.Add(“@ApplicationName”, SqlDbType.NVarChar);
cmdChangeUserName.Parameters.Add(“@OldUserName”, SqlDbType.NVarChar);
cmdChangeUserName.Parameters.Add(“@NewUserName”, SqlDbType.NVarChar);
cmdChangeUserName.Parameters[“@ApplicationName”].Value = ApplicationName;
cmdChangeUserName.Parameters[“@OldUserName”].Value = oldUserName;
cmdChangeUserName.Parameters[“@NewUserName”].Value = newUserName;
try
{
myConn.Open();
cmdChangeUserName.ExecuteNonQuery();
myConn.Close();
IsSuccsessful = true;
}
catch(Exception ex )
{IsSuccsessful = false;}
}
else{IsSuccsessful = false;}
return IsSuccsessful;
}
private static bool IsUserNameValid(string username)
{
//Add whatever username requirement validation you want here, doesnt
//the membership provider have some build in functionality for this?
return true;
}
}
Hi everybody, did anybody notice that main problem is not how to update the aspnet_Users and aspnet_Membership tables but the aspnet_Profile table as well. Don’t forget that the username is also referenced in the aspnet_Profile table. So the question is: “How are you going to update the aspnet_Profile table?”, knowing that the data format in that table is somehow not easy to manipulate through T-SQL. Please consider this fact and post a viable solution. Thanks anyway for all these comments trying to address the issue.