3. Iniial Build

We scaffold up the project we’ll be using throughout the rest of the book and put it under version control with Git.

About this chapter

This chapter introduces you to building REST APIs with .NET 10:

  • REST fundamentals: Understanding resource-based URLs, stateless communication, and HTTP verbs
  • What’s new in .NET 10: Performance improvements, minimal API enhancements, and built-in rate limiting
  • Why .NET for APIs: Cross-platform compatibility, high performance, and mature ecosystem
  • Getting started: Installing .NET SDK, choosing an IDE, and creating your first Web API project
  • Project setup: Understanding the project structure and minimal hosting model in Program.cs
  • Sample domain: Introducing the CommandAPI—a command-line reference application

Learning outcomes:

  • Understand REST principles and their importance in API design
  • Install and verify .NET 10 SDK and tooling
  • Create a new Web API project and understand its structure
  • Familiarize yourself with the Command/Platform domain model used throughout the book

1.1 Introduction to REST APIs and .NET 10

  • REST Principles: Resource-based URLs, stateless communication, standard HTTP methods
  • What’s New in .NET 10: Performance improvements, new minimal APIs enhancements, built-in rate limiting improvements
  • Why .NET for APIs: Cross-platform, high performance, mature ecosystem
  • Learning Path Overview: From basic CRUD to production-ready APIs

1.3 Creating the Initial Web API Project

At a command prompt navigate to your chosen working directory and type the following to scaffold up our project:

dotnet new webapi --use-controllers -n CommandAPI

This command:

  • Uses the webapi template to set up a bare-metal API
  • Specifies that we want to use controllers (MVC pattern)
  • Names the project CommandAPI

At a command prompt change into the CommandAPI directory:

cd CommandAPI

Performing a directory listing (ls command) you should see the project artifacts we have:

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----           7/09/2024  1:11 PM                Controllers
d----           7/09/2024  1:11 PM                obj
d----           7/09/2024  1:11 PM                Properties
-a---           7/09/2024  1:11 PM            127 appsettings.Development.json
-a---           7/09/2024  1:11 PM            151 appsettings.json
-a---           7/09/2024  1:11 PM            327 CommandAPI.csproj
-a---           7/09/2024  1:11 PM            133 CommandAPI.http
-a---           7/09/2024  1:11 PM            557 Program.cs
-a---           7/09/2024  1:11 PM            259 WeatherForecast.cs

1.4 Quick Look

Project File

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

Program.cs (Minimal Hosting Model)

  • Evolution: From Startup.cs to minimal APIs
  • Program.cs anatomy:
var builder = WebApplication.CreateBuilder(args);
// Service registration happens here
builder.Services.AddControllers();

var app = builder.Build();
// Middleware pipeline configured here
app.MapControllers();
app.Run();
  • Key Concepts:
    • WebApplicationBuilder - constructs the host
    • Service container - dependency injection setup
    • Middleware pipeline - request processing chain
    • Teaching Point: Show how this replaced the old Program.cs + Startup.cs pattern

Running & Testing

Let’s run and test the API to make sure everything from a base set up perspective is working ok:

CommandAPI ~> dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5279
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\Iteration_01\CommandAPI

Here you can see we have a single http endpoint running on port 5028.

It’s highly likely that you will have a different port allocation, don’t worry this is totally normal. When we scaffold the project, port allocations are somewhat random. Later we’ll be enabling https, at this point you can change the port allocation to match that of this tutorial if you like.

TODO: Test with HTTP Files

Remove boilerplate code

The API in its current form is not (for the most part) what we want to build, so we’re going to delete (and edit) some of the existing code.

  1. Delete the WeatherForecastController.cs file containing our controller (leave the controllers folder).
  2. Delete the WeatherForecast.cs file in the root of the project (this contains a class called WeatherForecast that was essentially the data returned in our test call).
  3. Edit the Program.cs file to contain only the following lines of code:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.MapControllers();

app.Run();

