-
-
Save mombrea/9a49716841254ab1d2dabd49144ec092 to your computer and use it in GitHub Desktop.
using Microsoft.AspNetCore.Identity; | |
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; | |
using System.Linq; | |
namespace My.App.Data | |
{ | |
public class DbInitializer : IDbInitializer | |
{ | |
private readonly ApplicationDbContext _context; | |
private readonly UserManager<ApplicationUser> _userManager; | |
private readonly RoleManager<IdentityRole> _roleManager; | |
public DbInitializer( | |
ApplicationDbContext context, | |
UserManager<ApplicationUser> userManager, | |
RoleManager<IdentityRole> roleManager) | |
{ | |
_context = context; | |
_userManager = userManager; | |
_roleManager = roleManager; | |
} | |
//This example just creates an Administrator role and one Admin users | |
public async void Initialize() | |
{ | |
//create database schema if none exists | |
_context.Database.EnsureCreated(); | |
//If there is already an Administrator role, abort | |
if (_context.Roles.Any(r => r.Name == "Administrator")) return; | |
//Create the Administartor Role | |
await _roleManager.CreateAsync(new IdentityRole("Administrator")); | |
//Create the default Admin account and apply the Administrator role | |
string user = "[email protected]"; | |
string password = "z0mgchangethis"; | |
await _userManager.CreateAsync(new ApplicationUser { UserName = user, Email = user, EmailConfirmed = true}, password); | |
await _userManager.AddToRoleAsync(await _userManager.FindByNameAsync(user), "Administrator"); | |
} | |
} | |
} |
namespace My.App.Data | |
{ | |
public interface IDbInitializer | |
{ | |
void Initialize(); | |
} | |
} |
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; | |
using Microsoft.EntityFrameworkCore; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Logging; | |
using My.App.Data; | |
namespace My.App.Admin | |
{ | |
public class Startup | |
{ | |
public Startup(IHostingEnvironment env) | |
{ | |
var builder = new ConfigurationBuilder() | |
.SetBasePath(env.ContentRootPath) | |
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) | |
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); | |
if (env.IsDevelopment()) | |
{ | |
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 | |
builder.AddUserSecrets<Startup>(); | |
} | |
builder.AddEnvironmentVariables(); | |
Configuration = builder.Build(); | |
} | |
public IConfigurationRoot Configuration { get; } | |
// This method gets called by the runtime. Use this method to add services to the container. | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
// Add framework services. | |
services.AddDbContext<ApplicationDbContext>(options => | |
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); | |
services.AddIdentity<ApplicationUser, IdentityRole>() | |
.AddEntityFrameworkStores<ApplicationDbContext>() | |
.AddDefaultTokenProviders(); | |
services.AddMvc(); | |
// Add Database Initializer | |
services.AddScoped<IDbInitializer, DbInitializer>(); | |
// Add application services. | |
services.AddTransient<IEmailSender, AuthMessageSender>(); | |
services.AddTransient<ISmsSender, AuthMessageSender>(); | |
} | |
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IDbInitializer dbInitializer) | |
{ | |
loggerFactory.AddConsole(Configuration.GetSection("Logging")); | |
loggerFactory.AddDebug(); | |
if (env.IsDevelopment()) | |
{ | |
app.UseDeveloperExceptionPage(); | |
app.UseDatabaseErrorPage(); | |
// Browser Link is not compatible with Kestrel 1.1.0 | |
// For details on enabling Browser Link, see https://go.microsoft.com/fwlink/?linkid=840936 | |
// app.UseBrowserLink(); | |
} | |
else | |
{ | |
app.UseExceptionHandler("/Home/Error"); | |
} | |
app.UseStaticFiles(); | |
app.UseIdentity(); | |
//Generate EF Core Seed Data | |
dbInitializer.Initialize(); | |
// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715 | |
app.UseMvc(routes => | |
{ | |
routes.MapRoute( | |
name: "default", | |
template: "{controller=Home}/{action=Index}/{id?}"); | |
}); | |
} | |
} | |
} |
@grumson
Check this:
aspnet/Identity#1065
@ych-szh You are amazing. Thank you! What exactly does using this scope achieve?
I was also having issues with System.ObjectDisposedException: 'Cannot access a disposed object.'
and eventually went with a new approach that uses an IWebHost
extension off of ASP.Net Core 2.x.
I get rid of System.ObjectDisposedException: 'Cannot access a disposed object.'
when I change this:
_context.Database.EnsureCreated();
await _roleManager.CreateAsync(new IdentityRole("Administrator"));
await _userManager.CreateAsync(new ApplicationUser { UserName = user, Email = user, EmailConfirmed = true}, password);
to this:
_context.Database.Migrate();
_roleManager.CreateAsync(new IdentityRole("Administrator")).GetAwaiter().GetResult();
_userManager.CreateAsync(new ApplicationUser { UserName = user, Email = user, EmailConfirmed = true }, password).GetAwaiter().GetResult();
In DoTNet Core 2.0 when I try and run this I get an error on the user creation that says "Value cannot be Null". I am guessing the last line of the initializer:
await _userManager.AddToRoleAsync(await _userManager.FindByNameAsync(user), "Administrator");
has a problem finding the user, but I cannot figure out why. Any ideas?
@daveinyyc can you post rest of your code?
It was because the password listed in this code is not complex enough @ibro, DotNet 2.0 adds some password complexity requirements obviously. Now I have fixed that and the user is creating, but i am getting the dispose error the other commentators mentioned. going to try the GetAwaiter().GetResult() statements like @Planche95 mentions in his comment
The example works if you change the interface to return type Task instead of type void.
namespace My.App.Data { public interface IDbInitializer { Task Initialize(); } }
Also use public async Task Initialize()
inside DbInitializer.
Hi!
when I run this code I get:
System.ObjectDisposedException: 'Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.'
On class DbInitializer : IDbInitializer line 38
Can you please help me!