-
Book Overview & Buying
-
Table Of Contents
ASP.NET Core 9 Web API Cookbook
By :
Let’s start by creating a basic web API that will serve as the foundation for the rest of the projects in this chapter. We will use SQLite’s in-memory database provider with EF Core, eliminating the need for database files or server connections. The API’s database will be populated with mock data generated by Bogus.
To begin, you will need the following:
dotnet new webapi -o mockAPI -f net9.0 --no-https --auth none
.gitignore file:dotnet new gitignore
dotnet add package Microsoft.EntityFrameworkCore dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Bogus dotnet add package Swashbuckle.AspNetCore.SwaggerUI
Models. Create a file called Product.cs and fill in the following Product class:namespace mockAPI.Models;
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public int CategoryId { get; set; }
}Data. In that folder, create your AppDbContext.cs file. Fill in a AppDbContext class, which will inherit from DbContext:using Microsoft.EntityFrameworkCore;
using mockAPI.Models;
namespace mockAPI.Data;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options):
base(options) { }AppDbContext class, on the next line, define the 'DbSet' property to use your new Products class:public DbSet<Product> Products { get; set; }OnModelCreating method:protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Product>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired();
entity.Property(e => e.Price).HasColumnType(
"decimal(18,2)");
});
}Program.cs file. Delete all the boilerplate code that .NET generated; we are going to start from scratch.Program.cs, import our new Data namespace, as well as the namespace for models and Bogus itself:using mockAPI.Data; using mockAPI.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Data.Sqlite; using Bogus;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();DbContext registration:builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlite(connection));
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<AppDbContext>();
context.Database.EnsureCreated();
}Service lifetime selection
We need to register a scoped service to interact with EF Core’s DbContext. This is counterintuitive; it might seem like a singleton service would be a more appropriate lifetime for working with a database. However, EF Core's DbContext is designed to be short-lived and is not thread-safe for concurrent operations.
if (!context.Products.Any())
{
var productFaker = new Faker<Product>()
.RuleFor(p => p.Name, f => f.Commerce.ProductName())
.RuleFor(p => p.Price, f => f.Finance.Amount(
50,2000))
.RuleFor(p => p.CategoryId, f => f.Random.Int(
1,5));
var products = productFaker.Generate(10000);
context.Products.AddRange(products);
context.SaveChanges();
}
}app.MapGet("/products", async (AppDbContext db) =>
await db.Products.OrderBy(p =>
p.Id).Take(10).ToListAsync());app.MapOpenApi();
if (app.Environment.IsDevelopment())
{
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/openapi/v1.json", "v1");
});
}
app.Run();http://localhost<yourport>/swagger/index.html and click on the Products endpoint to see our fake data generated by Bogus:dotnet run
You registered your AppDbContext with the service provider at startup, which is the standard way to integrate EF Core into ASP.NET Core dependency injection. This allows the database context to be available for your controllers, services, and so on.
You also added a scoped service provider that checks whether your database is empty. The scoped lifetime ensures that a new AppDbContext is created for each request, preventing any data inconsistencies that can plague singleton instances of database connections. If the database is empty, it will be seeded using the Faker<T> class from Bogus.
We also used the SQLite in-memory database provider for EF Core. This allows us to create a database entirely in memory without requiring an external SQLite file. While EF Core also includes an InMemory database provider, it is considered a legacy option and is not recommended for testing. Unlike the InMemory provider, SQLite’s in-memory database supports transactions and raw SQL, making it a closer approximation of a real-world database.