Featured

Minimal APIs in .NET 6

Last modified: February 27, 2022

.NET 6 (aka .NET Core) is the latest version and it is fast. It is the first LTS (Long Term Support) since .NET Core 3.1 and it will be supported for next three years. In this article, we are going to look at what are the Minimal APIs using a real-world example (SQL Server, Entity Framework (EF) Core), add Swagger for OpenAPI Specifications.

Table of Content

  1. Create a Project (windows/PC )
  2. Models
  3. DbContext
  4. APIs
  5. Test the application

What are the Minimal APIs?

It is very simple to write REST APIs without too many dependencies. It is similar to writing APIs in NodesJS with Express.

The following is good enough to write a simple Minimal API in ASP.NET 6. It is only 4 lines of code, no need for API Controller, no Startup.cs, and any other dependencies.

var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run();

Output output

Real World Example

We have some prerequisites before we starting coding the a "Real World Example". Today we are going to take a shop as an example, where there are lots of products and each product has a brand associated with it. We are going to get all the products, get a product by id, add, update, delete a product from the database.

  • Get all products
  • Add a product
  • Update a product
  • Select a product
  • Delete a product

Prerequisites:

  • .NET 6 SDK for your platform (Windows, Mac) click here
  • Visual Studio 2022 as .NET 6 is not supported for VS 2019 click here

Http verbs (CRUD)

  • GET app.MapGet()
  • POST app.MapPost()
  • PUT app.MapPut()
  • DELETE app.MapDelete()

Database Design Database

1. Create a Project

Open Visual Studio 2022, click "Create a new project" and then select "ASP.NET Core Empty Project". Configure the the project, solution and location of projects. Finally select the Framework (.NET 6 LTS)

create project create project create project

Once the project is created, we can see Program.cs. Let's open and examine it.

var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run();

Lots of code that used to be previous .NET has been removed, for example using directives. in .NET 6 it use implicit namespace to reduce the amount of using directives boilerplate in previous version of project templates. Namespaes are implicity using global using feature. When are see the content of .csproject of project file, we can see ImplicitUsings is enable.

<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> </Project>

With implicit namespace set to false, or previous version of both .NET and .NET Core, we some thing like below.

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Services; using System.Web.UI; using System.Web.UI.WebControls;

Note: we can run our API in any port. To do so we need code like below which run in 3000 port.

app.Run(“http://localhost:3000");

Rather then putting POCO classes and DbContext in the ProductContext in Product.cs, we will store them in separate files for easier reading.

2. Models

Let's create model but that, let's create a folder named Models.

  • Create a class file name Brand.
  • Create another class file name Product

Nuget packages, copy them to project.csproj file.

<ItemGroup> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.2"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup>

Below are standard POCO classes.

Brand

global using System.Text.Json.Serialization; namespace Demo.Models { public class Brand { public int Id { get; set; } public string Name { get; set; } [JsonIgnore] public ICollection<Product>Products { get; set; } } }

Product

namespace Demo.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public int BrandId { get; set; } [JsonIgnore] public Brand Brand { get; set; } } }

Note: JsonIgnore indicate to hide it from JSON output.

3. DbContext

Create a folder called Data and then create a class file called StoreDbContext

using Demo.Models; using Microsoft.EntityFrameworkCore; namespace Demo.Data { public class StoreDbContext: DbContext { public StoreDbContext(DbContextOptions<StoreDbContext> options): base(options) { } public DbSet<Brand> Brands => Set<Brand>(); public DbSet<Product> Products => Set<Product>(); } }

Before we create a database for this sample, we need to run Add-Migration to create migration file. After that we run Update-Database to add or modify database.

Add-Migration InitialCreate
Update-Database

In the appsetting.json, we add connection string.

"ConnectionStrings": { "DefaultConnection": "Server=.;Database=Demo;Trusted_Connection=True;MultipleActiveResultSets=true" }

Sample Data

INSERT INTO Brands VALUES('Apple'), ('Samsumg') INSERT INTO Products VALUES('iPhone 10', 800, 1), ('S10', 700, 2)

4. APIs

Get all the products

app.MapGet("/products", async (StoreDbContext db) => await db.Products.ToListAsync() );

We are going to add swashbuckler (Swashbuckle.AspNetCore) for our project, so we have documentation for it. To do that we can simply add this line ("") to project.csproj but this time, we are going to install through NuGet Packages option.

swashbuckle

builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();
app.UseSwagger(); app.UseSwaggerUI();

Add a Product

app.MapPost("/products", async ([FromBody] Product product, [FromServices] StoreDbContext db, HttpResponse response) => { db.Products.Add(product); await db.SaveChangesAsync(); response.StatusCode = 200; });
app.MapPut("/products", async (int productId, Product product, [FromServices] StoreDbContext db, HttpResponse response) => { var aProduct = db.Products.Where(w => w.Id == productId).SingleOrDefault(); if (aProduct == null) return Results.NotFound(); aProduct.BrandId = product.BrandId; aProduct.Name = product.Name; aProduct.Price = product.Price; await db.SaveChangesAsync(); return Results.Created("/products", aProduct); });
app.MapGet("/products/{id}", async (StoreDbContext db, int Id) => await db.Products.FirstOrDefaultAsync(s => s.Id == Id) is Product aProduct ? Results.Ok(aProduct) : Results.NotFound() );
app.MapDelete("/products/{id}", async (int Id, StoreDbContext db) => { if (await db.Products.FindAsync(Id) is Product aProduct){ db.Products.Remove(aProduct); await db.SaveChangesAsync(); return Results.Ok(aProduct); }; return Results.NotFound(); });

5. Test the application

  • Install Postman
  • Open Postman
  • Disable SSL certificate verification
    • From File > Settings (General tab), disable SSL certificate verification.

Get all products postmam

Add a product postmam

Update a product postmam

Select a product postmam

Delete a product postmam