Skip to main content

Seeding data is a crucial step in setting up a database for development and testing. In this blog post, we'll explore how to seed data in an EF Core context using JSON files in a .NET Core 8 Web API project. This approach allows for easy management and modification of seed data, especially when dealing with complex relationships and large datasets.

# Seeding Data in EF Core Using JSON Files in a .NET Core 8 Web API Project

Seeding data is a crucial step in setting up a database for development and testing. In this blog post, we'll explore how to seed data in an EF Core context using JSON files in a .NET Core 8 Web API project. This approach allows for easy management and modification of seed data, especially when dealing with complex relationships and large datasets.

## Step 1: Create a New .NET Core 8 Web API Project

First, let's create a new .NET Core 8 Web API project. Open your terminal and run the following commands:

```bash
dotnet new webapi -n MyWebApi
cd MyWebApi
```

## Step 2: Add EF Core and Configure the Database Context

Next, we need to add the necessary EF Core packages to our project:

```bash
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Design
```

Now, create the `ApplicationDbContext` class to configure our database context:

```csharp
// Data/ApplicationDbContext.cs
using Microsoft.EntityFrameworkCore;

public class ApplicationDbContext : DbContext
{
    public DbSet<User> Users { get; set; }

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
}
```

## Step 3: Create Models and JSON Seed Data Files

Define the `User` model:

```csharp
// Models/User.cs
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}
```

Create a JSON file for seeding data. Place this file in a directory named `SeedData`:

```json
// SeedData/Users.json
[
  {
    "Id": 1,
    "Name": "John Doe",
    "Email": "john.doe@example.com"
  },
  {
    "Id": 2,
    "Name": "Jane Smith",
    "Email": "jane.smith@example.com"
  }
]
```

## Step 4: Implement the Seeding Logic

Create a static class for seeding data:

```csharp
// Data/SeedData.cs
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;

public static class SeedData
{
    public static async Task SeedAsync(ApplicationDbContext context, IWebHostEnvironment env, bool seedData)
    {
        if (!seedData) return;

        // Construct the full path to the JSON file
        var usersFilePath = Path.Combine(env.ContentRootPath, "SeedData", "Users.json");

        // Seed Users
        var users = await ReadJsonFileAsync<List<User>>(usersFilePath);
        if (users != null)
        {
            context.Users.AddRange(users);
        }

        await context.SaveChangesAsync();
    }

    private static async Task<T> ReadJsonFileAsync<T>(string filePath)
    {
        if (!File.Exists(filePath)) return default;

        var json = await File.ReadAllTextAsync(filePath);
        return JsonSerializer.Deserialize<T>(json);
    }
}
```

## Step 5: Configure the Application to Seed Data at Startup

Update `appsettings.json` to include a seed data flag:

```json
// appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "YourConnectionStringHere"
  },
  "SeedData": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}
```

Modify `Program.cs` to configure the database context and seed data at startup:

```csharp
// Program.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Configure DbContext
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

// Seed data at startup
using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;
    var context = services.GetRequiredService<ApplicationDbContext>();
    var configuration = services.GetRequiredService<IConfiguration>();
    var env = services.GetRequiredService<IWebHostEnvironment>();
    var seedData = configuration.GetValue<bool>("SeedData");

    await SeedData.SeedAsync(context, env, seedData);
}

app.Run();
```

## Step 6: Configure the .csproj File to Include JSON Files

To ensure that your project can read JSON files at startup, you need to include these files in your project and ensure they are copied to the output directory. Modify your `.csproj` file as follows:

```xml
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0" />
  </ItemGroup>

  <ItemGroup>
    <!-- Include all JSON files in the SeedData directory -->
    <None Update="SeedData\**\*.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>
```

## Conclusion

By following these steps, you can easily seed your EF Core database with data from JSON files in a .NET Core 8 Web API project. This approach provides a flexible and maintainable way to manage seed data, making it easier to set up your database for development and testing. Using `IWebHostEnvironment` to resolve the path to your JSON files ensures that your application can locate these files regardless of the environment it is running in, making your seeding logic more robust and portable.