Build With Abdallah logo Build With Abdallah Software · AI · Automation
Tutorial 7 min read Jun 06, 2026

Building a .NET 10 Microservice with Minimal APIs

In this tutorial, we'll explore how to build a microservice using .NET 10's Minimal APIs. Minimal APIs provide a simpler and more efficient way to create HTTP APIs with less ceremo

A
Abdallah Mohamed
Senior Full-Stack Engineer
Building a .NET 10 Microservice with Minimal APIs

Building a .NET 10 Microservice with Minimal APIs

In recent years, microservices have become a popular architectural style for building scalable and maintainable applications. With the release of .NET 10, Microsoft has introduced Minimal APIs, which simplify the process of creating lightweight HTTP services. This tutorial will guide you through building a basic microservice using .NET 10's Minimal APIs. This approach is beneficial for developers who want to create fast, small, and efficient microservices without the overhead of a full-fledged MVC framework.

Prerequisites

Before we start building our microservice, ensure that you have the following tools installed on your machine:

  1. .NET SDK 10: Download and install the .NET SDK from the official website or use the following command:

    dotnet --version
    

    Ensure it returns a version number starting with 10.

  2. Visual Studio Code: You can download it from Visual Studio Code.

  3. C# Extension for VS Code: Install the C# extension in Visual Studio Code for enhanced development support.

  4. Postman: This is optional but recommended for testing your API endpoints.

Project Structure

Let's set up the project structure for our microservice. We'll create a simple directory tree to organize our files:

/MinimalMicroservice
    ├── Program.cs
    ├── WeatherForecast.cs

Step 1: Create a New .NET 10 Project

First, create a new directory for your microservice and initialize a new .NET 10 project.

mkdir MinimalMicroservice
cd MinimalMicroservice
dotnet new web -n MinimalMicroservice

This command creates a new .NET web project with the necessary files. The -n flag specifies the name of the project.

Step 2: Set Up the Program.cs File

The Program.cs file is the entry point for our microservice. We will configure it to use Minimal APIs.

Open the Program.cs file and replace its content with the following code:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello, World!");

app.Run();

Explanation:

  • WebApplication.CreateBuilder: Initializes a new instance of the application builder.
  • MapGet: Defines a route for HTTP GET requests. Here, it returns a simple "Hello, World!" message.
  • app.Run(): Starts the application.

Step 3: Create a WeatherForecast Endpoint

Now, let's add a more meaningful endpoint to our microservice. We'll create a simple weather forecast API.

First, create a new file named WeatherForecast.cs in the MinimalMicroservice directory with the following content:

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public string Summary { get; set; }
}

Next, update the Program.cs file to include the weather forecast endpoint:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello, World!");

app.MapGet("/weatherforecast", () =>
{
    var summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = summaries[Random.Shared.Next(summaries.Length)]
        })
        .ToArray();

    return forecast;
});

app.Run();

Explanation:

  • WeatherForecast Class: This class represents the structure of our weather forecast data.
  • MapGet("/weatherforecast"): Defines a new GET endpoint that returns an array of WeatherForecast objects.
  • Enumerable.Range: Generates a sequence of numbers that we use to create multiple forecast entries.
  • Random.Shared: Provides a thread-safe random number generator used to generate random temperatures and summaries.

With these steps, you have set up a basic .NET 10 microservice using Minimal APIs. In the next part of this tutorial, we will explore additional features and enhancements to make our microservice more functional and robust.

Step 4: Add Dependency Injection and Logging

To enhance our microservice, we will implement dependency injection and logging. This will help in maintaining clean code and tracking the application's behavior.

Modify Program.cs

Update your Program.cs file to register services and configure logging:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;

var builder = WebApplication.CreateBuilder(args);

// Configure logging
builder.Logging.ClearProviders();
builder.Logging.AddConsole();

// Add services to the container
builder.Services.AddSingleton<IWeatherService, WeatherService>();

var app = builder.Build();

app.MapGet("/", () => "Hello, World!");

app.MapGet("/weatherforecast", (IWeatherService weatherService) =>
{
    return weatherService.GetForecast();
});

app.Run();

public interface IWeatherService
{
    WeatherForecast[] GetForecast();
}

