Published:

.NET 5.0 - Bare Bones API Tutorial

Tutorial built with .NET 5.0

This is a step by step tutorial on how to build a simple bare bones .NET 5.0 API from scratch with a couple of example endpoints/routes. Each step provides details on every line of code and configuration to show how it all fits together, and the resulting API can be used as a minimal starter project for building a new .NET API.

The completed API starter project is available on GitHub at https://github.com/cornflourblue/dotnet-5-bare-bones-api.


Tutorial Contents


Tools Required to Develop .NET 5.0 APIs

To develop, run and test .NET 5.0 APIs download and install the following:

  • .NET SDK - includes the .NET runtime and command line tools
  • Visual Studio Code - free code editor / IDE that runs on Windows, Mac and Linux
  • C# extension for Visual Studio Code - adds support to VS Code for developing and debugging .NET applications
  • Postman - a GUI based API client for testing.


Create MSBuild C# Project File (.csproj)

The .NET CLI uses the Microsoft Build Engine (MSBuild) to build .NET projects. A .NET project file is an XML document containing MSBuild code that executes when you run the command dotnet build, and has a file extension based on the programming language used in the project (e.g. .csproj for C#, .fsproj for F#, .vbproj for VB etc).

There is a lot more to MSBuild than I can cover in this post, for full documentation see https://docs.microsoft.com/visualstudio/msbuild/msbuild.

SDK style projects

When .NET Core was released, a new type of MSBuild project called an SDK style project was also released to simplify project files and make them much smaller. Traditionally ASP.NET projects had large and complex MSBuild project files that were managed automatically by the Visual Studio IDE, but Visual Studio isn't required for .NET Core or .NET 5.0+ projects so the new format was created to make it easier to understand and edit the files by hand.

SDK style project files are simplified because the MSBuild complexity is encapsulated in an SDK which contains a set of MSBuild properties, items, targets and tasks for building the project, all you need to do is reference the SDK for your project type.

For more info on SDK style projects see https://docs.microsoft.com/dotnet/core/project-sdk/overview.

Project file details

The <Project> element is the root element of an MSBuild project file, the Sdk attribute tells MSBuild that this is an SDK style project and specifies that it's a .NET Web App with the value Microsoft.NET.Sdk.Web.

The <TargetFramework> element creates an MSBuild property named TargetFramework with the value net5.0 to configure the build for the .NET 5.0 framework. Properties in MSBuild are key/value pairs like variables in other programming languages, they are declared by adding child elements to a <PropertyGroup> element.

Create the project file

  1. Create a new folder for the project named WebApi
  2. Create a new C# project file in the folder named WebApi.csproj
  3. Copy the below MSBuild XML into the project file and save
<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>
</Project>

Back to top


Create .NET Startup Class

The Startup class configures the services available to the .NET Dependency Injection (DI) container in the ConfigureServices() method, and configures the .NET request pipeline for the application in the Configure() method. Both methods are called by the .NET runtime when the app starts, first ConfigureServices() followed by Configure().

The .NET host passes an IApplicationBuilder to the Configure() method, all DI services are also available to Configure() and can be added as parameters to the method (e.g. public void Configure(IApplicationBuilder app, IMyService myService) { ... }). For more info on the startup class and both configure methods see https://docs.microsoft.com/aspnet/core/fundamentals/startup.

Startup class details

The services.AddControllers() method registers services for controllers with the .NET dependency injection (DI) system.

Routing middleware is added to the request pipeline by calling both app.UseRouting() and app.UseEndpoints(...), the first adds route matching middleware and the second adds endpoint execution middleware to the pipeline. The lambda expression x => x.MapControllers() is passed to app.UseEndpoints() to create endpoints for action methods of attribute routed controllers (controllers decorated with the [Route("...")] attribute).

Create the Startup class

  1. Create a new C# class file in the project folder named Startup.cs
  2. Copy the below C# code into the file and save
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace WebApi
{
    public class Startup
    {
        // add services to the DI container
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
        }

        // configure the HTTP request pipeline
        public void Configure(IApplicationBuilder app)
        {
            app.UseRouting();
            app.UseEndpoints(x => x.MapControllers());
        }
    }
}

