2022
ASP.NET Basics

ASP.NET Basics

Translated from German using DeepL and ChatGPT.

Date: August 2022
Reading time: 12 minutes


This blog post, explains what ASP.NET is and what types of projects can be created with it.

.NET

.NET is a development platform by Microsoft for building apps. The framework is free, cross-platform, open-source, object-oriented, and is considered one of the most efficient today.

Key Facts

Initial Release Date: End of 2000
Developer: Microsoft
Current Version: 6.0.3
Programming Languages: C#, F#, Visual Basic, C++

ASP.NET

ASP.NET (Active Server Pages Network Enabled Technologies) is a web framework for creating dynamic HTML, CSS, and JS web apps, applications, and services. It has been available since 2002.

The advantages of ASP.NET include:

  • Reduced development time
  • Out-of-the-box features
  • Simplicity
  • Security
  • Customizability
  • ...

ASP.NET applications consist of two files:
The Program.cs configures, builds, and starts the application.
The appsettings.json file contains the configuration, including allowed hosts, logging information, and connection strings. These values are used in Program.cs but can also be accessed by models.

Learning

If questions arise about specific points regarding ASP.NET, they can usually be clarified quickly.
For beginners, the Microsoft tutorials in video format are recommended: https://dotnet.microsoft.com/en-us/learn/aspnet (opens in a new tab)

Models

When creating a project in Visual Studio, you'll encounter several options. In this section, I'll explain each model.

Models

Web Forms

Documentation: https://docs.microsoft.com/en-us/aspnet/web-forms/ (opens in a new tab)

What is Web Forms?

Web Forms applications are called through the browser. Pages are written with HTML, client-side scripts, server controls, and server code. Upon request, everything is compiled and executed by the framework.
A Web Form page consists of a file for both code and markup. In Visual Studio, Web Forms development is very user-friendly, which is its biggest advantage. Elements can be dragged and dropped, and pages can be edited via an editor. It's also easy to set properties, methods, and events.
However, Web Forms is rarely used today. The approach is outdated, and tutorials are mostly obsolete.

What

Installation

When creating a new project, you need to select the appropriate template.

Installation

In a later step, you can choose Web Forms.

Installation Two

If Web Forms is not listed, you need to install two things under ASP.NET web development:

  • .NET Framework project and item templates
  • Additional project templates

Details

MVC

Documentation: https://docs.microsoft.com/en-us/aspnet/core/mvc/overview?view=aspnetcore-6.0 (opens in a new tab)
Tutorial: https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-6.0&tabs=visual-studio (opens in a new tab)

What is MVC?

MVC is a widely used pattern that divides the project into Models, Views, and Controllers.
The big advantage is that you can create both GUIs and APIs within the same project. MVC is the modern project type and has been around the longest. Because of this, there are many projects that follow this approach.

MVC

Installation

MVC Installation

Example

This example demonstrates what is needed to display a page.

Often forgotten is that MVC doesn't consist of just three parts. A request must first be routed to a controller.
In ASP.NET, routing can be found in Program.cs.
This file describes how the URL should look when the page is called.

Program.cs
app.MapControllerRoute(
	name: "default",
	pattern: "{controller=Home}/{action=Index}/{id?}");

If the request is sent with the URL /Home/Index/2, the Index method in the HomeController will be executed with the parameter 2.

Here, we assume a URL like /Welcome/kay/3. It's important to adjust the route accordingly.

Controllers/HelloWorldController.cs
using Microsoft.AspNetCore.Mvc;
 
namespace MvcMovie.Controllers
{
	public class HelloWorldController : Controller
	{
		public IActionResult Index()
		{
			return View();
		}
 
		public IActionResult Welcome(string name, int numTimes = 1)
		{
			ViewData["Message"] = "Hello " + name;
			ViewData["NumTimes"] = numTimes;
			return View();
		}
	}
}

After the code in the Welcome method is executed and ViewData is filled, the View method is called, which renders the corresponding view.

Views/HelloWorld/Welcome.cshtml
@{
	ViewData["Title"] = "Welcome";
}
 
<h2>Welcome</h2>
 
<ul>
	@for (int i = 0; i < (int)ViewData["NumTimes"]!; i++)
	{
		<li>@ViewData["Message"]</li>
	}
</ul>

In the view, besides the HTML, the @ symbol is used to inject C# code.
In this case, a loop is used to display the name multiple times.

