Kobek
Kobek

Reputation: 1211

ASP.NET MVC 5 Identity - "A user name already exists" when using custom user

I am using ASP.NET MVC 5 to create a web app.

For the purposes of my app I have created a seprate "Website User" class that looks like this:

public class WebsiteUser
{
    public WebsiteUser()
    {
        this.Comments = new List<CommentEntityModel>();
    }
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ApplicationUser IdentityUser { get; set; }
    public ICollection<CommentEntityModel> Comments { get; set; }
}

My issue comes when I try and register a new user into the website.

My register action looks like this

public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Username, Email = model.Email };
            var websiteUser = service.CreateWebsiteUser(user);

            var result = await UserManager.CreateAsync(user, model.Password);
            var websiteUserResult = service.RegisterWebsiteUser(websiteUser);

            UserManager.AddToRole(user.Id, UserRoles.WebsiteUser.ToString());
            if (result.Succeeded && websiteUserResult)
            {
                await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);

                return RedirectToAction("Index", "Home");
            }
            AddErrors(result);
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

Pretty much the default one that Identity creates, except for these two lines:

var websiteUser = service.CreateWebsiteUser(user);
var websiteUserResult = service.RegisterWebsiteUser(websiteUser);

And what I have for them in the service is this :

CreateWebsiteUser()

public WebsiteUser CreateWebsiteUser(ApplicationUser appuser)
    {
        var user = new WebsiteUser
        {
            Name = appuser.UserName,
            IdentityUser = appuser
        };

        return user;
    }

RegisterWebsiteUser()

public bool RegisterWebsiteUser(WebsiteUser websiteUser)
    {
        try
        {
            this.context.WebsiteUsers.Add(new WebsiteUser {Name = websiteUser.Name, IdentityUser = websiteUser.IdentityUser});
            this.context.SaveChanges();
            return true;
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }

    }

And my issue is, that whenever I try to register a new user I get an exception on the this.context.SaveChanges() line, saying "A user name with the name |Name| already exists".

|Name| is basically the value of the UserName column in the ASPNetUsers Table.

I am really stuck and can't find a solution. (I can't even understand why an error like this would happen)

My DB structure seems okay to me so I guess the issue is somewhere else.

The only solution I can think of, is to completely remove my own User class and just add properties to the deafult ASP User.

Any help is greatly appreciated.

Upvotes: 0

Views: 2655

Answers (1)

Kobek
Kobek

Reputation: 1211

Solved it. Leaving this here if anyone faces a similar problem.

Basically, due to some voodoo magic, that I do not understand, when you try to just add the just-created ApplicationUser to the IdenityUser's property of your custom User class, EF screws up, thinking you are using 2 data contexts.

The way to solve this is to instead use .Find(id) to find the ApplicationUser in the database, and then give that to the property.

So, instead of going

public bool RegisterWebsiteUser(ApplicationUser appUser)
{
        this.context.YourUsers.Add(new YourUser {IdentityUser = appUser});
        this.context.SaveChanges();

}

You do this:

public bool RegisterWebsiteUser(ApplicationUser applicationUser)
{
        string id = applicationUser.Id;
        var userFromDb = context.Users.Find(id);
        this.context.YourUsers.Add(new YourUser {IdentityUser = userFromDB});
        this.context.SaveChanges();
}

Upvotes: 1

Related Questions