繁体   English   中英

在Asp.net核心中植入IdentityRole时出错

[英]Error in Seeding IdentityRole in Asp.net core

我无法将数据播种到身份角色表中。 我总是得到错误

System.NullReferenceException:'对象引用未设置为对象的实例。 <> 4__this._roleManager为空

我不确定为什么会发生这种情况,为什么不将数据植入表中,我该如何解决呢? 下面是我的代码

public class UserRoleSeed
{
    private readonly RoleManager<IdentityRole> _roleManager;
    private string[] _roleArray = { "Admin, TerminalManager, Dispatcher, Driver, Mechanic, Recruiter, MechanicManger" };

    public UserRoleSeed(RoleManager<IdentityRole> roleManager)
    {
        _roleManager = roleManager;
    }

    public async void Seed()
    {
        foreach (string index in _roleArray)
        {
            if ((await _roleManager.FindByNameAsync(index)) == null)
            {
                await _roleManager.CreateAsync(new IdentityRole { Name = index });
            }
        }         
    }
}

对于我的Startup.cs

    public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TransportDbContext>(options =>
           options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddMvc();  

            services.AddIdentity<ApplicationUser, IdentityRole<int>>()
                .AddEntityFrameworkStores<TransportDbContext>()
                .AddDefaultTokenProviders();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();

                //app.UseStaticFiles();

                app.UseAuthentication();
                app.UseMvc(
               routes =>
               {
                   routes.MapRoute("Default", "{controller=Home}/{action=Index}/{id?}");
               });
            }

            // seeds data into the identity role table
            new UserRoleSeed(app.ApplicationServices.GetService<RoleManager<IdentityRole>>()).Seed();
        }
    }
}

您正在使用异步方法来播种您的角色,但您没有等待它。 这意味着您的代码会继续前进,最终在分支超出范围时在异步方法中使用您依赖的变量。 因此, NullReferenceException

另外,像RoleManager<TRole>这样的服务是“作用域”服务,这意味着它们只能从特定的活动范围中检索。 在实际的请求中,将为该请求创建一个范围,以允许将这些服务注入到请求管道中的任何内容中。 但是,这里您没有活动范围,因此必须创建一个范围。

而不是尝试作为您的Configure方法的一部分进行播种,您应该将此代码移到Program类中。 下面的代码解决了以上两个问题:

public class Program
{
    public static void Main(string[] args) =>
        MainAsync(args).GetAwaiter().GetResult();

    public static async Task MainAsync(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();

        using (var scope = host.Services.CreateScope())
        {
            await new UserRoleSeed(scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>()).Seed();
        }

        await host.RunAsync();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

本质上,您将使用异步Main来运行您的应用程序,然后使您能够等待诸如种子之类的其他事件。 对于它的价值,可以使用实际的异步Main在C#7.2中将其缩短一些时间,即:

public static async Task Main(string[] args)

不必从Main代理到MainAsync ,但在MainAsync ,编译器只是为您设置了相同的构造。

这是使此代码正常工作的最短路径,但是您仍然有一些小问题。 首先,您应该避免使用async void ,这是一种反模式。 您实际上是在吞下异步输出,包括可能引发的任何异常。 当您实际上不关心实际收益时,实际上应该始终使用async Task作为收益。 需要使用async void个人已知的少数情况是适当的。 换句话说,如果您不知道何时应使用async void ,则不应使用async void

另外,尽管在类上新建一个并将依赖项传递给构造函数在技术上没有错,但在这种情况下,使该类静态化并将所需的依赖项传递给seed方法更合适:

await UserRoleSeed.Seed(roleManager);

最后,同样,尽管不是很关键,但惯例是使用Async后缀来命名异步方法。 这清楚地表明该方法是异步的,并防止了因为不明显需要等待它而意外地不等待该方法(这里可能就是这种情况)。 简而言之,将名称从Seed更改为SeedAsync ,因为它可以异步工作。

好的,我想通了,下面是我的解决方案。

我基本上修改了用于植入数据的类,并将其重命名为DbInitializer.cs

 public class DbInitializer
{
    private static readonly string[] _roleArray = { "Admin", "Terminal Manager", "Dispatcher", "Driver", "Mechanic", "Recruiter", "Mechanic Manger" };

    public static async Task InitializeAync (TransportDbContext context, IServiceProvider serviceProvider)
    {
        var roleManager = serviceProvider.GetRequiredService<RoleManager<Role>>();


        foreach (string index in _roleArray)
        {
            if ((await roleManager.FindByNameAsync(index)) == null)
            {
                await roleManager.CreateAsync(new Role { Name = index });
            }
        }

    }
}}

然后我按照@Chris Pratt的建议在Program.cs文件中调用了该函数。

public class Program
{
    public static void Main(string[] args) =>
    MainAsync(args).GetAwaiter().GetResult();

    public static async Task MainAsync(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();
        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            var context = services.GetRequiredService<TransportDbContext>();
            await DbInitializer.InitializeAync(context, services);
        }

        await host.RunAsync();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
} }

感谢所有试图帮助我的人

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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