25

I have an ASP.NET Core app that uses Identity. It works, but when I am trying to add custom roles to the database I run into problems.

In Startup ConfigureServices I have added Identity and the role manager as a scoped service like this:

services.AddIdentity<Entities.DB.User, IdentityRole<int>>()
                .AddEntityFrameworkStores<MyDBContext, int>();

services.AddScoped<RoleManager<IdentityRole>>();

and in Startup Configure I inject RoleManager and pass it to my custom class RolesData:

    public void Configure(
        IApplicationBuilder app, 
        IHostingEnvironment env, 
        ILoggerFactory loggerFactory,
        RoleManager<IdentityRole> roleManager
    )
    {

    app.UseIdentity();
    RolesData.SeedRoles(roleManager).Wait();
    app.UseMvc();

This is the RolesData class:

public static class RolesData
{

    private static readonly string[] roles = new[] {
        "role1",
        "role2",
        "role3"
    };

    public static async Task SeedRoles(RoleManager<IdentityRole> roleManager)
    {

        foreach (var role in roles)
        {

            if (!await roleManager.RoleExistsAsync(role))
            {
                var create = await roleManager.CreateAsync(new IdentityRole(role));

                if (!create.Succeeded)
                {

                    throw new Exception("Failed to create role");

                }
            }

        }

    }

}

The app builds without errors, but when trying to access it I get the following error:

Unable to resolve service for type 'Microsoft.AspNetCore.Identity.IRoleStore`1[Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole]' while attempting to activate 'Microsoft.AspNetCore.Identity.RoleManager

What am I doing wrong? My gut says there's something wrong with how I add the RoleManager as a service.

PS: I have used "No authentication" when creating the project to learn Identity from scratch.

Christian Wattengård
  • 5,543
  • 5
  • 30
  • 43
Glenn Utter
  • 2,313
  • 7
  • 32
  • 44
  • I suggest create another project using individual user accounts so you can compare to what gets setup for you when you use the template that includes identity – Joe Audette Jan 02 '17 at 12:06
  • A brand new project with "individual user accounts" added does not contain any code that sets up roles. – Glenn Utter Jan 02 '17 at 12:21
  • no it doesn't but it could have some code that wires up dependencies you haven't wired up correctly – Joe Audette Jan 02 '17 at 13:20
  • On an unrelated note, you should avoid injecting scoped dependencies like `RoleManager` in the `Configure` method, as it will prevent the underlying `DbContext` from being correctly disposed. Instead, consider using `IServiceScopeFactory.CreateScope()` to create a service scope that will be disposed when your `SeedRoles` method returns (you can take a look at https://github.com/openiddict/openiddict-samples/blob/master/samples/ClientCredentialsFlow/AuthorizationServer/Startup.cs#L98-L115 for an example) – Kévin Chalet Jan 02 '17 at 15:12

3 Answers3

30

I was having this issue

No service for type 'Microsoft.AspNetCore.Identity.RoleManager`

And this page was the first result on Google. It did not answer my question, so I thought I would put my solution here, for anyone else that may be having this problem.

ASP.NET Core 2.2

The missing line for me was .AddRoles() in the Startup.cs file.

        services.AddDefaultIdentity<IdentityUser>()
            .AddRoles<IdentityRole>()
            .AddDefaultUI(UIFramework.Bootstrap4)
            .AddEntityFrameworkStores<ApplicationDbContext>();

Hope this helps someone

Source: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.2 (at the bottom)

Dave ت Maher
  • 1,561
  • 14
  • 8
24

What am I doing wrong? My gut says there's something wrong with how I add the RoleManager as a service.

The registration part is actually fine, tho' you should remove services.AddScoped<RoleManager<IdentityRole>>(), as the role manager is already added for you by services.AddIdentity().

Your issue is most likely caused by a generic type mismatch: while you call services.AddIdentity() with IdentityRole<int>, you try to resolve RoleManager with IdentityRole, which is an equivalent of IdentityRole<string> (string being the default key type in ASP.NET Core Identity).

Update your Configure method to take a RoleManager<IdentityRole<int>> parameter and it should work.

Kévin Chalet
  • 39,509
  • 7
  • 121
  • 131
  • 1
    This was a great fix and very helpful. I also recommend calling the SeedRoles from a DatabaseInitializer so that does the CreateUsers and the roles async from the startup something like`code` public async Task SeedAsync(){ await CreateUsersAsync(); await RolesData.SeedRoles(_roleManager);} – RussHooker Jun 07 '17 at 03:01
  • I had a function where I seed some data, including roles. And when I fetched the RoleManager service, I did serviceProvider.GetRequiredService>(); it should have been serviceProvider.GetRequiredService>>(); with the generic integer specificity – Minasie Shibeshi Sep 05 '20 at 09:22
0

This my solution seed User and Role ASP.NET Core 2.2

Startup.cs

services.AddDefaultIdentity<ApplicationUser>()
            .AddRoles<IdentityRole<Guid>>()
            .AddDefaultUI(UIFramework.Bootstrap4)
            .AddEntityFrameworkStores<ApplicationDbContext>();

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    ...
    ...
    SeedData.Initialize(app.ApplicationServices);
)

SeedData.cs

public static void Initialize(IServiceProvider serviceProvider)
{
    using (var scope = serviceProvider.CreateScope())
    {
        var provider = scope.ServiceProvider;
        var context = provider.GetRequiredService<ApplicationDbContext>();
        var userManager = provider.GetRequiredService<UserManager<ApplicationUser>>();
        var roleManager = provider.GetRequiredService<RoleManager<IdentityRole<Guid>>>();

        // automigration 
        context.Database.Migrate(); 
        InstallUsers(userManager, roleManager);
     }
 }

 private static void InstallUsers(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole<Guid>> roleManager)
    {
        const string USERNAME = "admin@mysite.com";
        const string PASSWORD = "123456ABCD";
        const string ROLENAME = "Admin";

        var roleExist = roleManager.RoleExistsAsync(ROLENAME).Result;
        if (!roleExist)
        {
            //create the roles and seed them to the database
            roleManager.CreateAsync(new IdentityRole<Guid>(ROLENAME)).GetAwaiter().GetResult();
        }

        var user = userManager.FindByNameAsync(USERNAME).Result;

        if (user == null)
        {
            var serviceUser = new ApplicationUser
            {
                UserName = USERNAME,
                Email = USERNAME
            };

            var createPowerUser = userManager.CreateAsync(serviceUser, PASSWORD).Result;
            if (createPowerUser.Succeeded)
            {
                var confirmationToken = userManager.GenerateEmailConfirmationTokenAsync(serviceUser).Result;
                var result = userManager.ConfirmEmailAsync(serviceUser, confirmationToken).Result;
                //here we tie the new user to the role
                userManager.AddToRoleAsync(serviceUser, ROLENAME).GetAwaiter().GetResult();
            }
        }
    }
dev-siberia
  • 2,746
  • 2
  • 21
  • 17
  • This method produced errors for me. I changed the `IdentityRole` to `IdentityRole` throughout and it worked like a charm. – Eric K Jun 18 '19 at 21:59