How to change user name in ASP.NET 2.0 Membership Provider

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:

  1. Create a new user using the new email address
  2. 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.
  3. Create a new profile for the new user account
  4. Copy all the properties from the old profile to the new profile
    object.
  5. Log out user from old account
  6. 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);
    }
}

21 thoughts on “How to change user name in ASP.NET 2.0 Membership Provider”

  1. Daniel,

    I’ve used the approached you describe and it has worked just fine for me.

    Cheers, Ben

  2. 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

  3. 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

  4. 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

  5. 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

  6. 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

  7. 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.

  8. 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.

  9. 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;

    }

    }

  10. 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.