Question

I am upgrading an application in Development from MVC4/EF5 to MVC5/EF6 to make use of (among other things) ASP.Net Identity. When I try to Create a User, my code is flagging the Model as Invalid and not creating the user. My View is simply displaying a box to enter an email, and then a Switch that lets the logged in admin select either an MemberOrganization or Sponsor to assign the new user 2 via some dropdowns.

The Create() method of my UserController is below:

        // GET: Admin/UserManagement/Create
        public ActionResult Create()
        {
            ViewBag.headerTitle = "Create User";
            ViewData["Organization"] = new SelectList(db.MemberOrganizations, "Id", "Name");
            ViewData["Sponsor"] = new SelectList(db.SponsorOrganizations, "Id", "Name");
            ViewBag.SwitchState = true;
            ApplicationUser newUser = new ApplicationUser();
            newUser.RegisteredDate = DateTime.Now;
            newUser.LastVisitDate = DateTime.Now;
            newUser.ProfilePictureSrc = null;
            return View(newUser);
        }

        // POST: Admin/UserManagement/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Create([Bind(Include = "Property1, Property2, etc.")] ApplicationUser applicationUser)
        {
            if (ModelState.IsValid)
            {
                ViewBag.headerTitle = "Create User";
                PasswordHasher ph = new PasswordHasher();
                var password = ph.HashPassword("aR@nD0MP@s$w0r9");
                var user = new ApplicationUser() { UserName = applicationUser.UserName, Email = applicationUser.Email, PasswordHash = password };
                IdentityResult result = await UserManager.CreateAsync(user, user.PasswordHash);
                if (result.Succeeded)
                {
                    await db.SaveChangesAsync();
                    return RedirectToAction("Index", "UserManagement");
                }
                else
                {
                    ModelState.AddModelError("", "Failed to Create User.");
                }
            }

            ModelState.AddModelError("", "Failed to Create User.");

            var errors = ModelState.Where(x => x.Value.Errors.Count > 0).Select(x => new { x.Key, x.Value.Errors }).ToArray();

            var errors2 = ModelState.Values.SelectMany(v => v.Errors);

            ViewData["Organization"] = new SelectList(db.MemberOrganizations, "Id", "Name", applicationUser.MemberOrgId);
            ViewData["Sponsor"] = new SelectList(db.SponsorOrganizations, "Id", "Name", applicationUser.SponsorOrgId);
            if (applicationUser.MemberOrgId != null)
            {
                ViewBag.SwitchState = true;
            }
            else
            {
                ViewBag.SwitchState = false;
            }
            ViewBag.OrganizationId = new SelectList(db.MemberOrganizations, "Id", "State", applicationUser.MemberOrgId);

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

        }

In my attempts to debug the issue I added the errors/errors2 variables as suggested in this post. Going down into the Model State properties when these are flagged I receive:

InvalidModelState1

InvalidModelState2

Does anyone have some thoughts on this matter? My previous code was working fine but I'm still getting use to ASP.Net Identity.

EDIT: As suggested by Rikard I have set my model where SponsorOrgID and MemberOrgID are not both required (only 1). Now my code processes down until the following segment:

var user = new ApplicationUser() { Name = applicationUser.Name, Email = applicationUser.Email, PasswordHash = password };
                IdentityResult result = await UserManager.CreateAsync(user, user.PasswordHash);
if (result.Succeeded) // ERROR
{
    await db.SaveChangesAsync();
    return RedirectToAction("Index", "UserManagement");
}

When I check the value of result and drill down to Errors->[string[]]->[0] the error message is: Name cannot be null or empty. Anyone have thoughts on this? I added a field to my View to specify the new users Name and incorporated it into the above new ApplicationUser() code line. I'm not fully sure where I am missing something.

EDIT2: Create() View [Relevant]:

@model PROJECTS.Models.ApplicationUser

@{
    ViewBag.Title = "Create";
    Layout = "~/Areas/Admin/Views/Shared/_LayoutAdmin.cshtml";
    string cancelEditUrl = "/Admin/UserManagement/";
}

@using (Html.BeginForm("Create", "UserManagement", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    @Html.HiddenFor(model => model.RegisteredDate)

    <div class="container">

        <div class="row">
            <div class="editor-label">
                @Html.LabelFor(model => model.Name)
            </div>
            <div class="editor-field" style="margin-bottom: 15px">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Name)
            </div>
        </div>

        <div class="row">
            <div class="editor-label">
                @Html.LabelFor(model => model.Email)
            </div>
            <div class="editor-field" style="margin-bottom: 15px">
                @Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Email)
            </div>
        </div>

....
Was it helpful?

Solution

As you can se in your last picture you have an error on the property SponsorOrgId that has the value string.Empty (""). Maybe the SponsorOrgId in ApplicationUser has the [Requried] attribute.

EDIT

Regarding your problem when trying to add the user to the Database (that was happen when you call UserManager.Create(user,password);

IdentityResult result = await UserManager.CreateAsync(user, user.PasswordHash);
if (result.Succeeded)
{
    await db.SaveChangesAsync();
    return RedirectToAction("Index", "UserManagement");
}
else
{
    var errors = string.Join(",", result.Errors);
    ModelState.AddModelError("", errors);
}

Then you can debug the value of "errors" or read the error message from your ModelState.

Regarding your EDIT

Add name to this part:

var user = new ApplicationUser() { UserName = applicationUser.UserName, Email = applicationUser.Email, PasswordHash = password, Name = applicationUser.Name };

EDIT 2 The problem is that is not possible to create a user without a username. But you can add the user's email to the username. And then change it to the user specified username. To make it pass the validation you need to add this part.

UserManager.UserValidator = new UserValidator<User>(UserManager) { RequireUniqueEmail = true };

OTHER TIPS

I realize it's late for a reply, but I read four threads on this before resolving this issue. It's not entirely obvious, and it appears to be an inheritance conflict with custom properties. The root of my problem was my creation of a UserName property - a custom property (...or so I thought) that I wanted to define as FirstName + " " + LastName.

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
//    public new string UserName { get; set; }
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)

...remainder removed for clarity.

As soon as I commented-out this line from IdentityModels.cs, which removed my custom property, POOF! Problem: solved. I drilled inheritance definitions all the way back to IUser[TKey], and I found what I think was the root of my (our) problem.

namespace Microsoft.AspNet.Identity
{
    // Summary:
    //     Minimal interface for a user with id and username
    //
    // Type parameters:
    //   TKey:
    public interface IUser<out TKey>
    {
    // Summary:
    //     Unique key for the user
    TKey Id { get; }
    //
    // Summary:
    //     Unique username
        string UserName { get; set; }
    }
}

I knew you could add custom properties to the ApplicationUser class, but I didn't know there were specific property names already in use - not defined in this class. Initially, after adding my UserName field simply as a public string, I received this:

[...] warning CS0114: 'MyApp.Models.ApplicationUser.UserName' hides inherited member 'Microsoft.AspNet.Identity.EntityFramework.IdentityUser<string,Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin,Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole,Microsoft.AspNet.Identity.EntityFramework.IdentityUserClaim>.UserName'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.

I'm good at following instructions, so I added the 'new' keyword (remember that line above I had to comment-out...?). It solved the compile time CS0114 warning, but it obstructed IUser's UserName.

OP (and countless others) did the same thing, I believe, when he wrote this:

var user = new ApplicationUser() { UserName = applicationUser.UserName, Email = applicationUser.Email, PasswordHash = password };

If you have username and email properties in your applicationuser class, these properties are hiding actual properties, so remove them from your application class.This will solve the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top