Open a terminal and use dotnet --help
to see available commands. Additionally, use dotnet new --help
to view options available to the new project command.
Run the following command to view every type of project template for your SDK:
dotnet new --list
A solution is a collection of projects. It is the glue that binds all of the individual projects into a logical unit.
dotnet new sln
ASP.NET Core MVC is the Model-View-Controller architecture for the ASP.NET framework.
dotanet new mvc
Open the Rider Project Launcher by opening the application without selecting an existing project. At the top, there will be a button to create a New Solution. Click it, and then select ASP.NET Core Web Application under the .NET/.NET Core section. The screen should look similar to the one below.
From here, you can specify the Solution Name and Project Name and it will create both the solution file and the project files for you. The Auth selector will allow you to choose a form of authentication that the project will automatically set up upon creation. By selecting Individual authentication, for example, the project will set up a database, user models, and a migration DTO.
New ASP.NET Core MVC project with individual authentication
/Solution
/Project
/Dependencies
/.NET 6.0
/Imports
/Properties
launchSettings.json
/Areas
/Identity
/Controllers
/Data
/Models
/Views
/Shared
/wwwroot
/css
/js
/lib
appsettings.json
appsettings.Development.json
Program.cs
launchSettings.json
which specifies how the app is launched when you use dotnet run
in the console or press the play button in an editor.DbContext
files live. These are the files that make up the connection and configuration of the application’s data source.The Program.cs
file contains all of the instructions to start the application.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using TestApp.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
builder.Services.AddDbContext<>()
— This is the method to establish a connection string with the data source, which in this case, is SQLite. The connection comes from the Configuration
class which pulls from appsettings.Development.json
or appsettings.json
respectively.builder.Services.AddDefaultIdentity<>()
— This method establishes a default Identity using Entity Frameworks data store. This is the authentication for user login.builder.Services.AddControllerWithViews()
— This will look through the Controllers folder and add all controllers that have views to the services list. This is an automation to adding the controllers manually. It uses dependency injection to add the controllers as dependencies.app.UseMigrationsEndPoint()
— If the app is in “Development Mode”, it will check if the database has any pending migrations and will apply them if needed. If it is not in development mode, throw an error to /Home/Error
.app.UseHttpsRedirection()
— Redirect users to the HTTPS protocol if accessing the site via HTTP.app.UseStaticFiles()
— This enables access to the files in wwwroot
.app.MapControllerRoute()
— This defines the routes for accessing various views on the application and which controllers to pull form. The default
route (which defines the starting page when going to the root URL for the application) is mapped to the Home
controller, which through naming conventions, knows to look for Controllers/HomeController.cs
.app.MapRazorPages()
— This will scan for Razor pages and map their associated routes. Because this is technically a different routing configuration, the Razor routes should not contain similar names to the Controller routes.HomeController.cs
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using TestApp.Models;
namespace TestApp.Controllers;
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel {RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier});
}
}
public HomeController(ILogger<HomeController> logger)
— This is a the constructor that brings in ILogger
of type HomeController
. ILogger is the default logging system inside .NET Core. The constructor brings in a logger and assigns it to a private immutable class variable.public IActionResult Index()
— This is the default action. You should always have an Index Action on your controllers because (by default) the default route for each controller is always mapped to the Index action. This can be changed, however, in Program.cs
. This method just returns the View, which through naming conventions, knows to look for Views/Home/Index.cshtml
.public IActionResult Privacy()
— This is another action that returns the appropriate view if the Privacy route is accessed. By naming convention, the View()
method will look for Views/Home/Privacy.cshtml
.public IActionResult Error()
— This will return a special view that pulls from the ErrorViewModel
. The decorator above the this method tells the framework that if this particular route is accessed, do not cache this page in the browser. That way it always has the latest information.Models in ASP.NET are just about displaying data. They are used as a middle layer between Data Transfer Objects and Controllers. They are a place to manipulate the data that you retrieve from the database before the Controllers have access to it.
ErrorViewModel.cs
namespace TestApp.Models;
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
Views/Shared/_Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>@ViewData["Title"] - TestApp</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css"/>
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true"/>
<link rel="stylesheet" href="~/TestApp.styles.css" asp-append-version="true"/>
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">TestApp</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
<partial name="_LoginPartial"/>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2022 - TestApp - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
@code
— Any code that has an @
symbol before it will be rendered as C# code. This is considered part of the Razor Syntax, which is a small language of symbols that tell the framework to recognize parts of the code as C# instead of HTML inside the views.
<partial name="_LoginPartial"/>
— This is essentially an injection of cshtml code into this specific part of the DOM. The name refers to the file in the same folder called _LoginPartial.cshtml
.
Views/Shared/_LoginPartial.cshtml
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @User.Identity?.Name!</a>
</li>
<li class="nav-item">
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new {area = ""})">
<button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
</li>
}
</ul>
This will add links to the navigation bar based on if the user is logged in or not. If you are not logged in, the view will show to links to Register and Login, but if you are logged in, it will display your name and a link to logout.