Model

In MVC, there are several useful features related to the model.

Entity Framework

When working with models, it's also useful to use Entity Framework (EF).
EF allows you to generate a database from the code or generate code based on an existing database. There are two approaches: Model First and DB First. Since I am using the Model First approach in my current project, I will explain this here.

Example: https://docs.microsoft.com/en-us/ef/core/get-started/overview/first-app?tabs=netcore-cli (opens in a new tab)

I first created the corresponding models. After that, I used the Package Manager Console to create and apply a migration.

Package Manger Console
Add-Migration InitialCreate
Update-Database

Line 1 generates a Migrations/{timestamp}_InitialCreate.cs file.
Line 2 uses the generated migration to update the database.

Context

A Context class was created during the process.
This class contains the DbSet<Nistbox.Models.Nistbox> properties, which represent the data in the database.

The project is about birdhouses (Nestboxes).

Data/NestboxContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Nestbox.Models;
 
namespace Nestbox.Data
{
	public class NestboxContext : DbContext
	{
		public NestboxContext (DbContextOptions<NestboxContext> options)
			: base(options)
		{
		}
 
		public DbSet<Nestbox.Models.Coordinates>? Coordinates { get; set; }
		public DbSet<Nestbox.Models.Log>? Log { get; set; }
		public DbSet<Nestbox.Models.Nestbox>? Nestbox { get; set; }
	}
}
Dependency Injection

The NestboxContext can be used in controllers via Dependency Injection (DI).

NestboxesControllers.cs
private readonly NistboxContext _context;
 
public NistboxesController(NistboxContext context)
{
	_context = context;
}

To enable this, the following code was added to Program.cs.

Program.cs
builder.Services.AddDbContext<NistboxContext>(options =>
	options.UseSqlServer(
		builder.Configuration.GetConnectionString("NistboxContext") ??
		throw new InvalidOperationException("Connection string 'NistboxContext' not found.")
	)
);
Connection String

To establish a connection to the database, a connection string is needed.

appsettings.json
"ConnectionStrings": {
	"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-Nestbox-CONNECTION-KEY;
	Trusted_Connection=True;MultipleActiveResultSets=true",
	"NistboxContext": "Server=(localdb)\\mssqllocaldb;Database=Nestbox.Data;Trusted_Connection=True;
	MultipleActiveResultSets=true"
},
Initial Create

This file is responsible for creating the data in the database.

20220714140140_InitialCreate.cs
// ...
protected override void Up(MigrationBuilder migrationBuilder)
{
	migrationBuilder.AlterColumn<float>(
		name: "Longitude",
		table: "Coordinates",
		type: "real",
		nullable: false,
		oldClrType: typeof(int),
		oldType: "int");
 
	migrationBuilder.AlterColumn<float>(
		name: "Latitude",
		table: "Coordinates",
		type: "real",
		nullable: false,
		oldClrType: typeof(int),
		oldType: "int");
}
// ...
Alternatives

As mentioned earlier, there is also the DB-First approach. With this approach, you first create the tables in the database and then generate the code from them.
You can read more about it here: https://docs.microsoft.com/en-us/ef/ef6/modeling/designer/workflows/database-first (opens in a new tab)

View

C# Code

As mentioned earlier, C# code can be written in views. This opens up a lot of possibilities. More information can be found in the documentation: https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/views/ (opens in a new tab)

Partial Views

Another advantage of MVC is that it allows for clean views, where the data only needs to be displayed. However, such views can become very large and hard to manage.
To avoid this, parts of a view can be outsourced. This is done by default.
To understand how, you can look at the layout file. It contains @RenderBody(), which inserts the content of the page into the layout.

Shared/_Layout.cshtml
<div class="container">
	<main role="main" class="pb-3">
		@RenderBody()
	</main>
</div>

Such partial views can be identified by the horizontal lines.
You can also create and integrate your own partial views.

Partial Views

Shared/_Layout.cshtml
@Html.Partial("_NavBar")

Controller

In controllers, you can do a lot. It's also important how you communicate with the view. This section explains how to do this.

Passing Data into Views

When logic is handled in the controllers and needs to be displayed in the views, the question arises: how can you pass data into the views?
There are several ways to do this.

