Create minimal APIs using ASP.NET Core 6 and Visual Studio 2022

One of the features of ASP.NET Core 6 that has got much attention is minimal APIs. You can now create API endpoints without creating a controller and routing related configuration. I have already discussed creation of minimal APIs in a few articles published earlier. The earlier articles were published during the Preview days of ASP.NET Core 6 and use Visual Studio 2019. Now that the final versions of ASP.NET Core 6 and Visual Studio 2022 are available, it's time to revisit the subject and look into various aspects of minimal APIs in more details. To that end this multipart article series is going to discuss just that.

To begin with, we will create Employees CRUD endpoints using minimal APIs and Visual Studio 2022 API project template.

Open Visual Studio 2022 and click on the Create a new project option on the startup window.

Then pick the Web API project template as shown below:

This template allows you to create controller-based APIs or minimal APIs. Once you click on the Next dialog you will be shown this project configuration dialog:

Enter the project name as MinimalAPI, pick some project location and click on the Next button.

Now you can specify some additional information as shown below:

Look at the checkbox that says Use controller. By default this checkbox is selected indicating that the project will use controller-based APIs. If you uncheck this checkbox (as I have done in this case) the project uses minimal APIs. Uncheck this checkbox since we want to play with minimal APIs in this article. Keep other settings to their default values and hit Create.

The following figure shows the default project loaded in the Solution Explorer.

As you can see, there is no API controller since we unchecked that option during project creation. The Program.cs will contains startup and minimal API code.

Next, open Program.cs and delete all the code from it. We will write everything needed for our CRUD APIs in step-by-step manner. We will also store global usings in GlobalUsings.cs file. So, add a new C# class file named GlobalUsings.cs.

Now add the ConnectionStrings section to the appsettings.json file.

"ConnectionStrings": {
    "AppDb": "data source=.;initial catalog=Northwind;
              integrated security=true"

Here, we stored a connection string for the Northwind database with key name AppDb.

Then add the following code in the empty Program.cs file.

var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.

This code creates a WebApplicationBuilder using the CreateBuilder() method. It also reads the database connection string from the appsettings.json file and stores it in a local variable. This is done using the Configuration property of the WebApplicationBuilder and GetConnectionString() method.

Our Employees minimal API requires Employee entity class and a custom DbContext class named AppDbContext. We will add these classes in Program.cs file itself (you could have placed them in separate files) as shown below:

public class Employee
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

public class AppDbContext : DbContext
    public AppDbContext(DbContextOptions<AppDbContext> 
options) : base(options)
    public DbSet<Employee> Employees { get; set; }

The Employee class contains three properties namely EmployeeID, FirstName, and LastName.

The AppDbContext class inherits from DbContext class and contains Employees DbSet.

Now register the AppDbContext with DI container by adding this line below the GetConnectionString() call.

(o => o.UseSqlServer(connectionString));

The AddDbContext() registers a custom DbContext with the DI container and also specifies the connection string using the UseSqlServer() extension method. You may need to add this namespaces in the GlobalUsings.cs file:

global using Microsoft.EntityFrameworkCore;

Now we can build the WebApplication object as shown below:

var app = builder.Build();
if (app.Environment.IsDevelopment())

The Build() method creates a WebApplication instance. We also wire developer exception page middleware and HTTPS redirection middleware using the UseDeveloperExceptionPage() and UseHttpsRedirection() methods.

Now let's define the CRUD endpoints using various "Map" methods as shown below.

(AppDbContext db) =>
    return Results.Ok(db.Employees.ToList());

(AppDbContext db, int id) =>
    return Results.Ok(db.Employees.Find(id));

(AppDbContext db, Employee emp) =>
    return Results.Created($"/minimalapi/employees/
{emp.EmployeeID}", emp);

(AppDbContext db, int id, Employee emp) =>
    return Results.NoContent();

(AppDbContext db, int id) =>
    var emp = db.Employees.Find(id);
    return Results.NoContent();

The first MapGet() call handles GET requests made  at /minimalapi/employees. The handler function receives the AppDbContext parameter through DI automatically. Inside, we simply return a List of all the Employee entities to the caller after wrapping the data in Results.Ok() method. The Ok() method sets the HTTP status code to 200.

The second MapGet() call handles GET requests that also carry an EmployeeID in the route's id parameter. The handler method takes two parameters - AppDbContext and id. Inside, we find an Employee matching the id parameter, wrap it in Ok() and return it to the caller.

The MapPost() call handles POST requests made at /minimalapi/employees. The handler function takes two parameters viz. AppDbContext and Employee object. Note that AppDbContext is supplied by DI and Employee is constructed from request's body. Inside, we add the Employee to the Employees DbSet and persist it to the database by calling SaveChanges(). The Created() method sets the HTTP status code to 201 and also indicates the URL at which the newly added resource (Employee) will be avaulable.

The MapPut() call handles PUT requests made at /minimalapi/employees/{id}. The hander function receives AppDbContext and it as before. Inside, we update an existing Employee using the Update() method and SaveChanges() method. We return HTTP status code 204 using NoContent() method.

Finally, the MapDelete() call handles DELETE requests made at /minimalapi/employees/{id}. The handler function finds an Employee matching the EmployeeID, removes it from Employees DbSet using Remove() method, and then deletes the Employee from the database using SaveChanges() method. This time also we return HTTP status code 204 using NoContent() method.

Now that all minimal API endpoints have been defined, let's run the application by calling:


To test the endpoints, run the application from Visual Studio by pressing F5. Once the browser opens, go to the address bar and navigate to /minimalapi/employees. 

As you can see, a list of all the employees is displayed as expected.

Now enter this URL - /minimalapi/employees/1.

This time only one Employee is returned to the client.

We can test only the GET verbs from the browser's address bar. It would be better if we can test all the APIs before using them in a client app. In the next part of this multipart article series, we will integrate Swagger with our minimal APIs. Swagger allows you to easily invoke the API endpoints from the browser without creating a client application.

That's it for now! Keep coding!!

Bipin Joshi is an independent software consultant and trainer by profession specializing in Microsoft web development technologies. Having embraced the Yoga way of life he is also a meditation teacher and spiritual guide to his students. He is a prolific author and writes regularly about software development and yoga on his websites. He is programming, meditating, writing, and teaching for over 27 years. To know more about his ASP.NET online courses go here. More details about his Kriya and Meditation online course are available here.

Posted On : 25 November 2021

Tags : ASP.NET ASP.NET Core Web Services .NET Framework C# Visual Studio