Back to top


Create Program Class with Main Method

The Main() method is the entry point for a .NET application, when an app is started it searches for the Main() method to begin execution. The method can be located anywhere in a project but is typically placed in the Program class.

A .NET web app is run within a host which handles app startup, lifetime management, web server configuration and more. A host is created and launched by calling Build().Run() on a host builder (an instance of the IHostBuilder interface). A host builder with pre-configured defaults can be created with the CreateDefaultBuilder() convenience method provided by the static Host class (Microsoft.Extensions.Hosting.Host).

Program class details

The CreateDefaultBuilder() method creates a generic host builder configured for both web and non-web applications (e.g. worker service apps). The ConfigureWebHostDefaults() extension method configures the host builder for hosting a web app including setting Kestrel as the web server, adding host filtering middleware and enabling IIS integration. For more info on the default host builder settings see https://docs.microsoft.com/aspnet/core/fundamentals/host/generic-host#default-builder-settings.

The x.UseStartup<Startup>() method specifies which startup class to use when building a host for the web app.

Create the Program class

  1. Create a new C# class file in the project folder named Program.cs
  2. Copy the below C# code into the file and save
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(x => x.UseStartup<Startup>());
        }
    }
}

Back to top


Create App Settings File

The appsettings.json file is the base configuration file in a .NET app that contains settings for all environments (e.g. Development, Production). You can override values for different environments by creating environment specific appsettings files (e.g. appsettings.Development.json, appsettings.Production.json).

Configuration values from the app settings file are accessed with an instance of IConfiguration which is available via .NET dependency injection (e.g. public MyConstructor(IConfiguration configuration) { ... }), the config values are retrieved by key (e.g. configuration["Logging:LogLevel:Microsoft"]).

For more info on configuration in .NET see https://docs.microsoft.com/aspnet/core/fundamentals/configuration/.

App settings file details

The Logging section of the app settings file configures the LogLevel for a couple of selected categories (Microsoft and Microsoft.Hosting.Lifetime). The LogLevel sets the minimum level of message to log for each category, the default level is Information so by default all messages of level Information or higher will be logged.

The setting "Microsoft": "Warning" prevents a bunch of messages from being logged for each request to the API by setting the minimum log level to Warning for all categories that begin with Microsoft.

The setting "Microsoft.Hosting.Lifetime": "Information" overrides the previous setting to log Information messages for API lifetime events (startup and shutdown) by setting the log level for a more specific category (Microsoft.Hosting.Lifetime).

For more info on logging in .NET see https://docs.microsoft.com/aspnet/core/fundamentals/logging/.

Create the app settings file

  1. Create a new file in the project folder named app.settings.json
  2. Copy the below JSON code into the file and save
{
    "Logging": {
        "LogLevel": {
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        }
    }
}

Back to top


Create Product Entity Class

Entity classes represent the core data of a .NET app, and are commonly used with an ORM such as Entity Framework to map to data stored in a relational database (e.g. SQL Server, MySQL, SQLite etc). Entities can also be used to return HTTP response data from controller action methods, and to pass data between different parts of the application (e.g. between services and controllers).

Product entity details

The Product entity class represents the data for a product in the application, it contains a minimal set of properties (just Id and Name) for testing the bare bones API.

Create the Product class

  1. Create a new folder in the project folder named Entities
  2. Create a new C# class file in the Entities folder named Product.cs
  3. Copy the below C# code into the file and save
namespace WebApi.Entities
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

Back to top


Create Products Controller

