C# 如何在ASP.NET Core 2.2中实现标识

C# 如何在ASP.NET Core 2.2中实现标识,c#,asp.net,asp.net-core,.net-core,asp.net-core-mvc,C#,Asp.net,Asp.net Core,.net Core,Asp.net Core Mvc,在我的网站上,我想让管理员登录一个帐户,以便修改数据库。此外,我可能会在将来添加一些角色和帐户 因此,我正在尝试实现身份 我在Visual Studio 2019中做了一个项目(不确定这是否重要),选择了ASP.NET Core 2.2(我自己安装了Core 2.2),使用MVC,使用个人用户帐户进行身份验证,然后点击了“配置HTTPS”框 创建项目后,我打开它,创建一个随机帐户,得到一个错误,然后迁移数据库来修复它 然后,我添加了appsetting.json: "UserSettings":

在我的网站上,我想让管理员登录一个帐户,以便修改数据库。此外,我可能会在将来添加一些角色和帐户

因此,我正在尝试实现身份

我在Visual Studio 2019中做了一个项目(不确定这是否重要),选择了ASP.NET Core 2.2(我自己安装了Core 2.2),使用MVC,使用个人用户帐户进行身份验证,然后点击了“配置HTTPS”框

创建项目后,我打开它,创建一个随机帐户,得到一个错误,然后迁移数据库来修复它

然后,我添加了
appsetting.json

"UserSettings": {
    "UserName": "MyAdminUser",
    "UserEmail": "MyAdminUser@gmail.com",
    "UserPassword": "A_123456a"
}
在文件夹
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");
                }
            }
        }
    }
}
但当我运行它时,网页上出现了错误
HTTP error 500.30-ANCM进程内启动失败
,调试控制台显示了以下异常:

  • Microsoft.Extensions.DependencyInjection.Abstractations.dll中的“System.InvalidOperationException”
  • System.Private.CoreLib.dll中的“System.AggregateException”
我不知道如何解决这个问题。

此外,我还发现了所有这些问题(及其答案),,,以及这些非一般性的问题。但我对它们的主要问题是,每一个都使用不同的方法来实现一个标识(其中一些已经过时到2.2),我不知道哪一个更好,甚至有些在我的项目中出现错误,或者我根本不理解,所以我试着这样做(我读到在
程序中执行此代码在性能上优于
启动

顺便说一下,我还尝试从
program
中删除我的代码,而是从
Startup
中添加
Configure
方法参数
IServiceProvider serviceProvider
,并且:

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

运行代码会在以下行显示异常:

var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var rolemager=serviceProvider.GetRequiredService();
根据异常情况,您似乎缺少启用标识的
startup.cs
文件中的配置。我看不到您的
startup.cs
,但我怀疑您缺少整个
服务。AddIdentity(…)
调用

我建议您花些时间阅读如何在ASP.NET Core中配置标识。这些始终是一个很好的起点


另外,您在问题中提到的有很好的步骤。您特别需要查看步骤2和步骤3。

问题是,您试图从
IServiceProvider
检索作用域服务,而不创建作用域。有趣的是,您在调用
Seed.CreateRoles
的过程中创建了一个作用域,但随后传递了in
IServiceProvider
,未限定范围

您应该做的是传入
IServiceProvider
并在
Seed.CreateRoles
方法中创建作用域,或者将作用域创建留在现在的位置,而是传入作用域服务,即
RoleManager
UserManager

编辑

您需要执行以下操作之一:

  • 注入
    IServiceProvider
    ,然后在seed方法内创建您的作用域:

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

    公共静态异步任务CreateRoles(IServiceProvider服务){
    var configuration=services.GetRequiredService();
    使用(var scope=services.CreateScope())
    {
    var roleManager=scope.ServiceProvider.GetRequiredService();
    var userManager=scope.ServiceProvider.GetRequiredService();
    //种子数据
    }
    }
    
  • 注入您的作用域服务:

    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();
    
    var host=CreateWebHostBuilder(args.Build();
    var configuration=host.Services.GetRequiredService();
    使用(var scope=host.Services.CreateScope())
    {
    var roleManager=scope.ServiceProvider.GetRequiredService();
    var userManager=scope.ServiceProvider.GetRequiredService();
    CreateRoles(配置、角色管理器、用户管理器);
    }
    host.Run();
    

  • 我没有
    服务。AddIdentity(…)
    ,但是Visual Studio生成了这段代码
    服务。AddDefaultIdentity().AddDefaultUI(UIFramework.Bootstrap4)。AddEntityFrameworkStores();
    ,这不是身份的配置吗?我用
    服务。AddIdentity().AddEntityFrameworkStores().AddDefaultTokenProviders()替换了它
    但是我在System.Private.CoreLib.dll中得到了
    'System.ArgumentNullException',在System.Private.CoreLib.dll中得到了
    'System.AggregateException'。我会更仔细地再读一遍第二个问题。很抱歉,我想我还没听懂你的意思。那么,我应该把
    服务
    变量作为参数传递吗de
    Seed.CreateRoles
    仅作为参数
    IServiceProvider serviceProvider
    和do
    var Configuration=serviceProvider.GetRequiredService()
    ?这并不能修复错误。我在internet上发现了关于作用域的问题,并认为这是正确的。请参阅上面的编辑。本质上,使用作用域服务必须在同一个
    IServiceProvider
    实例创建的作用域内完成。如果在作用域内调用种子方法无关紧要,那么如果您仍然在直接在里面唱
    IServiceProvider
    IServiceProvider
    没有作用域,因此如果不创建另一个作用域,就无法从中拉出作用域服务。
    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
        }
    }
    
    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();