Build a Backend with ASP.NET Core — Beginner Guide

Dilshara Hetti Arachchige
10 min readApr 14, 2024

--

ASP.NET Core

ASP.NET Core, a powerful and open-source framework from Microsoft, provides a superb foundation for building efficient and scalable backends.

In this blog series, we’ll be constructing a comprehensive Courses API. This API will serve as a central hub for retrieving information about courses and their instructors, laying the groundwork for a dynamic web application.

Welcome to the first blog of this exciting series! Today, we’ll dive into the essentials of ASP.NET Core and build a simple, yet functional, Course API.

Why ASP.NET Core?

Here’s why ASP.NET Core is a compelling choice for crafting your backend systems:

  • Cross-platform — Develop and run your backends on Windows, Linux, or macOS.
  • Performance — ASP.NET Core consistently ranks among the fastest web frameworks, giving your applications an edge.
  • Flexibility — Its modular design allows you to pick and choose the exact components you need, reducing overhead.
  • Strong Community and Support — Backed by Microsoft and a large community, you’ll find plenty of resources and help when needed.
  • Modern Tooling — Works seamlessly with popular development tools like Visual Studio and Visual Studio Code.

What We’ll Cover

In this blog post, we’ll guide you through the essentials of building a backend with ASP.NET Core. Get ready to dive into…

  • Setting up your development environment
  • Creating your first ASP.NET Core web API project
  • Implementing basic CRUD operations (Create, Read, Update, Delete)

Getting Started

Download .NET latest version

Download .NET Latest version (.NET 8.0 is the latest version when drafting this blog and .NET 9.0 was on preview) from the official site https://dotnet.microsoft.com/en-us/download

Open VS Code and type CTRL+P to access the Quick Dialog and type .NET New Project and select it.

As a beginner, starting from a clean slate is always good. So, choose the ASP.NET Core Web, Empty template.

Select a project location, give your project a suitable name, and set up your development environment. We’ll be building a Courses API for this demo project, so I’ve named the project ‘Courses API’.

Development Environment

After the project setup, the IDE project structure should look something like the above.

Extension to Download

C# Dev Kit

C# Dev Kit

This is your all-in-one toolkit for streamlined .NET development. It includes:

  • C# for Visual Studio Code (powered by OmniSharp): The backbone for intelligent code editing, navigation, and debugging.
  • Project System for Visual Studio Code: Improved handling of your .NET project files for better organization.
  • MSBuild for Visual Studio Code: Allows you to run essential build commands directly inside your editor.

NuGet Package Manager

.NET projects often use many external libraries. This extension is your best friend for finding, installing, and keeping those libraries up-to-date.

Project Structure and Generated Files

launchSettings.json

As per starters, you may need to know a bit about the launchSettings.json file you may find in your “properties” folder.

Think of launchSettings.json as a configuration center for how your application launches during development. Here’s what it helps you control:

  • Environment Variables: You can set different environment variables (like “Development,” “Staging,” or “Production”) and your application can behave differently based on those settings.
  • Application URLs: Defines the ports and addresses your application will listen on when you start it up for testing.
  • IIS Settings: If you’re using IIS Express (a lightweight web server for development), you can configure relevant settings here.
  • Browser Launch: You can even tell it which browser to open automatically when running your project.

Program.cs

This file is the heart of your ASP.NET Core application. It’s the starting point where everything begins. Think of it as the main gate to your app. This involves creating a web server and configuring things like how your application handles incoming requests.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
  • The WebApplicationBuilder — The WebApplication.CreateBuilder(args) method sets the stage. It creates an object (builder) that helps you configure and construct all the essential parts of your web application.
  • The WebApplication — This builder.Build() is where the builder takes all your configurations and assembles them into the actual WebApplication object (app). Your application is now ready to run!
app.MapGet("/", () => "Hello World!");
  • Mapping Routes — app.MapGet("/", ...) tells your app, "When someone sends an HTTP GET request to the root path ('/'), respond with the text 'Hello World!'". This is the most basic way to define a route or an endpoint in your API.
app.Run();
  • Starting the Engine — app.Run() gets your web application up and running! It starts the web server and begins listening for incoming requests. Your application is now live and waiting to respond to those requests.

Running the Application

Navigate to correct project location on the terminal and enter

dotnet run

Use any of your REST Clients and make a GET request to the root endpoint.

Cautious: Double-check your local host port in the launchSettings.json file.

localhost port: 5238

Course Mappings for CRUD Operations

Initial Data setup

As we won’t be exploring database connectivity in this blog, we’ll start the project with a hardcoded course list. However, since C# is a strictly typed language, we’ll first need to define DTOs (Data Transfer Objects) to represent a Course object.

A DTO is a class specifically designed to hold the data we want to transfer between different parts of our application, or even between our application and external systems (like an API).

Start by creating a new folder called Dtos. In the folder, create a new Dto called “GetCoursesDto.cs”. We will be storing the course ID, name, description, no of chapters and instructor ID as fields for now.

namespace CourseAPI.Dtos;

public record class CreateCourseDto(
string Name,
string Description,
int NoOfChapters,
string InstructorId
);

Now we can have a list of courses to perform CRUD Operations. Create a list of dummy “GetCoursesDto” objects as follows in the program.cs file.

List<GetCoursesDto> courses = [

new (
1,
"Node Backend Development",
"This is a demo course",
20,
"1"
),
new (
2,
"React Development",
"This is a Full course",
10,
"2"
),
new (
3,
"Java with OOP Internship Bootcamp",
"This is a Full course",
20,
"2"
)
];

GET All Courses and One Course Mapping

In RESTful APIs, the HTTP verb ‘GET’ is used to retrieve data.

GET All Courses

Route “courses” defines the base URL path users will access for this piece of functionality.