Controller classes contain action methods that handle the HTTP requests sent to a .NET API. The MapControllers() method called in Startup.cs above automatically creates HTTP endpoints for action methods of attribute routed controllers (controllers decorated with the [Route("...")] attribute. All public methods of a controller are called action methods.

Products controller details

The ProductsController class derives from ControllerBase, a built-in .NET base class for an API controller (basically an MVC controller without view support), it provides methods and properties for handling HTTP requests including Ok(), NotFound(), Request and Response. For more info on ControllerBase see https://docs.microsoft.com/aspnet/core/web-api#controllerbase-class.

The [ApiController] attribute enables a few features designed to simplify API development, including automatic model validation and HTTP 400 response on failure, and automatic inference of the binding source (location) of parameters based on parameter type and name (e.g. [FromBody], [FormQuery] etc). For more info see https://docs.microsoft.com/aspnet/core/web-api#apicontroller-attribute.

The [Route("[controller]")] attribute sets the route template to "[controller]" to use the controller name as the base route for all action methods (i.e. "/users"). For more info on attribute routing see https://docs.microsoft.com/aspnet/core/mvc/controllers/routing#attribute-routing-for-rest-apis.

The private _products variable contains a hardcoded list of products to enable testing of the GetAll() and GetById() action methods, in a real world application this data would usually come from a database or another type of data repository.

The GetAll() method uses the Ok() convenience method to return an HTTP 200 OK response with a list of all products. The [HttpGet] attribute constrains the method to only match HTTP GET requests, the attribute is used without a route template parameter so it matches the base path of the controller ("/products").

The GetById() method returns an Ok() response with the specified product if it exists, otherwise it returns NotFound() (HTTP response code 404 Not Found). The [HttpGet("{id}")] attribute constrains the method to HTTP GET requests matching the path /products/{id} (e.g. /products/1, /products/2 etc), the {id} path parameter is automatically bound to the int id parameter of the method.

The IActionResult return type represents various HTTP status codes such as 200 OK, 400 Bad Request, 404 Not Found etc. The Ok() method creates an implementation of IActionResult that produces a HTTP 200 OK response.

Create the ProductsController class

  1. Create a new folder in the project folder named Controllers
  2. Create a new C# class file in the Controllers folder named ProductsController.cs
  3. Copy the below C# code into the file and save
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using WebApi.Entities;

namespace WebApi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class ProductsController : ControllerBase
    {
        private List<Product> _products = new List<Product>
        {
            new Product { Id = 1, Name = "Milo" },
            new Product { Id = 2, Name = "Tim Tams" }
        };

        [HttpGet]
        public IActionResult GetAll()
        {
            return Ok(_products);
        }

        [HttpGet("{id}")]
        public IActionResult GetById(int id)
        {
            var product = _products.Find(x => x.Id == id);
            if (product == null)
                return NotFound();

            return Ok(product);
        }
    }
}

Back to top


Launch API and Test with Postman

Postman is a great tool for testing APIs, you can download it at https://www.postman.com/downloads.

Start the API by running dotnet run from the command line in the project root folder (where the WebApi.csproj file is located), you should see a few console messages including Now listening on: http://localhost:5000. To enable hot reloading (restarting on file changes) use the command dotnet watch run.

NOTE: To find out how to easily launch the API in debug mode with VS Code see VS Code + .NET - Debug a .NET Web App in Visual Studio Code and skip to the step: Generate tasks.json and launch.json.

How to get all products from the API

Follow these steps to fetch a list of all products from the API with Postman:

  1. Open a new request tab in Postman by clicking the plus (+) button at the end of the tabs
  2. Change the HTTP method to GET with the dropdown selector on the left of the URL input field
  3. In the URL field enter the address to the products route of your local API - http://localhost:5000/products
  4. Click the Send button, you should receive a "200 OK" response containing a JSON array with all the products in the API

Screenshot of Postman after the request:


How to get a single product from the API

Follow these steps to fetch a specific product from the API with Postman:

  1. Open a new request tab in Postman by clicking the plus (+) button at the end of the tabs
  2. Change the HTTP method to GET with the dropdown selector on the left of the URL input field
  3. In the URL field enter the address to the product details route of your local API - http://localhost:5000/products/1
  4. Click the Send button, you should receive a "200 OK" response containing a JSON object with the specified product details

Screenshot of Postman after the request:

Back to top

 

Subscribe or Follow Me For Updates

Subscribe to my YouTube channel or follow me on Twitter or GitHub to be notified when I post new content.