MoviesController.cs
ViewData["Movie"] = movie;
return View();
Random.cs
<h2>@( ((Movie) ViewData["Movie"]).Name )</h2>
View Method

Later, you can pass the value directly via the View method.

MoviesController.cs
return View(movie);
Random.cs
<h2>@Model.Name</h2>
ViewBag

The issue with the previous two methods is that passing multiple data values can be cumbersome. Therefore, ViewBag is used.

MoviesController.cs
ViewBag.Title= "Hello World";
return View();
Random.cs
<h2>@ViewBag.Title</h2>
Action Results

View is just one of the helper methods. Here are a few more.

Action Results

MoviesController.cs
namespace Vidly.Controllers
{
	public class MoviesController : Controller
	{
		// GET: Movies
		public ActionResult Random()
		{
			var movie = new Movie() { Name = "Shrek" };
			return View(movie);
			//return Content("Hello Wolrd");
			//return HttpNotFound();
			//return new EmptyResult();
			//return RedirectToAction("Index", "Home", new { page = 1, sortBy = "name" });
		}
	}
}

Blazor

Documentation: https://docs.microsoft.com/en-us/aspnet/core/blazor/?WT.mc_id=dotnet-35129-website&view=aspnetcore-6.0 (opens in a new tab)
Tutorial: https://dotnet.microsoft.com/en-us/learn/aspnet/blazor-tutorial/intro (opens in a new tab)
Website: https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor (opens in a new tab)

What is Blazor?

Blazor distinguishes between two types of project.

On the one hand, there is Blazor Server. Blazor Server is extremely unique. It combines server-side and client-side rendering. This means that it can put together the pages very quickly, but still remains very interactive. The user therefore receives the website quickly and can also add elements, such as in React or Angular. C# is used as the front-end language instead of JS. The markup and code is written in Razor files.
This combination of server-side and client-side rendering makes Blazor Server one of the fastest projects.

However, there is also Blazor WebAssembly. Such projects are only loaded on the client side. In addition, WebAssembly applications are poorly protected . You are therefore not allowed to use keys, establish direct database connections and not even the appsettings file is desired. If you want to work with data, an additional API is required.
In addition to these disadvantages, there is also an important reason to use it. Such projects can be used offline after a download of approx. 10 megabytes. For the user, it then looks like a desktop application.

Installation

When installing Blazor, it is important that you select the desired project.

blazor

blazor-web

Example

In this case I show how powerful Blazor Server is.

This Razor file is enough to build a fully functional counter.

Counter.razor
@page "/counter"
 
<PageTitle>Counter</PageTitle>
 
<h1>Counter</h1>
 
<p role="status">Current count: @currentCount</p>
 
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
 
@code {
	private int currentCount = 0;
	private void IncrementCount()
	{
		currentCount++;
	}
}

Razor Pages

Tutorial: https://docs.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/?view=aspnetcore-6.0 (opens in a new tab) Documentation: https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-6.0&tabs=visual-studio (opens in a new tab)

What is Razor Pages?

With the MVC model, you had to take care of a lot of things in different places. With Razor Pages you should be able to create pages more productively . According to Microsoft, Razor Pages is the newer and simpler model like MVC. Each file represents an endpoint. And the HTML can be output elegantly using C#.
This project type is particularly recommended for static applications. This is because server-side rendering is extremely fast.

Installation

Here you can already make use of the Razor Pages features after the ASP.NET Core Web App installation.

razor

Example

As you can see from this simple example, a page consists of two files.

The cshtml file represents the page.

Page/Index.cshtml
@page
@model IndexModel
@{
	ViewData["Title"] = "Home page";
}
 
<div class="text-center">
	<h1 class="display-4">Welcome</h1>
	<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

The data is provided in the cshtml.cs file.

Page/Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
	public class IndexModel : PageModel
	{
		private readonly ILogger<IndexModel> _logger;
 
		public IndexModel(ILogger<IndexModel> logger)
		{
			_logger = logger;
		}
 
		public void OnGet()
		{
		}
	}
}

In this further, somewhat larger example, you can clearly see how the two files interact.

razor-example

In the nested cshtml.cs file, the data is handled and delivered to the page.

