Ошибка в заполнении IdentityRole в ядре Asp.net - PullRequest
0 голосов
/ 04 марта 2019

У меня проблемы с отправкой данных в таблицу ролей идентификации.Я всегда получаю сообщение об ошибке

System.NullReferenceException: «Ссылка на объект не установлена ​​для экземпляра объекта».<> 4__this._roleManager имеет значение null

Я не уверен, почему это происходит и почему он не помещает данные в таблицу. Как это исправить?Ниже мой код

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();
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 08 марта 2019

Хорошо, ребята, я понял это, вот мое решение.

Я в основном изменил класс для заполнения данных и переименовал его в 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 });
            }
        }

    }
}}

, затем я вызвал функциюв моем файле Program.cs, предложенном @Chris Pratt.

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>();
} }

, спасибо всем, кто пытался мне помочь

0 голосов
/ 04 марта 2019

Вы используете асинхронный метод для заполнения своих ролей, но не ожидаете его.Это означает, что ваш код продолжает двигаться, в конечном итоге принимая переменные, от которых вы зависите, в асинхронном методе вместе с ним, когда ветви выходят из области видимости.Следовательно, NullReferenceException s.

Кроме того, такие сервисы, как 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 для запуска вашего приложения, которая затем даст вам возможность ожидать дополнительные вещи, такие как ваше семя.Для чего это стоит, это может быть несколько сокращено в C # 7.2 с фактическим асинхронным Main, то есть:

public static async Task Main(string[] args)

Без необходимости прокси от Main до MainAsync,но под капотом компилятор просто настраивает эту же конструкцию для вас.

Это кратчайший путь, чтобы этот код работал, но у вас все еще есть пара незначительных проблем.Во-первых, вам следует избегать использования async void, который является антипаттерном.По сути, вы глотаете асинхронный вывод, включая любые исключения, которые могут быть выброшены.Практически всегда следует использовать async Task в качестве возврата, если вы не заботитесь о фактической прибыли.Те немногие ситуации, когда async void подходит, известны лицам, которым необходимо его использовать.Другими словами, если вы не знаете, когда следует использовать async void, то вам не следует использовать async void.

Кроме того, хотя нет ничего технически неправильного в обновлении класса и передачезависимости в конструктор, в этом случае более уместно сделать класс статическим и передать необходимые зависимости в метод seed:

await UserRoleSeed.Seed(roleManager);

Наконец, опять же, хотя это и не критично, принято называть асинхронные методы с помощьюсуффикс Async.Это проясняет, что метод является асинхронным, и предотвращает случайное ожидание метода просто потому, что не очевидно, что его нужно ожидать (что могло иметь место здесь).Короче говоря, измените имя с Seed на SeedAsync, поскольку он работает асинхронно.

...