In traditional ASP.NET Core applications, the Controller is a fundamental part of the MVC (Model-View-Controller) architecture. It receives incoming HTTP requests and produces responses. However, the new .NET 6 introduces a revolutionary concept: the Minimal API.
Minimal APIs are a lean, high-performance feature that allows developers to build HTTP APIs with as little code as possible. It’s a more declarative and functional approach that leverages the new C# features, especially the top-level statements and improved lambda support, to reduce the boilerplate code, making it a more productive model for developers.
The main differences between the traditional controller-based model and the Minimal API include:
Program.cs
file, which simplifies the code and streamlines the application structure.In this blog post, we will delve into the world of Minimal APIs, explore its features, especially its use with Dependency Injection (DI), and progressively build a complex application. Let’s start from the very basics.
To start with Minimal APIs, you need to have .NET 6 SDK installed on your system. Once you have the SDK ready, you can create a new Web API project with the following command:
dotnet new web
This will create a new project with a single Program.cs
file. Here is a simple example of a Minimal API:
var builder = WebApplication.CreateBuilder(args);var app = builder.Build();app.MapGet("/", () => "Hello, World!");app.Run();
In this example, app.MapGet("/", () => "Hello, World!");
maps a GET request to the root (”/”) URL path of the application to a delegate that returns a string “Hello, World!“.
In C#, a delegate is a reference type variable that holds the reference to a method. It’s a powerful feature that makes it possible to pass methods as parameters. Minimal APIs leverage delegates to handle HTTP requests.
app.MapGet("/hello", () => "Hello from delegate!");
In this example, the delegate () => "Hello from delegate!"
is invoked when a GET request is made to “/hello”.
As we delve deeper into Minimal APIs, let’s introduce complexity gradually. Imagine we want to create an API to manage a list of products.
First, let’s define a Product
record:
public record Product(int Id, string Name, decimal Price);
Next, we will need to store our products somewhere. For simplicity, we will use an in-memory list:
var products = new List<Product>{new Product(1, "Product 1", 10.99m),new Product(2, "Product 2", 20.99m),// Add more products as necessary};
Now, we can create an endpoint to retrieve all products:
app.MapGet("/products", () => products);
Dependency Injection (DI) is a technique to achieve Inversion of Control (IoC) between classes and their dependencies. It allows for more flexible, modular, and testable code. In a Minimal API, we can easily use Dependency Injection.
Let’s consider a scenario where we have a service to manage our products. We’ll start by defining an interface for our service:
public interface IProductService{IEnumerable<Product> GetProducts();// Other product operations can be defined here}
We’ll then implement this interface:
public class ProductService : IProductService{private readonly List<Product> _products;public ProductService(){_products = new List<Product>{new Product(1, "Product 1", 10.99m),new Product(2, "Product 2", 20.99m),// Add more products as necessary};}public IEnumerable<Product> GetProducts() => _products;}
We can now register ProductService
in our DI container:
var builder = WebApplication.CreateBuilder(args);builder.Services.AddSingleton<IProductService, ProductService>();var app = builder.Build();
To use our ProductService
, we can modify our /products
endpoint to inject the IProductService
:
app.MapGet("/products", ([FromServices] IProductService productService) => productService.GetProducts());
With the DI in place, the Minimal API architecture provides a highly testable, flexible, and modular codebase.
So far, we’ve only dealt with GET requests. However, Minimal APIs are fully capable of handling other HTTP methods. Let’s implement a POST endpoint to add new products:
app.MapPost("/products", (Product product, [FromServices] IProductService productService) =>{productService.AddProduct(product);return Results.Created($"/products/{product.Id}", product);});
Here, we’re injecting both Product
(from the request body) and IProductService
into our POST method. After adding the product, we return a 201 Created status along with the location of the new resource.
.NET 6 has introduced a range of new features designed to simplify the development of web applications. Among the most exciting of these is Minimal APIs. Minimal APIs allow developers to build HTTP APIs with minimal coding and configuration. It’s a simpler, more streamlined way to build APIs, and it offers a number of advantages over traditional controller-based APIs.
But what if we could make Minimal APIs even simpler?
I’m excited to announce the release of my new .NET library, MicroEndpoints. MicroEndpoints is designed to simplify the creation of HTTP endpoints, and it’s built to leverage the power of .NET 6’s Minimal APIs.
The aim of MicroEndpoints is to further simplify the process of setting up HTTP APIs. With this library, creating both asynchronous and synchronous operations becomes a breeze. It’s all about making your API development process more efficient and straightforward.
One of the main benefits of using MicroEndpoints is its ease of use. The library takes care of a lot of the boilerplate code that you would normally have to write when setting up an API, allowing you to focus more on your business logic.
But that’s not all. MicroEndpoints also makes unit testing your endpoints easier. With its clean, minimalistic design, you can isolate your endpoint logic and test it without having to worry about the complexities of HTTP requests and responses. This means you can ensure your endpoints are working as expected before you even deploy your API.
You can find MicroEndpoints on GitHub and NuGet. I’m excited to see how developers use MicroEndpoints to simplify their API development. I hope it will be as useful to you as it has been to me in my projects. Feel free to share your thoughts and feedback with me, and let’s take our .NET 6 Minimal APIs to the next level!
I’d like to take a moment to express my gratitude to Steve Smith @ardalis and his Ardalis.ApiEndpoints package. This excellent package was a significant influence on the development of MicroEndpoints. Ardalis’s work on developing a clean architecture for .NET has been inspiring, and I highly recommend checking out his package as well.
If you want to explore more about Minimal APIs and related topics, here are some recommended resources:
Minimal APIs are a new, streamlined way of building lightweight HTTP APIs in .NET 6. Leveraging new features of C#, they provide an efficient, expressive, and flexible approach to writing APIs.
While they may be “minimal,” they certainly don’t lack in capability. They support complex routing, model binding, and even Dependency Injection out of the box. They are a powerful tool in the .NET ecosystem and definitely worth exploring for your next API project.
Remember, while minimalism is the goal, the possibilities with Minimal APIs are endless. Happy coding!
We’d love to hear your feedback on this tutorial! If you have any questions or suggestions for improvement, please don’t hesitate to reach out. You can leave a comment below, or you can contact us through the following channels:
We’ll do our best to address any questions or concerns you may have. We look forward to hearing from you and helping you make the most of building efficient and reliable Minimal APIs with C# and .NET!
Quick Links
Legal Stuff