无法用数据播种数据库

时间:2019-08-06 11:01:57

标签: asp.net-core-mvc

我写了一个类来为数据库添加数据。调试时,它会堆叠在等待状态IdentitySeedData.EnsurePopulated(service);问题可能出在usermanager.createasync()上。看看:

namespace SportStore1
{
public class Program
{
    public static void Main(string[] args)
    {
        var Host = BuildWebHost(args);
        var Scopes = Host.Services.GetRequiredService<IServiceScopeFactory>();
        using (var scope = Scopes.CreateScope())
        {
            var service = scope.ServiceProvider;
            SeedDataFunc(service);
            SeedIdentityDataFunc(service);
        }
        Host.Run();
    }

    public static void SeedDataFunc(IServiceProvider service)
    {
        SeedData.EnsurePopulated(service);
    }

    public static async void SeedIdentityDataFunc(IServiceProvider service)
    {
        await IdentitySeedData.EnsurePopulated(service);
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();

    /*
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

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

namespace SportStore1.Data
{
  public static class IdentitySeedData
  {
    public static async Task EnsurePopulated(IServiceProvider service)
    {
        UserManager<IdentityUser> userManager = service.GetRequiredService<UserManager<IdentityUser>>();
        IConfiguration configuration = service.GetRequiredService<IConfiguration>();
        ApplicationDbContext dbContext = service.GetRequiredService<ApplicationDbContext>();

        if (!dbContext.Roles.Any())
        {
            foreach (var role in Roles)
            {
                dbContext.Add(role);
                await dbContext.SaveChangesAsync();
            }
        }

        if (!dbContext.Users.Any())
        {
            var user = new IdentityUser() { UserName = configuration["Email"], Email = configuration["Email"], EmailConfirmed = true };
            await userManager.CreateAsync(user, configuration["Password"]);
        }

        if (!dbContext.UserRoles.Any())
        {
            var roleID = dbContext.Roles.Where(p => p.Name == "Administrator").FirstOrDefault().Id;
            var userID = dbContext.Users.Where(p => p.Email == configuration["Email"]).FirstOrDefault().Id;

            var userRole = new IdentityUserRole<string>()
            {
                RoleId = roleID,
                UserId = userID
            };

            dbContext.UserRoles.Add(userRole);
            await dbContext.SaveChangesAsync();
        }
    }

    private static List<IdentityRole> Roles = new List<IdentityRole>()
    {
         new IdentityRole { Name = "Administrator", NormalizedName = "Administrator", ConcurrencyStamp = Guid.NewGuid().ToString() },
         new IdentityRole { Name = "Manager", NormalizedName = "Manager", ConcurrencyStamp = Guid.NewGuid().ToString() },
         new IdentityRole { Name = "User", NormalizedName = "User", ConcurrencyStamp = Guid.NewGuid().ToString()}
    };
  }
 }

它在等待IdentitySEedData.EnsurePopulated(service)时堆叠,并显示消息System.ObjectDisposedException:'无法访问已处置的对象。 对象名称:“ UserManager`1”。有解决办法吗?

2 个答案:

答案 0 :(得分:0)

您需要等待异步方法。看来Main是同步的,但是您可以更改它。在C#7.2+中,您实际上只能拥有一个异步main:

public static async Task Main(string[] args)

在较小的版本中,您只需这样做:

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

public static async Task MainAsync(string[] args)
{
    ...
}

无论如何,当您使用异步Main时,编译器只是在幕后为您构建。请记住,如果要这样做,您还需要做await host.RunAsync();

也就是说,这不再是数据库播种的方法。参见documentation

答案 1 :(得分:0)

您还需要使用using()语句来确保dbcontext一旦超出范围就被处置。

我在使用ApplicationUser的全新asp.net core 2.0个人用户帐户中尝试了您的代码,并且在使用using块后效果很好:

public static class IdentitySeedData
{
    public static async Task EnsurePopulated(IServiceProvider service)
    {
        UserManager<ApplicationUser> userManager = service.GetRequiredService<UserManager<ApplicationUser>>();
        IConfiguration configuration = service.GetRequiredService<IConfiguration>();

        using (var dbContext = service.GetRequiredService<ApplicationDbContext>())
        {

            //ApplicationDbContext dbContext = service.GetRequiredService<ApplicationDbContext>();

            if (!dbContext.Roles.Any())
            {
                foreach (var role in Roles)
                {
                    dbContext.Add(role);
                    await dbContext.SaveChangesAsync();
                }
            }

            if (!dbContext.Users.Any())
            {
                var user = new ApplicationUser() { UserName = configuration["Email"], Email = configuration["Email"], EmailConfirmed = true };
                await userManager.CreateAsync(user, configuration["Password"]);
            }

            if (!dbContext.UserRoles.Any())
            {
                var roleID = dbContext.Roles.Where(p => p.Name == "Administrator").FirstOrDefault().Id;
                var userID = dbContext.Users.Where(p => p.Email == configuration["Email"]).FirstOrDefault().Id;

                var userRole = new IdentityUserRole<string>()
                {
                    RoleId = roleID,
                    UserId = userID
                };

                dbContext.UserRoles.Add(userRole);
                await dbContext.SaveChangesAsync();
            }
        }
    }

    private static List<IdentityRole> Roles = new List<IdentityRole>()
    {
         new IdentityRole { Name = "Administrator", NormalizedName = "Administrator", ConcurrencyStamp = Guid.NewGuid().ToString() },
         new IdentityRole { Name = "Manager", NormalizedName = "Manager", ConcurrencyStamp = Guid.NewGuid().ToString() },
         new IdentityRole { Name = "User", NormalizedName = "User", ConcurrencyStamp = Guid.NewGuid().ToString()}
    };
}

启动:

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

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


        services.AddTransient<IEmailSender, EmailSender>();

        services.AddMvc();
    }

请参阅Cannot access a disposed object in ASP.NET Core when injecting DbContext