Edit.cshtml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
	public class EditModel : PageModel
	{
		private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
		public EditModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
		{
			_context = context;
		}
 
		[BindProperty]
		public Movie Movie { get; set; } = default!;
 
		public async Task<IActionResult> OnGetAsync(int? id)
		{
			if (id == null || _context.Movie == null)
			{
				return NotFound();
			}
			var movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
			if (movie == null)
			{
				return NotFound();
			}
			Movie = movie;
			return Page();
		}
 
		// To protect from overposting attacks, enable the specific properties you want to bind to.
		// For more details, see https://aka.ms/RazorPagesCRUD.
		public async Task<IActionResult> OnPostAsync()
		{
			if (!ModelState.IsValid)
			{
			return Page();
			}
 
			_context.Attach(Movie).State = EntityState.Modified;
 
			try
			{
				await _context.SaveChangesAsync();
			}
			catch (DbUpdateConcurrencyException)
			{
				if (!MovieExists(Movie.ID))
				{
					return NotFound();
				}
				else
				{
					throw;
				}
			}
 
			return RedirectToPage("./Index");
		}
 
		private bool MovieExists(int id)
		{
			return (_context.Movie?.Any(e => e.ID == id)).GetValueOrDefault();
		}
	}
}

The cshtml files contain, among other things, ordinary HTML. However, the data from the controller can be used here.
Here you can see again that the different concepts do not differ from each other in all respects.

Edit.cshtml
@page
@model RazorPagesMovie.Pages.Movies.EditModel
 
@{
	ViewData["Title"] = "Edit";
}
 
<h1>Edit</h1>
 
<h4>Movie</h4>
<hr />
<div class="row">
	<div class="col-md-4">
		<form method="post">
			<div asp-validation-summary="ModelOnly" class="text-danger"></div>
			<input type="hidden" asp-for="Movie.ID" />
			<div class="form-group">
				<label asp-for="Movie.Title" class="control-label"></label>
				<input asp-for="Movie.Title" class="form-control" />
				<span asp-validation-for="Movie.Title" class="text-danger"></span>
			</div>
			<div class="form-group">
				<label asp-for="Movie.ReleaseDate" class="control-label"></label>
				<input asp-for="Movie.ReleaseDate" class="form-control" />
				<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
			</div>
			<div class="form-group">
				<label asp-for="Movie.Genre" class="control-label"></label>
				<input asp-for="Movie.Genre" class="form-control" />
				<span asp-validation-for="Movie.Genre" class="text-danger"></span>
			</div>
			<div class="form-group">
				<label asp-for="Movie.Price" class="control-label"></label>
				<input asp-for="Movie.Price" class="form-control" />
				<span asp-validation-for="Movie.Price" class="text-danger"></span>
			</div>
			<div class="form-group">
				<input type="submit" value="Save" class="btn btn-primary" />
			</div>
		</form>
	</div>
</div>
 
<div>
	<a asp-page="./Index">Back to List</a>
</div>
 
@section Scripts {
	@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

API

The API model is also worth mentioning at this point.

There is no GUI in such projects. You create an application that returns a json (or other data) in response to requests. In this way, the data is also well protected.
The purpose of this is that another application, such as a React project, makes use of the API.

You should not create such a project if you want to create an application in a short space of time. Because for a user to be able to operate the app, it must first be used by a frontend.
(Unless you want the user to send the data in the request body. However, this is not suitable for the DAU (opens in a new tab)).

Conclusion

In my current project, I am working with the MVC model. So far, I have only had positive experiences with it. In my opinion , MVC makes it possible to work efficiently. In addition, the strict separation keeps everything clean and clear.
However, I have also tried the other models. So far, I can't find anything wrong with them either.

You can't say that one of the models is better than the others. Depending on the project, there is a variant that makes the most sense. It is therefore helpful if you know the concepts and can differentiate between them.
Note: You can also combine projects if necessary.

Here is an overview of the most important points.

Project typeAdvantagesDisadvantages
Web FormsDrag and DropNo longer modern, outdated tutorials, should no longer be used
MVCHigh speed, GUI and API possible in one project, well-known concept, widely usedAlready somewhat older, Blazor Server as a modern alternative
Blazor ServerBest speed, server-side and client-side rendering, high interactivity for the userNot optimal for static pages
Blazor WebAssemblyOffline access after download (approx. 10 MB)Client-side only, security risks, requires API usage
Razor PagesHigh speed, fast page creation, best choice for static contentServer-side bound
APIVery fast, easy to implement, high securityNo GUI, must be used by other applications, not directly comparable with the other project types