Here we removed:

  • References to Swagger. This is a really useful way to document REST API’s but it’s not part of our base build so we’ll remove it, (for now).
  • Authorization middleware. We’ll need this later, but again for focus and clarity we’ll remove it in this iteration.
  1. Edit the launchSettings.json file (found in the Properties folder) to resemble the following:
{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "https://localhost:7086;http://localhost:5279",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Here we removed:

  • IIS Settings: We’re not running our API from IIS so we don’t need this.
  • Redundant profiles. We’re only going to use the https profile.

In the remaining profile you can see that we now have 2 applicationUrls:

  • http://localhost:5279
  • https://localhost:7086 (new)

We’ve now introduced a HTTPS address that we’ll use for the remainder of the book. While it can add some degree of added complexity (see below), I always default to https where possible, and would only consider http endpoints if there was a compelling reason to do so.

Points to note about https

HttpsRedirection

Looking back at the Program.cs file, you’ll see that one of the lines we retained was:

app.UseHttpsRedirection();

This is middleware that will take any request to a http address and redirect it to a https one. While we can’t test this right now (we’ve deleted our controller!), if you look at the log output for the API, you’ll notice the following warning:

warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.

This occurred because the redirect attempt failed as we were using the http profile originally, and therefore there was no https route to go to.

Local Development Certificates

As we are using HTTPS, we need to employ a Self Signed Development Certificate to allow for HTTPS to work as expected. If this is the first time you’ve set up a .NET API you’ll more than likely need to explicitly trust a local self-signed certificate.

You can do that by executing the following command:

dotnet dev-certs https --trust

You will see output similar to the following, and as suggested you will get a separate confirmation pop up if this is indeed the first time you’ve done this:

Trusting the HTTPS development certificate was requested. 
A confirmation prompt will be displayed if the certificate 
was not previously trusted. Click yes on the prompt to trust the certificate.
Successfully trusted the existing HTTPS certificate.

Add Packages

We now want to add the packages to our project that will support the added functionality we require.

The package repository for .NET is called NuGet, when we add package references to our project file, they are downloaded from here.

To add the packages we need execute the following:

dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Microsoft.EntityFrameworkCore.Design

These packages allow us to use the PostgreSQL database from a .NET app.

To double check the references were added successfully, I like to look in the .csproj file, in our case: CommandAPI.csproj. You should see something similar to the following:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

</Project>

Here you should see the relevant package references in the <ItemGroup> section.

You’ll not a package reference to Swashbuckle.AspNetCore, this was present in our boilerplate code and can also be removed for now.

Initialize Git

We will be using Git throughout the book to put our project under source control, and later we’ll be leveraging Git & GitHub to auto deploy our code to Azure. For now, we’ll just set up and use Git locally.

📖 Read more about source control here.

Create a .gitignore file

First off we’ll create a .gitignore file, this tells Git to exclude files and folders from source control, such as the obj and bin folders found in a .NET Project.

At a command prompt “inside” our project folder type the following command:

dotnet new gitignore

NOTE: That we don’t include the period in front of the gitignore argument even though the file its self is called .gitignore

Upon executing that command you should see that a .gitignore file has been created in our project that excludes the artifacts relevant to a .NET project. A brief sample is shown below:

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

Basic Git Config

If this is the first time Git is being used on the PC or Mac that you’re working on, you’ll need to provide it with some basic identification details. This is so Git can track who has made changes to the code under source control. If we didn’t have this information, it would undermine the whole point of source control.

Git won’t let you make commits to a repository unless you have provided this information.

You only need to add your name and email address, to do some at a command prompt type:

git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

This will configure these details globally for all repositories on this machine.

Initialize Git

We’ve still not yet put our project under source control, to do so, type the following at a command prompt inside the project folder:

git init
git add .
git commit -m "chore: initial commit"

These commands do the following:

  • Initialize a git repository
  • Stage all our files for commit (using the “.” wildcard)
  • Finally commit all our staged files along with a Conventional Commit message

📖 You can read more about Conventional Commits here.

We should also check to see what our initial branch is called. Later versions of Git will name this branch main while older versions will name it master. Given the negative connotations of the latter, it’s standard practice today to rename to main.

To check the name of this branch type:

git branch

This will return something like:

* main

If this is the case - all good! If you’re using an earlier version of Git and this is not what you get, then I’d suggest 2 things:

  1. You update the version of Git you’re using
  2. Rename the branch to main by typing the following:
git branch -M main