简体   繁体   中英

How to implement Identity in ASP.NET Core 2.2

In my website, I want to let login the admin with an account in order to modify the database. Also, I might add some roles and accounts in the future.

So, I am trying to implement identity .

I made a project in Visual Studio 2019 (not sure if that is important) and choose ASP.NET Core 2.2 (I installed Core 2.2 on my own) with MVC, Authentication with individual user accounts and I let clicked the box which said: "configure for HTTPS".

Once made the project, I open it, make a random account, got an error and then migrate the database to fix it.

Then, I add in appsetting.json :

"UserSettings": {
    "UserName": "MyAdminUser",
    "UserEmail": "MyAdminUser@gmail.com",
    "UserPassword": "A_123456a"
}

Create a new class inside the folder Data :

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace WebApplication1.Data {
    public static class Seed {
        public static async Task CreateRoles(IServiceProvider serviceProvider, IConfiguration Configuration) {
            // Add customs roles
            var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
            // Note: I used IdentityUser instead of make my ApplicationUser as other people do because the default idendity is fine for me, I don't need additional fields nor I want to make this more difficult.
            var UserManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>();
            string[] roleNames = { "Admin" };
            IdentityResult roleResult;

            foreach (var roleName in roleNames) {
                // Create roles and seeding them to the database
                var roleExist = await RoleManager.RoleExistsAsync(roleName);
                if (!roleExist) {
                    roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
                }
            }

            // Create a super user
            var poweruser = new IdentityUser {
                UserName = Configuration.GetSection("AppSettings")["UserSettings:UserName"],
                Email = Configuration.GetSection("AppSettings")["UserSettings:UserEmail"]
            };

            string userPassword = Configuration.GetSection("AppSettings")["UserSettings:UserPassword"];
            var user = await UserManager.FindByEmailAsync(Configuration.GetSection("AppSettings")["UserSettings:UserEmail"]);

            if (user == null) {
                var createPowerUser = await UserManager.CreateAsync(poweruser, userPassword);
                if (createPowerUser.Succeeded) {
                    // Assign the new user the "Admin" role 
                    await UserManager.AddToRoleAsync(poweruser, "Admin");
                }
            }
        }
    }
}

And finally replace the Main method of Program class to:

public static void Main(string[] args) {
    var host = CreateWebHostBuilder(args).Build();    
    using (var scope = host.Services.CreateScope()) {
        var services = scope.ServiceProvider;
        var serviceProvider = services.GetRequiredService<IServiceProvider>();
        var configuration = services.GetRequiredService<IConfiguration>();
        Seed.CreateRoles(serviceProvider, configuration).Wait();
    }    
    host.Run();
}

But when I run it, the error HTTP Error 500.30 - ANCM In-Process Start Failure is raised on the webpage and the debug console said the following exceptions:

  • 'System.InvalidOperationException' in Microsoft.Extensions.DependencyInjection.Abstractions.dll
  • 'System.AggregateException' in System.Private.CoreLib.dll

I don't know how to fix that.

Also, I have found all these questions (with their answers) 1 , 2 , 3 , 4 , 5 , 6 and these Non-SO 7 and 8 . But my main problem with them is that each one use a different way to implement an Identity (some of them obsolete to 2.2) and I don't know which one is better, even some raise error on my project or I don't understand at all, so I tried to do this (I read that execute this code in Program is better than Startup in perfomance).

By the way, I also tried to remove my code from Programm and instead add in the Configure method from Startup the parameter IServiceProvider serviceProvider and:

// I used _ = because VS said me something about async
_ = Seed.CreateRoles(serviceProvider, Configuration);

Running your code shows an exception on the following line:

var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();

Based on the exception it appears you are missing the configuration in the startup.cs file to enable Identity. I can't see your startup.cs but I suspect you are missing the whole services.AddIdentity(...) calls.

I suggest you take some time to read up on how to configure Identity in ASP.NET Core. The Microsoft Docs are always a good place to start.

Also, the second question you mentioned in your question has good steps. You specifically need to look at Step 2 and Step 3.

The issue is that you're attempting to retrieve scoped services from IServiceProvider without creating a scope. Interestingly, you created a scope around your call to Seed.CreateRoles , but then you pass in IServiceProvider , which is not scoped.

What you should be doing is either passing in IServiceProvider and creating the scope inside your Seed.CreateRoles method, or leave the scope creation where it is now and instead pass in your scoped services, ie RoleManager and UserManager .

Edit

You need to do one of the following:

  1. Inject IServiceProvider and then create your scope inside the seed method:

     var host = CreateWebHostBuilder(args).Build(); Seed.CreateRoles(host.Services); host.Run(); 

    Then:

     public static async Task CreateRoles(IServiceProvider services) { var configuration = services.GetRequiredService<IConfiguration>(); using (var scope = services.CreateScope()) { var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>(); var userManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>(); // seed data } } 
  2. Inject your scoped services:

     var host = CreateWebHostBuilder(args).Build(); var configuration = host.Services.GetRequiredService<IConfiguration>(); using (var scope = host.Services.CreateScope()) { var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>(); var userManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>(); Seed.CreateRoles(configuration, roleManager, userManager); } host.Run(); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM