Getting Started
In this blog series, I will be documenting my study of the .Net framework providing a basic overview on how to get started. To begin with, I will be covering the creation of a basic API backend.
.NET is an open-source framework for building modern, cross-platform applications. It offers a rich set of tools and libraries that help developers create robust, scalable, and high-performance software. Additionally, .NET supports multiple programming languages, including C#, Visual Basic, and F#.
Throughout these blogs, I will be primarily programming in C#.
Note: This blog series assumes that the reader has a basic understanding of core OOP concepts (classes, inheritance, setters, getters, etc.). If you are not familiar with any strongly typed language I'd highly recommend familiarizing yourself with at least one before proceeding.
At this stage, if you haven't yet done so, download the
official .Net SDK. Throughout this guide, I will use .Net 9.0 on Windows. However, there are also official development kits for Linux and Mac OS. Just remember commands may differ somewhat if you are not also using the Windows command prompt.
The .Net CLI
Let's begin by making sure .Net is installed correctly using:
dotnet --info
Running the following command should provide a quick overview of the CLI, assuming .Net is correctly installed on your machine:
dotnet -h
You should familiarize yourself with this list, but I'll discuss individual commands in more detail later.
Creating a new project
So, let's cut to the chase and create our first project. Create a directory for the application. My project is called EShop, so I'm naming my directory accordingly.
Next, navigate to your project directory and create a solution file. This file will automatically be named after your project directory. For example, if your project is called MyCoolProject the solution file will be named MyCoolProject.sln.
mkdir EShop
cd EShop
dotnet new sln
In .NET development, a solution is a container for organizing and managing multiple projects. The .sln file stores information about the projects within the solution, their dependencies, build configurations and other related settings. The use of this method makes it easier to work on multiple projects simultaneously.
Now comes the fun part, picking a project template to start from. You can list all of .Net's included templates with the following command:
dotnet new list
In this project, we will start with the ASP.NET Core Web API template. Note: In the first command I append a flag named 'controllers'. There are two flavours of the Web API template. The Minimal API template (the default template) which is designed to be lightweight and straightforward, using the least amount of code necessary to define routes and handle requests. And the 'controllers' template which follows the traditional MVC (Model-View-Controller) pattern and requires you to define controllers.
After generating the API project it is added to the solution file, it is at this stage we can then navigate to the project directory and run it.
dotnet new webapi -n API -controllers // Create the project appending the 'controllers' flag.
dotnet sln add API // Add the API project to the solution file.
cd API // Navigate to the API project directory.
dotnet run // Run the project.
Note: .Net runs the application on a randomly generated port. If you wish to change this open the generated launchSettings.json in the properties directory. The property applicationUrl can be updated to your port of choice if you wish to do so.
.Net should automatically launch the application in your default browser at this stage. If nothing happens, you can navigate to the localhost address displayed in the console yourself. (I will explain how to configure this behaviour later in the guide). You will be greeted by the message "This localhost page can’t be found", but don't worry, this is fully expected as we haven't built anything yet.
Navigate to http://localhost:5078/WeatherForecast (remember to use the correct port, mine in this example is 5000). If your application is running you should be greeted by some sample data returned from the provided by the generated example controller "WeatherForecast".
Project structure
Having now created the project, we will examine its structure, files, and configuration.
Note: The code in these boilerplate may slightly differ depending on what version of .NET you are using.
Bin
The "bin" folder is the directory that contains the compiled output of the project.
Controllers
As the name implies, this folder houses our application controllers.
obj
The "obj" folder is a temporary directory that is used during the build process. "obj" stands for "object," and it contains intermediate files generated during the compilation and build process of the application.
Properties
The "Properties" folder contains various project-related settings and configuration files. It serves as a central place for managing project-specific properties.
Note: Exclude obj and bin folders in your git ignore if you are checking into version control.
Project Files
Properties/launchSettings.json
The launchSettings.json file is primarily used by development tools, such as Visual Studio or the .Net CLI. It determines how the project should be launched, debugged or tested during development. If you are familiar with the JSON format the structure of this file should look fairly familiar.
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Note: The launchSettings.json file by default has multiple profiles, and we only need one to run our application. I have simplified my example for now as this is all we need at this stage.
Let's go through its individual properties one by one.
$schema: This property specifies the URL of the JSON schema that defines the structure and validation rules for the launchSettings.json file.
profiles: This property is an object that contains one or more profiles. A profile represents a specific configuration for launching or debugging the project.
http: This property represents a profile configuration for launching or debugging a .NET project using an HTTP server.
commandName: This property specifies the command to be executed when launching the project. In this case, the value is Project, which means that the project itself will be executed.
dotnetRunMessages: This property is a boolean value that determines whether or not to display messages from the dotnet run command in the console. If set to true, you will see messages related to the running project.
launchBrowser: This property is a boolean value that determines whether or not to automatically launch a web browser when the project is started. In this case, it is set to false, so the browser will not be launched.
applicationUrl: This property specifies the URL where the project will be hosted. In this example, the project will be hosted at "http://localhost:5000".
environmentVariables: This property is an object that allows you to specify environment variables for the project. In this case, it sets the value of the "ASPNETCORE_ENVIRONMENT" variable to "Development" specifying the environment in which the project should run.
API.csproj
The API.csproj file is an XML-based project file that defines the properties, dependencies, and other project-specific configurations.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup>
<!-- Make sure nullable warnings occur as errors -->
<WarningsAsErrors>CS8618</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
</Project>
PropertyGroup: This element groups a set of properties together.
TargetFramework: This property specifies the target framework version for the project. In this example, the project is targeting the .NET 7.0 framework.
Nullable: This property specifies the nullability behaviour for the project. It determines whether a variable or parameter can accept or return null values, and how the compiler or runtime treats nullability in terms of type safety and potential null reference errors. In this case, it is set to "enabled", which means that nullability checks are turned on.
ImplicitUsings: This property enables implicit namespace imports in the project. It allows you to use types from certain namespaces without explicitly importing them.
ItemGroup: This element groups a set of items together. In this case, it is used to define the package references for the project.
WarningsAsErrors: This property specifies that the warning with the code "CS8618" should be treated as an error. It means that if the specified warning is encountered during compilation, it will be treated as an error and prevent the successful build of the project.
Note: The code "CS8618" refers to a nullability warning, I will cover nullability and why I have set this to be an explicit error in a later blog.
PackageReference: This line specifies a package reference to the "Microsoft.AspNetCore.OpenApi" package with version 7.0.10. It indicates that the project depends on this package and requires it to be installed.
appsettings.json
appsettings.json is the main configuration file for the project. It contains the default configuration settings that apply to all environments (development, production, test, etc.) The example below sets the default log level to "Information", which means that any log messages with a level of "Information" or higher will be logged. Similarly, the Microsoft.AspNetCore namespace is set to "Warning".
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
appsettings.Development.json
appsettings.Development.json has heavy similarities with appsettings.json, however, it is used to customize or override the default settings specifically for the development environment. For example, in the configuration below the Microsoft.AspNetCore namespace is overridden to have a log level of "Information".
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Information"
}
}
}
Program.cs
In a .NET project, Program.cs (also known as the dependency injection container) serves as the entry point for the application. When the application is launched, the runtime looks for the Main method defined in the Program.cs file and executes it. The Main method sets up the application, configures services, and starts the application's execution.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// Replace in production environment.
// app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
WeatherForecast.cs
WeatherForecast.cs is a sample file included with the ASP.NET Core Web API template. It is the class definition used for the Weather Forecast data we previously fetched.
namespace API;
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
}
WeatherForecastController.cs
The WeatherForecastController.cs file is the corresponding controller to WeatherForecast.cs. It demonstrates how controllers in ASP.NET Core handle incoming requests, execute the necessary logic, and return the appropriate responses.
using Microsoft.AspNetCore.Mvc;
namespace API.Controllers;
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
EShop.sln
As previously discussed a solution is a container for organizing and managing multiple projects.
Note: While it is technically possible to manually edit the solution file using a text editor, it is generally not recommended or necessary.
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API", "API\API.csproj", "{67A9CC8E-2C90-4233-98DC-165C01B759CA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{67A9CC8E-2C90-4233-98DC-165C01B759CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67A9CC8E-2C90-4233-98DC-165C01B759CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67A9CC8E-2C90-4233-98DC-165C01B759CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67A9CC8E-2C90-4233-98DC-165C01B759CA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal