When you start learning a programming language, one of your first exercises will probably be to write a “Hello World” application to figure out the basic concepts. This exercise works well if you’re writing a simple console program that will only print out the greetings on the screen.
However, once you move onto learning to write web apps using a new framework, such as ASP.NET Core, such a simple code is not enough — partially because web apps are more complex. And also because, right off the bat, the tools and frameworks used for writing web apps try to introduce advanced techniques and approaches for building and maintaining them once they scale.
It all can seem like too much for a beginner. So, here we are going to take apart the default ASP.NET Core solution template piece by piece, then figure out the purpose of each piece and how exactly it works.
Please note that this isn’t a full-scale tutorial on all the aspects of creating web apps in ASP.NET Core. Rather, it is a short guide where you can check why there is a particular part added to your project or find a piece of code and a link to the relevant documentation that explains it in detail.
Let’s start with creating a new empty web app with the “Create a new project” wizard in Visual Studio.
Here is how this step should look:
When you press Next, the wizard will ask you to choose the names of the new solution and project and the folder to place the solution files in:
Tip #1: Place the project and the solution into separate folders. Choosing the same location for both is convenient only for very small applications. Once you start adding other layers to your solution (domain classes, data layers, API, etc.), having them in separate projects will be more practical.
Tip #2: Use the general name of your application for the name of the solution (like “MyCoolApp”) and add the “.Web” suffix for the project name (e.g., “MyCoolApp.Web”).
Most ASP.NET programmers start with the one selected on the screenshot, ASP.NET Core with Razor Pages, with the default authentication subsystem — Individual User Accounts stored locally. This is the template we are going to explore.
After finishing the steps described above you get a new solution with one project inside it. The structure of your web project (the only one in your solution for now) looks like this:
Let’s take a closer look at each part of your new project.
This is the first node in your project’s structure and possibly the less-used one. It is intended to automate the multiple steps necessary to connect a project to an external service (like Azure Storage or Application Insights). You can right-click on this node and select “Add connected service…” to run a wizard that will lead you through the process. Usually, it just adds necessary packages and gives you basic instructions on how to start using the service in your app. As I’ve already mentioned, there is a good chance you will not use this node in your project’s lifetime.
This element of your project structure contains all packets or other projects on which your project depends.
There are four main folders inside this node:
Please note that analyzers work only at compile time and do not affect your resulting application.
NB: You can use a “dotnet --info” console command to check the list of installed frameworks.
This is the main item in this node. It lists all NuGet packages you added (installed) to your project. If any of those packages depend on other packages, they will be installed automatically and listed as sub-nodes of the root-level packages. You can remove each installed package here (right-click / Remove).
This is the list of other projects your project depends on in the current solution. You can reference other projects using the “Add reference” command from the right-click menu.
This part contains different properties of your project that you can modify by double-clicking on this node in the Solution Explorer. Most of the properties there affect the compile- and debug-time behavior of your project.
The only item inside this node is a “launchSettings.json” file that contains the list of the launch profiles. Each profile defines how to run your project when you click on the “Run” button in Visual Studio.
This folder was added because the “Authentication” option was turned on when you created your project.
In addition to the core authentication/authorization packages (which is called ASP.NET Core Identity), the default template also adds the “Microsoft.AspNetCore.Identity.UI” package. This is a Razor-class library that contains all forms and partial views for authentication and user management: Log in, Registration, Reset Password, User Profile, and many others. All these forms will use your layout (defined in “Pages/Shared/_Layout.cshtml”) and so will match your website’s design.
However, you still might want to change some of those forms (or even all of them). In this case, you can use the Scaffold command and add the necessary files to your project. The scaffolded files will be added into the “Areas/Identity” folder.
As in the previous case, this folder appears in our new project because of the “Authentication” option turned on at the beginning.
By default, all user-related information (users, their roles, claims, etc.) is stored in a database accessed with Entity Framework Core ORM (object-relational mapping) framework. If you are not familiar with EF Core, you can find a lot of tutorials on Microsoft Docs.
The “Data” folder contains your DB context class named “ApplicationDbContext.” This class is derived from the “IdentityDbContext” class defined in the “Microsoft.AspNetCore.Identity.EntityFrameworkCore” assembly, and it includes all DB sets (tables) necessary to store user-related information.
You can use this class or create another DbContext class to add your models.
Finally, the “Data” folder contains the “Migrations” sub-folder where all your Entity Framework Core migrations are stored.
This folder contains all pages (forms) of your web applications. ASP.NET Core has two default approaches for content rendering: MVC (Model View Controller) and Razor Pages (which is, actually, a kind of MVC, where each controller and the corresponding view are stored together). Both approaches use Razor syntax that you can think of as HTML + C#.
Each Razor page is represented by a “.cshtml” file. The code related to it is stored in a so-called “code-behind” file with the same name and a “.cshtml.cs” extension.
From the start, the “Pages” folder contains a few default pages, such as Index (the home page of your web app), Privacy, and Error. Additionally, you can find the main layout file (_Layout.cshtml) and some partial views in the “Pages/Shared” folder.
NB: It’s a common practice to prefix the names of the layouts and partial views with an
Now that we’ve looked over all the main folders that go with the default ASP.NET Core application template, let’s take a closer look at the files stored in the project’s root folder. They are the most important part of the project.
This file defines the “Program” class with one static method, “Main,” which is the entry point of your web application.
The only purpose of this method is to define the host and then pass the control to the Startup class. For more information about the default host builder, take a look at an article about Generic Host on Microsoft’s Docs.
This is a JSON file that stores the application’s settings. The settings have a hierarchical structure and can be accessed with the Configuration object defined in the Startup class or in any other place of your program where you injected IConfiguration service. For example:
var defaultLogLevel = Configuration.GetValue<string>("Logging:LogLevel:Default");
The different levels of hierarchy are separated by the colon (
By default, in addition to “application.settings,” the ASP.NET Core template also includes an “application.Development.settings” file. The settings, defined in this file, are loaded only into the Development environment and are not available in production. To learn more about the “.settings” files and configuration in ASP.NET Core projects in general, please read this article on Microsoft’s Docs.
This is the final part of the ASP.NET Core project’s structure. The “Startup” class serves three main purposes:
It performs all initialization tasks (setting application-wide constants, DB seeding, migrations, etc.).
It registers all services used in this project in the DI (dependency injection) container.
It defines the middleware pipeline of your web-application.
This class contains a lot of code (as for a project that has just been created) from the very beginning and will become even bigger when you start adding new features to your application.
We will take a look at it in more detail in a next article (coming soon), so stay tuned.
Subscribe to blog's updates. You will get notifications about new posts, and only them.