Table of Contents
Just like MVC 5, I was trying to enable automatic migrations and Seeding default data, but it seems the behaviour has been changed in MVC 6, so I thought I'll share the tip.
Here, we'll try to learn Seeding data in MVC 6 ASP.NET Core 2.2 application. Here, mainly Seeding data only is part of our scope.
Using Visual Studio 2019, I created a .NET Core 2.2 web application using the default template. Now my requirement is to seed some default data when the database is being created with Entity framework migrations.
For that purpose, we'll create a class DbInitializer.cs in the project and call its Initialize
function from Startup.cs class.
Create your Web Application in Visual Studio 2019:
Select the Language as C# and Project type as Web, then select the first template, ASP.NET Core Web Application and click Next.
Here is how my appsettings.json looks like:
I'll be using the localhost as my server with Windows authentication.
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=Mvc.SeedingData;
Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
Provide a project name and select the physical path and then click on Create. It'll create the project, then we'll add a new entity Terminal in the new project.
public class Terminal
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
}
Here is what my DbContext
class looks like:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Terminal> Terminal { get; set; }
}
Now, we need to delete everything from the Migrations folder because we have added a new entity in the DbContext
class that should be created in the database when we run the migrations and seed data.
Now, we need to run Add-migration
command and give some name to the migration.
Note: Enable-migrations
command is obsolete.
Now, we can run Update-database
command to create the database using our code first model. Now our database will be in place but there won't be any data in the tables as of now.
Now I've added a new class DbInitializer.cs in my project that we can call for seeding default values in the database through ApplicationDbContext
.
I've added default admin role and a user so when we start the application, we can login.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Mvc.SeedingData.Data;
using System;
using System.Linq;
namespace Mvc.SeedingData
{
public static class DbInitializer
{
public static void Initialize(IApplicationBuilder app)
{
using (var serviceScope = app.ApplicationServices.CreateScope())
{
var context = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
context.Database.EnsureCreated();
var _userManager =
serviceScope.ServiceProvider.GetService<UserManager<IdentityUser>>();
var _roleManager =
serviceScope.ServiceProvider.GetService<RoleManager<IdentityRole>>();
if (!context.Users.Any(usr => usr.UserName == "demo@test.com"))
{
var user = new IdentityUser()
{
UserName = "demo@test.com",
Email = "demo@test.com",
EmailConfirmed = true,
};
var userResult = _userManager.CreateAsync(user, "P@ssw0rd").Result;
}
if (!_roleManager.RoleExistsAsync("Admin").Result)
{
var role = _roleManager.CreateAsync
(new IdentityRole { Name = "Admin" }).Result;
}
var adminUser = _userManager.FindByNameAsync("demo@test.com").Result;
var userRole = _userManager.AddToRolesAsync
(adminUser, new string[] { "Admin" }).Result;
var terminal = context.Terminal
.Where(x => x.Name == "Test").FirstOrDefault();
if (terminal == null)
{
terminal = new Terminal()
{
Name = "Test",
CreatedDate = DateTime.Now,
};
context.Terminal.Add(terminal);
}
context.SaveChanges();
}
}
}
}
I want to run the DbInitializer
in case of Development mode only from the Startup.cs class. We need to add IdentityUser
and IdentityRole
into services as well.
public void ConfigureServices(IServiceCollection services)
{
..........
services.AddDefaultIdentity<IdentityUser>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequiredLength = 6;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
})
.AddRoles<IdentityRole>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
DbInitializer.Initialize(app);
}
..........................
}
Now when we'll start our project under Development mode, it'll call Initialize
method of DbInitializer class
and insert data into the database tables.
We have achieved our goal of seeding default data into our database when we create our database through migrations and started our project under Development environment. We tried to limit ourselves only to the defined scope of seeding default data. All of you people are most welcome if you've any questions, Thanks for reading....
- 28th July, 2019: Initial version
- 14th August, 2019: Improved the content and added source code for downloading