dave317
dave317

Reputation: 774

DotNet Core 2 Seed User and Roles

Using the template built into VS2017 for Core 2 MVC with Authentication. Trying to seed the database with Users and Roles. Roles work well, they seed. Users always return an error saying "Cannot be NULL", i think its because this line at the end of the initialize function cannot actually find the user

await _userManager.AddToRoleAsync(await _userManager.FindByNameAsync(user), "Administrator");

I used this post to build it: https://gist.github.com/mombrea/9a49716841254ab1d2dabd49144ec092

NOTE - This post is for Core 1.0 and I am using Core 2.0, that might be why I am having problems.

As mentioned, I can seed Roles but the user is not creating itself. Once i figure this out I will try multiple users, i already did a test creating multiple roles.

Here is the Initializer Class

//Taken from :
    //https://gist.github.com/mombrea/9a49716841254ab1d2dabd49144ec092
    public interface IdentityDBIitializer
    {
        void Initialize();
    }

    public class LatestUserDBInitializer : IdentityDBIitializer
    {
        private readonly ApplicationDbContext _context;
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly RoleManager<IdentityRole> _roleManager;

        public LatestUserDBInitializer(
            ApplicationDbContext context,
            UserManager<ApplicationUser> userManager,
            RoleManager<IdentityRole> roleManager)
        {
            _context = context;
            _userManager = userManager;
            _roleManager = roleManager;
        }

        //This example just creates an Administrator role and one Admin users
        public async void Initialize()
        {
            //create database schema if none exists
            _context.Database.EnsureCreated();

            //If there is already an Administrator role, abort
            //if (_context.Roles.Any(r => r.Name == "Administrator")) return;

            //Create the Administartor Role
            //await _roleManager.CreateAsync(new IdentityRole("Administrator"));

            //Create the default Admin account and apply the Administrator role
            string user = "[email protected]";
            string password = "z0mgchangethis";
            await _userManager.CreateAsync(new ApplicationUser { UserName = user, Email = user, EmailConfirmed = true }, password);
            await _userManager.AddToRoleAsync(await _userManager.FindByNameAsync(user), "Administrator");
        }
    }

Here is my STartup:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<POSContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("UKFest2018Context")));

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("UKFestIdentityContext")));

            services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();


            // Add Database Initializer
            services.AddScoped<IdentityDBIitializer, LatestUserDBInitializer>();

            // Add application services.
            services.AddTransient<IEmailSender, EmailSender>();

            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IdentityDBIitializer dBInitializer)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseAuthentication();

            //Seeds Identity DB
            dBInitializer.Initialize();

            //UserRoleInitializer.InitializeUsersAndRoles(app.ApplicationServices);

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }

Upvotes: 1

Views: 1396

Answers (2)

Nicholas
Nicholas

Reputation: 1980

wew, same issue when i was working on .NET Core 2 Betas...

It could either mean that the credentials did not comply with your configurations. Or, in my case, I had to obtain the dbcontext and managers via an IServiceProvider.

You can do this at the end of Configure(...)

// Data seeding
            await Data.DataSeeder.SeedDatabase(app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope());

Have a data seeder class that uses an IServiceScope to hook up with the dependencies, poof

public class DataSeeder
    {
        public static async Task SeedDatabase(IServiceScope scope)
        {
            try
            {
                CounterDbContext context = scope.ServiceProvider.GetService<CounterDbContext>();

                CustoUserManager userManager = scope.ServiceProvider.GetRequiredService<CustoUserManager>();
                CustoRoleManager roleManager = scope.ServiceProvider.GetRequiredService<CustoRoleManager>();

                // SEED USER CODE HERE
                // SEED USER CODE HERE
                // SEED USER CODE HERE
                // SEED USER CODE HERE


                if (!context.CurrencyTypes.Any()) {
                        string[,] currencyTypes = new string[,] {
                            { "Crypto", "CRYPTO" },
                            { "Fiat Money", "FIAT" }
                        };

                        for (int i = 0; i < currencyTypes.GetLength(0); i++)
                        {
                            CurrencyType cType = new CurrencyType()
                            {
                                Name = currencyTypes[i, 0],
                                TypeShortForm = currencyTypes[i, 1],
                            };

                            context.CurrencyTypes.Add(cType);
                        }

                        context.SaveChanges(firstUser.Id);
                    }
}
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }

This could be messy... The above was the seeding class right? Here's how you do it for the users.

#if DEBUG
                string[] CreateUsers = { "nixholas"};
                string[] CreateNames = { "Nicholas" };
                string[] CreateEmails = { "[email protected]" };
                string defaultPassword = "P@ssw0rd";

                // Seed the roles first
                // https://stackoverflow.com/questions/34343599/how-to-seed-users-and-roles-with-code-first-migration-using-identity-asp-net-mvc
                if (!roleManager.Roles.Any())
                {
                    foreach (UserRoleType role in Enum.GetValues(typeof(UserRoleType)))
                    {
                        var newRole = new Role();
                        newRole.Name = role.ToString();
                        await roleManager.CreateAsync(newRole);
                    }
                }

                if (await userManager.FindByEmailAsync(CreateEmails[0]) == null)
                {
                    for (int i = 0; i < CreateUsers.Length; i++)
                    {
                        User user = new User
                        {
                            Email = CreateEmails[i],
                            UserName = CreateUsers[i],
                            Name = CreateNames[i]
                        };

                        await userManager.CreateAsync(user, defaultPassword);

                        // Setup
                        await userManager.UpdateSecurityStampAsync(user);
                        user.NormalizedUserName = user.UserName;
                        user.NormalizedEmail = user.Email;
                        await userManager.UpdateNormalizedUserNameAsync(user);
                        await userManager.UpdateNormalizedEmailAsync(user);
                        await userManager.UpdateAsync(user);

                        // Email Automated Setup
                        var token = await userManager.GenerateEmailConfirmationTokenAsync(user);
                        await userManager.ConfirmEmailAsync(user, token);

                        await userManager.AddToRoleAsync(user, "Owner");
                    }
                }

Upvotes: 0

Edward
Edward

Reputation: 30046

For your issue, it is caused by that your password is not valid which causes the creating user failed. Then, await _userManager.FindByNameAsync(user) will return null instead of the expected User.

You could try the Password like 1qaz@WSX.

You could refer enter link description here to find the default requirements.

Upvotes: 1

Related Questions