Search code examples
c#asp.net-mvcrazorasp.net-identity

Application Role Name Cannot Be Null Or Empty


So I am trying to create a new role in my MVC5 application. Every time I get an exception saying:

Name cannot be null or empty

Model:

    public class ApplicationRole : IdentityRole
    {
        public new string Id { get; set; }

        [Display(Name = "Name")]
        public new string Name { get; set; }

        [Display(Name = "Description")]
        [StringLength(100, MinimumLength = 5)]
        public string Description { get; set; }
    }

Controller:

[HttpPost]
[ValidateAntiForgeryToken]

public async Task<ActionResult> Create(ApplicationRole model)
{
    try
    {
        if (ModelState.IsValid)
        {
            var role = new ApplicationRole()
            {
                Name = model.Name,
                Description = model.Description
            };
            var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>());
            var result = await roleManager.CreateAsync(role);
            if (result.Succeeded)
            {
                return RedirectToAction("Index", "Roles", model);
            }
            else
            {
                AddErrors(result);
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
    // If we got this far, something failed, redisplay form
    return View(model);
}

Execution stops on the following line:

  var result = await roleManager.CreateAsync(role);

View:

@model IEnumerable<User_Manager_Interface.Models.ApplicationRole>
@{

    Layout = "~/Views/Shared/_Layout.cshtml";
}

@Html.ActionLink("Create New", "Create", "Roles", new object { }, new { @class = "stdbtn" })


<div class="contenttitle radiusbottom0">
    <h2 class="table"><span>Roles</span></h2>
</div>

<table cellpadding="0" cellspacing="0" border="0" class="stdtable" id="dyntable">
 <tbody>

        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Description)
                </td>

                <td>
                    @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                    @Html.ActionLink("Details", "Details", new { id = item.Id }) |
                    @Html.ActionLink("Delete", "Delete", new { id = item.Id })
                </td>
            </tr>
        }
    </tbody>
</table>

What I don't get is that role does get the fields I pass in my view but the error persists. Any suggestions on how I can get around this? Hopefully I have provided enough to reproduce the error.

UPDATE to my scenario:

  1. IdentityRole has its own Id and Name properties and if I declare them within the ApplicationRole model and decorating them with the new keyword it will obviously hide the inherited member. I was aware of this when I posted the question.

  2. If I remove the two properties altogether, then the application throws an exception at Runtime detailed:

Mapping and metadata information could not be found for EntityType 'User_Manager_Interface.Models.ApplicationRole

Going back to point 1. above, the reason I went with that implementation over 2. is because with 1., the application does not terminate but instead throws a model state error (as described in the question title) about Name property being null.

I tried to examine the stack trace for more details about the exception but I couldn't gather more information other than what I already know:

e.StackTrace "
at System.Data.Entity.Core.Objects.ObjectContext.GetTypeUsage(Type entityCLRType)\r\n
at System.Data.Entity.Core.Objects.ObjectContext.ValidateEntitySet(EntitySet entitySet, Type entityType)\r\n
at System.Data.Entity.Core.Objects.ObjectContext.VerifyRootForAdd(Boolean doAttach, String entitySetName, IEntityWrapper wrappedEntity, EntityEntry existingEntry, EntitySet& entitySet, Boolean& isNoOperation)\r\n
at System.Data.Entity.Core.Objects.ObjectContext.AddObject(String entitySetName, Object entity)\r\n
at System.Data.Entity.Internal.Linq.InternalSet1.<>c__DisplayClassd.<Add>b__c()\r\n
at System.Data.Entity.Internal.Linq.InternalSet
1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)\r\n
at System.Data.Entity.Internal.Linq.InternalSet1.Add(Object entity)\r\n
at System.Data.Entity.DbSet
1.Add(TEntity entity)\r\n
at Microsoft.AspNet.Identity.EntityFramework.RoleStore`3.d__2.MoveNext()\r\n---

End of stack trace from previous location where exception was thrown ---\r\n
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
at Microsoft.AspNet.Identity.RoleManager2.<CreateAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult()\r\n at User_Manager_Interface.Controllers.RolesController.d__5.MoveNext() in C:\Users\Linda\UserManager\FSKUserManager\FSK_UserManager_Web\Controllers\RolesController.cs:line 104"


Solution

  • I think it has to do with the new keyword in property declaration. If IdentityRole has already these properties remove the following properties from your ApplicationRole model

    public new string Id { get; set; }
    
    [Display(Name = "Name")]
    public new string Name { get; set; }
    

    UPDATE: In your ApplicationRole class, by declaring the Id and Name properties with the new keyword, you are actually hide the base class (IdentityRole) properties. As a result every time you are trying to save a new record these properties are null and you get the corresponding error.

    Also change this line from

    var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>());
    

    To

    var roleManager = new RoleManager<ApplicationRole>(new RoleStore<ApplicationRole>(db));