Monday, October 5, 2026

ASP.NET 10.0 Minimal WebAPI with SQLite

This tutorial is about using ASP.NET 10.0 Minimal WebAPI. We will build a simple application that uses SQLite to save students data. We will then consume the API from an HTML page. 

Requirements:

  • .NET 10.0
  • C# Dev Kit VS Code Extenstion

In a suitable working directory, create a Web API web application in the terminal window with:

dotnet new webapi -o StudentsMinApi 
cd StudentsMinApi
mkdir Data
mkdir Models
mkdir wwwroot code . dotnet watch

This will appear in your terminal window:

Point your browser to the URL displayed in the terminal window, followed by /weatherforecast.

In the above case the address would be http://localhost:5130/weatherforecast. This would display the following in your browser:

Look at API code in Program.cs:

app.MapGet("/weatherforecast", () => {
    var forecast =  Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast");

Add this tool if you do not already have it: 

dotnet tool install --global dotnet-ef 

Let us add these packages that provide support for SQLite and reading a CSV file: 

dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SQLite
dotnet add package Microsoft.EntityFrameworkCore.SQLite.Design
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Swashbuckle.AspNetCore

Inside the Models folder, add the following Student class: 

public class Student {
    public int StudentId { get; set; }
    public string? LastName { get; set; }
    public string? FirstName { get; set; }
    public string? School { get; set; }
    public string? Gender { get; set; }
    public DateTime? DateOfBirth { get; set; }
}

Developers prefer having sample data when building data driven applications. Therefore, we will create some sample data to ensure that our application behaves as expected. Copy the following data from https://gist.github.com/medhatelmasry/2ae7a36d5392f862b0d1039b2a52b9b4 and save it in a text file wwwroot/students.csv.

Add the following connection string to appsettings.json:

"ConnectionStrings": {
  "DefaultConnection": "DataSource=school.db;cache=shared;"
},

Next, we need to add an Entity Framework context class. Inside the Data folder, add a class file named ApplicationDbContext with the following content: 

public class ApplicationDbContext : IdentityDbContext<IdentityUser> {

    public DbSet<tudent> Students => Set<Student>();

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

    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Student>().HasData(GetStudents());
    }

    private static IEnumerable<Student> GetStudents() {
        string[] p = { Directory.GetCurrentDirectory(), "wwwroot", "students.json" };
        var csvFilePath = Path.Combine(p);

        var json = File.ReadAllText(csvFilePath);
        var data = System.Text.Json.JsonSerializer.Deserialize<List<Student>>(json) ?? new List<Student>();

        return data;
    }

}

In the above code, student data is being seeded in the OnModelCreating() method by reading contents of students.json file.

We need to register the context class (ApplicationDbContext) with dependency injection in Program.cs. Add the following code right before “var app = builder.Build();” in Program.cs: 

var connStr = builder.Configuration.GetConnectionString("DefaultConnection")
    ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");

builder.Services.AddDbContext<ApplicationDbContext>(option => option.UseSqlite(connStr));

Let us add a migration and subsequently update the database. Execute the following CLI commands in a terminal window:

dotnet ef migrations add M1 -o Data/Migrations
dotnet ef database update

At this point the database and tables are created.

Students API

Let us add API endpoints that:

  • Read all the students
  • Read students that belong to a particular school
  • Read student data by id
  • Add student data
  • Update student data
  • Delete student data

This can easily be done using the scaffold tool. Make sure you install the tool with this terminal window command:

dotnet tool install --global Microsoft.dotnet-scaffold

Once you have installed the scaffold tool, enter the following command to start the tool at the root of your project:

dotnet scaffold

Make the choices as shown in the various images below:

 

A file named StudentsApi.cs gets created in the root folder of your project with this code:

using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.EntityFrameworkCore;
using StudentsMinApi.Data;
using StudentsMinApi.Models;

public static class StudentsApi {
    public static void MapStudentEndpoints(this IEndpointRouteBuilder routes) {
        var group = routes.MapGroup("/api/Student").WithTags(nameof(Student));

        group.MapGet("/", async (ApplicationDbContext db) => {
            return await db.Students.ToListAsync();
        })
        .WithName("GetAllStudents");

        group.MapGet("/{id}", async Task<Results<Ok<Student>, NotFound>> (int studentid, ApplicationDbContext db) => {
            return await db.Students.AsNoTracking()
                .FirstOrDefaultAsync(model => model.StudentId == studentid)
                is Student model
                    ? TypedResults.Ok(model)
                    : TypedResults.NotFound();
        })
        .WithName("GetStudentById");

        group.MapPut("/{id}", async Task<Results<Ok, NotFound>> (int studentid, Student student, ApplicationDbContext db) => {
            var affected = await db.Students
                .Where(model => model.StudentId == studentid)
                .ExecuteUpdateAsync(setters => setters
                .SetProperty(m => m.StudentId, student.StudentId)
                .SetProperty(m => m.LastName, student.LastName)
                .SetProperty(m => m.FirstName, student.FirstName)
                .SetProperty(m => m.School, student.School)
                .SetProperty(m => m.Gender, student.Gender)
                .SetProperty(m => m.DateOfBirth, student.DateOfBirth)
        );

            return affected == 1 ? TypedResults.Ok() : TypedResults.NotFound();
        })
        .WithName("UpdateStudent");

        group.MapPost("/", async (Student student, ApplicationDbContext db) => {
            db.Students.Add(student);
            await db.SaveChangesAsync();
            return TypedResults.Created($"/api/Student/{student.StudentId}",student);
        })
        .WithName("CreateStudent");

        group.MapDelete("/{id}", async Task<Results<Ok, NotFound>> (int studentid, ApplicationDbContext db) => {
            var affected = await db.Students
                .Where(model => model.StudentId == studentid)
                .ExecuteDeleteAsync();

            return affected == 1 ? TypedResults.Ok() : TypedResults.NotFound();
        })
        .WithName("DeleteStudent");
    }
}

Note the following mapping code in your Program.cs file:

app.MapStudentEndpoints();

You can start the WebAPI app and view all students at endpoint: /api/student.

OPTIONAL: If you want migrations to be applied automatically, add the following code to Program.cs right before the last “app.Run()” statement

using (var scope = app.Services.CreateScope()) {
    var services = scope.ServiceProvider;

    var context = services.GetRequiredService<ApplicationDbContext>();    
    context.Database.Migrate();
}

Adding Swagger Support

It is very easy to add Swagger support to our application so that we can easily test the various endpoint that our WebAPI application has to offer. 

Add the following code right under app.MapOpenApi():

app.UseSwaggerUI(options =>
{
        options.SwaggerEndpoint("/openapi/v1.json", "My WebAPI");
});

In file Properties/launchSettings.json, set the value of launchBrowser to true in two places:

"launchBrowser": true

Also, add the following property to both the http and https blocks:

"launchUrl": "swagger"

Restart the app by typing dotnet watch in the terminal window. The app will automatically load into your default browser in a Swagger interfact that looks like this:

Go ahead and test all the available student endpoints.

CORS (Cross-Origin Resource Sharing)

In wwwroot folder, create a file named show.html and add to it this HTML/JavaScript code:

<!DOCTYPE html>
<html>
  <html>
    <head>
      <meta charset="utf-8" />
      <title>Test API</title>
    </head>
    <body>
      <h3>Test API</h3>
      <button id="btnGetData">Get Data</button>
      <pre id="preOutput"></pre>
      <script>
        const url = "PUT-API-URL-HERE";

        var showResponse = function (object) {
          document.querySelector("#preOutput").innerHTML = JSON.stringify(
            object,
            null,
            4
          );
        };

        const button = document.querySelector("#btnGetData");
        button.addEventListener("click", (e) => {
          getData();
        });

        var getData = async function () {
          await fetch(url)
            .then((response) => {
              return response.json();
            })
            .then((data) => {
              showResponse(data);
            });

          return false;
        };
      </script>
    </body>
  </html>
</html>

Replace PUT-API-URL-HERE with the URL that gets all the students (Example: http://localhost:5130/api/students). 

From the file system, double-click on the wwwroot/show.html file. You will see the following page:


When you click on the “Get Data” button, nothing will appear because there is a JavaScript error. To understand where this error is coming from, hit F12 in your browser and check the console. This error will appear:

We need to enable CORS on the API project. This is done by adding the following code in Program.cs just before “var app = builder.Build();”:
 
// Add Cors
builder.Services.AddCors(o => o.AddPolicy("Policy", builder => {
  builder.AllowAnyOrigin()
    .AllowAnyMethod()
    .AllowAnyHeader();
}));

Also, in the same Program.cs file, add this code just after “var app = builder.Build();”: 

app.UseCors("Policy");

Save your code then make a new request for data from show.html. This time you should be successful:


The application should work as expected.

Congrats for coming this far.

No comments:

Post a Comment