public class WeatherService : IWeatherService
{
    public WeatherForecast[] GetForecast()
    {
        var summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        return Enumerable.Range(1, 5).Select(index =>
            new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = summaries[Random.Shared.Next(summaries.Length)]
            })
            .ToArray();
    }
}

Explanation

  • Logging: Configures console logging to track application events.
  • IWeatherService: Defines an interface for the weather service.
  • WeatherService: Implements the IWeatherService interface to provide weather forecasts.
  • AddSingleton: Registers the WeatherService as a singleton service, meaning one instance is used throughout the application's lifetime.

Step 5: Handle Errors Gracefully

To improve the robustness of our microservice, we need to handle errors gracefully. We will use middleware to catch and log exceptions.

Update Program.cs

Modify the Program.cs file to include error handling middleware:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;

var builder = WebApplication.CreateBuilder(args);

builder.Logging.ClearProviders();
builder.Logging.AddConsole();

builder.Services.AddSingleton<IWeatherService, WeatherService>();

var app = builder.Build();

app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        context.Response.StatusCode = 500;
        context.Response.ContentType = "application/json";

        var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
        if (exceptionHandlerPathFeature?.Error is not null)
        {
            var logger = app.Services.GetRequiredService<ILogger<Program>>();
            logger.LogError(exceptionHandlerPathFeature.Error, "An error occurred.");

            await context.Response.WriteAsync(new
            {
                error = "An internal server error occurred."
            }.ToString());
        }
    });
});

app.MapGet("/", () => "Hello, World!");

app.MapGet("/weatherforecast", (IWeatherService weatherService) =>
{
    return weatherService.GetForecast();
});

app.Run();

public interface IWeatherService
{
    WeatherForecast[] GetForecast();
}

public class WeatherService : IWeatherService
{
    public WeatherForecast[] GetForecast()
    {
        var summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        return Enumerable.Range(1, 5).Select(index =>
            new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = summaries[Random.Shared.Next(summaries.Length)]
            })
            .ToArray();
    }
}

Explanation

  • UseExceptionHandler: Middleware to handle exceptions globally.
  • ILogger: Logs error details to the console for troubleshooting.

Complete Working Example

Here is the complete code for the microservice:

Program.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;

var builder = WebApplication.CreateBuilder(args);

builder.Logging.ClearProviders();
builder.Logging.AddConsole();

builder.Services.AddSingleton<IWeatherService, WeatherService>();

var app = builder.Build();

app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        context.Response.StatusCode = 500;
        context.Response.ContentType = "application/json";

        var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
        if (exceptionHandlerPathFeature?.Error is not null)
        {
            var logger = app.Services.GetRequiredService<ILogger<Program>>();
            logger.LogError(exceptionHandlerPathFeature.Error, "An error occurred.");

            await context.Response.WriteAsync(new
            {
                error = "An internal server error occurred."
            }.ToString());
        }
    });
});

app.MapGet("/", () => "Hello, World!");

app.MapGet("/weatherforecast", (IWeatherService weatherService) =>
{
    return weatherService.GetForecast();
});

app.Run();

public interface IWeatherService
{
    WeatherForecast[] GetForecast();
}

public class WeatherService : IWeatherService
{
    public WeatherForecast[] GetForecast()
    {
        var summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        return Enumerable.Range(1, 5).Select(index =>
            new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = summaries[Random.Shared.Next(summaries.Length)]
            })
            .ToArray();
    }
}

WeatherForecast.cs

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public string Summary { get; set; }
}

Common Errors and Fixes

Error: HTTP Error 500.0 - Internal Server Error

  • Cause: Unhandled exceptions in the application.
  • Fix: Use the exception handling middleware as shown in the tutorial to log and respond to errors gracefully.

Error: Cannot resolve service for type 'IWeatherService'

  • Cause: The WeatherService was not registered correctly.
  • Fix: Ensure builder.Services.AddSingleton<IWeatherService, WeatherService>(); is included in Program.cs.

Conclusion

In this tutorial, you learned how to build a basic microservice using .NET 10's Minimal APIs. We covered setting up endpoints, implementing dependency injection, logging, and error handling. These practices help create a maintainable and efficient microservice architecture. You can expand on this foundation by integrating databases, authentication, and more.

Sources