How to use an in-memory database for quick project setup for dev environments in .NET
To quickly start working on a project on a new computer, I have started using a database completely defined in code. This way, it's just a matter of checking out the code and hitting dotnet run to start the application, no external resources needed.
Published:
I'm working on an application where I cannot access the database servers used in the test and production environments from my local machine. That means that for each dev machine I set up, I have to create a local SQLExpress server or similar.
This is cumbersome, so instead I have set up a small in-memory database only for the development environment using Entity Framework Core.
Compare the dev setup with the test and production environments in the diagram below.
Follow along to learn how!
There are two steps to the process, both added to Program.cs for initialization on application startup:
Add the database context to the WebApplicationBuilder
Add some initial test data to the database in the startup of the WebApplication
Add an in-memory database
I prefer to add services to the app's WebApplicationBuilder with an extension method, to keep Program.cs short and readable.
This extension method adds the database context with the in-memory database to the application:
public static class InMemoryDatabaseContextSetup
{
public static IServiceCollection AddInMemoryDatabases(
this IServiceCollection services)
{
services.AddDbContext<DefaultDbContext>(
options => options
.UseInMemoryDatabase("DefaultConnection"));
return services;
}
}
For reference, this is my method for adding my live SQL database to the application, not very different. The connection string is defined in appsettings.json.
public static IServiceCollection AddDatabases(
this IServiceCollection services,
IConfiguration configuration)
{
services.AddDbContext<DefaultDbContext>(
options => options
.UseSqlServer(configuration
.GetConnectionString("DefaultConnection")));
return services;
}
The DefaultDbContext and PhoneDataModel classes look like this, and because I use the same context class, my mock database and real database will have identical table schemas.
public class DefaultDbContext(
DbContextOptions<DefaultDbContext> options)
: DbContext(options)
{
public DbSet<PhoneDataModel> Phones { get; set; }
}
public class PhoneDataModel
{
[Key]
[Required]
[MaxLength(450)]
public string PhoneNumber { get; set; }
}
Add mock data to the in-memory database
To run my application, I don't require a lot of data in the database, just a couple of phone numbers.
If your application needs a lot of data in the database, be aware that it might be more work to keep the hardcoded data you feed into the in-memory database updated than to just have a normal database on your development machine.
public static class InMemoryDatabaseMockContentSetup
{
public static void AddInMemoryDatabaseMockContent(
this WebApplication app)
{
var mockDatabaseScope = app.Services.CreateScope();
var context = mockDatabaseScope
.ServiceProvider
.GetRequiredService<DefaultDbContext>();
var phone = new PhoneDataModel
{
PhoneNumber = "22334455"
};
context.Add(phone);
context.SaveChanges();
}
}
Remember, any changes to the in-memory database are lost as soon as the application stops. This is purely for development purposes.
Connect it all together in Program.cs
In Program.cs I check if we are in the Development environment and then add the in-memory database and add the mock data to it.
var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsDevelopment())
{
// Add in-memory database
builder.Services.AddInMemoryDatabases();
}
else
{
// Add test/production database using connectionstrings in appsettings.json
builder.Services.AddDatabases(builder.Configuration);
}
var app = builder.Build();
var env = app.Environment;
// Add content to mock database
if (env.IsDevelopment())
{
app.AddInMemoryDatabaseContent();
}
Happy coding!