4.3: Seeding the Database

The next step is to get the data in our database.

Add Newtonsoft.Json package

By manually adding it to your EFConnect.Data.csproj file, using the command prompt, or by using the NuGet package manager console, add a reference to Newtonsoft.Json to your .Data project.

<ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.2" />
    <PackageReference Include="Newtonsoft.Json" Version="11.0.1"/>
</ItemGroup>

Add Seed Class

In your .Data project, add a new class called Seed.cs.

We won't be using our Service to add users here - so, we'll also be borrowing the CreatePasswordSalt() method from our AuthService.

public class Seed
{
    private readonly EFConnectContext _context;
    public Seed(EFConnectContext context)
    {
        _context = context;
    }

    public void SeedUsers()
    {

        if (_context.Users.Any())                   // check if users are in the databaes
        {
            _context.Users.RemoveRange(_context.Users);         // if so, remove them
            _context.SaveChanges();
        }

        var userData = System.IO.File.ReadAllText("../EFConnect.Data/UserSeedData.json");    // read json
        var users = JsonConvert.DeserializeObject<List<User>>(userData);        // deserialize to a list of Users

        foreach (var user in users)
        {
            byte[] passwordHash, passwordSalt;
            CreatePasswordHash("password", out passwordHash, out passwordSalt);

            user.PasswordHash = passwordHash;
            user.PasswordSalt = passwordSalt;
            user.Username = user.Username.ToLower();
            user.LastActive = user.Created;

            _context.Users.Add(user);
        }

        _context.SaveChanges();
    }

    private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
    {
        using (var hmac = new System.Security.Cryptography.HMACSHA512())
        {
            passwordSalt = hmac.Key;
            passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
        }
    }
}

Register the Seed Class in Our Services

In the Startup.cs file in your .API project, register the Seed class as transient:

//  ...
services.AddTransient<Seed>();              //  <---- Added
services.AddMvc();
services.AddScoped<IAuthService, AuthService>();
//  ...

Remember what transient was? This will create a new instance of our Seed class only once - in this case when the project starts. This is just to ensure our data stays the same while developing. If we want to get our users back to the original state we can reseed the database - we'll also wipe out test data and go back to the original state.

Add Seeding to the Middleware Pipeline

First, add it as a parameter to the Configure() method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, Seed seeder)

Then, call it in the pipeline:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
seeder.SeedUsers();                 // <---- Added
app.UseCors(x => x.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials());
app.UseAuthentication();
app.UseMvc();

Run the Project and Seed the Data

Now, when we run the application, the our database will be seeded with our data!

Open up your terminal, navigate to the root of the .API project and run it:

dotnet watch run

Check the Database

Open up SQL Server Management Studio and verify that the data was added.

DatabaseSeeded

Looks good! We've got a big list of users to work with now.

You can comment out the seeder.SeedUsers() method in your middleware so it doesn't run every time you start the project up.

//  seeder.SeedUsers();

Last updated