app.MapGet("courses", () => courses);

Lambda Function() => courses is where you write the logic. Here, it returns thecourses list which contains all the course data. When the endpoint is reached, it simply returns the entire courses list.

GET One Course

In the “courses/{id}”, the {id} part makes this route dynamic. It will match requests like "/courses/1", "/courses/2", etc., where the number represents a specific course ID.

app.MapGet("courses/{id}",(int id)=> {
return courses.Find(course =>course.Id == id);
}).WithName("GetCourse");
  • Lambda Function:(int id) => ... - The id inside the parentheses is automatically extracted from the route based on its position after "courses/". courses.Find(course =>course.Id == id) - This line searches your courses list for the first course with an ID matching the id from the request.
  • WithName(“GetCourse”): This part assigns a name to the route. You’ll see later how this name can be useful for things like generating links within your application.

Post a New Course

When creating a new entry, the Post mapping would be utilized. To typesafe the payload, we can create a new model called CreateCourseDto.

Create a new record file in the Dtos folder as following

namespace CourseAPI.Dtos;

public record class CreateCourseDto(
string Name,
string Description,
int NoOfChapters,
string InstructorId
);

Previously, we used MapGet to retrieve course information. Now let's explore how we can add new courses to our list using MapPost. Route “courses” specifies the base path for adding new courses.

app.MapPost("courses",(CreateCourseDto newCourse)=>{
int id = courses.Count + 1;
GetCoursesDto course = new (id,newCourse.Name,newCourse.Description,newCourse.NoOfChapters,newCourse.InstructorId);

courses.Add(course);

return Results.CreatedAtRoute("GetCourse",new {id= id}, course);
});
  • (CreateCourseDto newCourse) defines an input parameter representing the data of the new course to be created. We would be utilizing the CreateCourseDto to model this data.
  • int id = courses.Count + 1; – A simple way to generate a new unique ID for our course (you'll likely replace this with a database-generated ID in a real application).
  • GetCoursesDto course = new (...) - Creates a new GetCoursesDto object representing the course to be added.
  • courses.Add(course); – Adds the newly created course object to your in-memory courses list.
  • return Results.CreatedAtRoute(...) – This is a successful response! It does three things:
  1. Provides an HTTP status code of 201 (Created).
  2. Includes a “Location” header indicating where the newly created course can be found using the ‘GetCourse’ route defined earlier.
  3. Returns the created ‘course’ object in the response body.
REST Client Response

Update an Existing Course

Our application isn’t complete without the ability to modify existing course information. For this, we’ll use MapPut.

In the “courses/{id}” route, the {id} makes this route dynamic, signalling that we need to provide the ID of the course we wish to update. Depending on the business logic, you can also create a separate Dto for the Update payload. But for the current implementation, the CreateCourseDto can be utilized.

app.MapPut("courses/{id}",(int id, CreateCourseDto updatedCourse) =>{
GetCoursesDto? currCourse = courses.Find(course=> course.Id == id);
if(currCourse == null){
return Results.NotFound();
}
GetCoursesDto newCourse = new(
id,
updatedCourse.Name,
updatedCourse.Description,
updatedCourse.NoOfChapters,
updatedCourse.InstructorId

);
courses[id-1] = newCourse;
return Results.Ok();
});
  • (int id, CreateCourseDto updatedCourse) – Takes the ID from the URL and the updated course data as input parameters.
  • GetCoursesDto? currCourse = ... – Attempts to find the existing course using its ID. The '?' allows currCourse to be null if no match is found.
  • if(currCourse == null) ... – Error handling! If the course is not found, it returns a '404 Not Found' response.
  • GetCoursesDto newCourse = new(...) – Creates a new course object incorporating the changes from updatedCourse.
  • courses[id-1] = newCourse; – Replace the old course in your list with the newly updated version.
  • return Results.Ok(); – Signals a successful update with a status code of 200 (OK).

Delete a Course

Finally, let’s enable the ability to remove courses from our collection. This is where the HTTP verb ‘DELETE’ comes into play. The “courses/{id}” route includes {id} to identify the specific course we want to delete.

app.MapDelete("courses/{id}",(int id)=> {
int courseId = courses.FindIndex(course => course.Id == id);
if(courseId == -1){
return Results.NoContent();
}
courses.RemoveAt(id-1);
return Results.NoContent();
});
  • int courseId = courses.FindIndex(...) – Finds the index (position) of the course with the matching ID within your courses list.
  • if(courseId == -1) ... – Another bit of error handling. If the course is not found, it returns a '204 No Content' response, as technically there's nothing to delete.
  • courses.RemoveAt(id-1) – Removes the course from your list using the index found earlier.
  • return Results.NoContent(); – Sends a '204 No Content' response to signal a successful deletion.

Congratulations. You have built your 1st simple API with ASP.NET Core. So let’s try to understand what’s left to explore.

What to Explore in the Next Blog

While we’ve built a solid foundation for a Courses API, there’s always more to learn in ASP.NET Core development. In the upcoming blog, we’ll dive into some exciting concepts that will level up your API skills.

  • Extension methods and route groups — Bring code organization and efficiency to your API endpoints.
  • Input validation — Ensure your API receives clean and reliable data.
  • Data models, database connectivity, and data querying — Introduce persistent storage through a database and learn to interact with it effectively.
  • Entity mapping — Bridge the gap between your code’s objects and database tables.
  • Dependency injection and service lifetime — Enhance the flexibility and testability of your application.
  • Asynchronous programming — Keep your API responsive and snappy, especially when dealing with time-consuming operations.

Get ready to take your ASP.NET Core backend development skills to new heights. See you in the next post!

--

--

Dilshara Hetti Arachchige

Software/Product Engineer who loves to build AI-Driven Solutions