In my last post I talked about Entity Framework Core Code-First approach. Today, I am going to post a tutorial on how to create a ASP.NET .NET Core MVC 3.1 web application and demo the code-first approach.

We are going to create a web application called SKBookClub which means Stephen King Book Club (Stephen King being one of my favorite authors!). It will be an ASP.NET MVC web app using ASP.NET Core 3.1. Since we will use a code-first approach, we will create the database and the database objects from the code itself.

This is going to be a very long post so I am going to skip some obvious steps and also the basic concepts. But I will provide the entire source code that I am using so that you can refer it if you are following along or directly use it. Also, feel free to post questions if you get stuck anywhere or you have any other questions, I would be happy to help. Leave a comment and I will respond. Here is the path of the source code – GitHub Path for SKBookClub

Getting Your Machine Ready

I want to make sure that you have everything ready to follow along with this tutorial. As mentioned, we are using ASP.NET Core 3.1 in the demos, and for this version of .NET Core, you will need to have Visual Studio 2019 installed. Of course, a browser is also required. I am running this on a Windows machine. If you’re using any other operating system, things will still work for you. Remember, ASP.NET Core is cross platform. You can download the Visual Studio 2019 from here and the .NET Core 3.1 SDK from here. For Visual Studio, you can download the free community version. The following is the webpage we will eventually create after this exercise –

This is the webpage we will eventually create

Module 1: Setting up an MVC Application

Step 1: When you open up Visual Studio 2019, it should prompt you with a ‘Get Started’ window. You can select Create a new project. The other way is to go to Visual Studio 2019 File menu and select New > Project.
In either case select ASP.NET Core Web Application.

Default Get Started window when you open up Visual Studio 2019
Select ASP.NET Core Web Application

Step 2: You will get an option to name the project and select the location. Name the project as SKBookClub. It is imperative that you use this exact name including capitalization, so that the namespaces match when code is copied and pasted.

Provide the name as SKBookClub

Step 3: In the next page, ensure that .NET Core is selected and and ASP.NET Core 3.1 is selected in the dropdowns. Then select Empty.
Let me explain why I selected Empty instead of selecting Web Application (Model-View-Controller). You can select this option as well and follow through the demo.
Different templates exist depending on the .NET Core version that you have selected at the top of the window. Selecting a particular template will generate various files and folders specific to that template. In case of MVC, it will create the Model, View and Controller folders and some relevant files. In real life you would end up using a specific naming convention for your files, therefore I prefer starting up with a blank slate and make my way creating the necessary folders and files.

You can select the Web Application (Model-View-Controller) option

Step 4: Hit Create. This should generate the project and it should look something like below. Run the application once and you should get ‘Hello World’ in the web browser

Generated project structure

Step 5: Go to Startup.cs and add the service collection method AddControllersWithViews() in the ConfigureServices() method. Also add app.UseHttpsRedirection() and app.UseStaticFiles() in the Configure() method. Refer the below screenshots. Build the application once to verify there is no error.
Before we move ahead, let me quickly explain both the code snippets. AddControllersWithViews() adds the MVC Controller services that are common to both Web API and MVC, but also adds the services required for rendering Razor views. In .NET Core 2.1 this was AddMvc() which got replaced in .NET Core 3.0.
I want my application to run on HTTPS, so I’m going to use the middleware that redirects HTTP requests to HTTPS using app.UseHttpsRedirection()
Also, I want to make sure that my application will also serve static files, like, images, JavaScript files, CSS files, and so on. By default, my application won’t do that. I need to plug in middleware that will do that, that’s why I will call the UseStaticFiles() middleware. By default, the UseStaticFiles() will search in a directory called wwwroot for static files (we can change that too)

Modify the startup.cs

Module 2: Creating the Model

Since this tutorial is all about code-first approach, creating the model is the most important aspect of this tutorial. Let me give a view how the database design would look like so that the model can be created accordingly. So the database is going to look more or less like the following (don’t bother about the datatypes)

Database diagram

Step 6: Add a folder called Model to the project. Just to remind, MVC requires certain folders and files to be named specifically. Add 2 class files which will be simple POCO classes called Book.cs and Genre.cs. Add the code for Book class and Genre class based on the database design above.

Book.cs and Genre.cs

Step 7: Add 2 repository classes – IBookRepository.cs and IGenreRepository.cs in the model folder
Creating the domain class aren’t enough. We’ll also need classes that will perform actual data persistence. This will be handled by creating a repository class, which is a class that abstracts away the details of how persistence is happening. The model should expose a simple API towards the rest of the application. Well, that is what you see here. We’re looking here at the contract, the interface of the repository called IBookRepository. This interface defines what our repository will be able to do initially. It defines a method, GetAllBooks, which is returning an IEnumerable in book, containing probably all books in the datastore. Next, it also defines a method called GetBookById, which accepts the ID of the book we’ll want to retrieve.

IBookRepository.cs and IGenreRepository.cs

Module 3: Creating the Controller

Step 8: Add a new folder in the project and name it as Controllers (As said earlier, it is a convention that ASP.NET Core MVC will look for). Next, add a controller file. You can right click on the Controllers folder, select Add and click Controller. I prefer, Add, New Item, select Web, and then you’ll find Controller Class – Empty; name it BookController.cs

Add BookController.cs

Step 9: Add the following code in the BookController.cs file. You can take the code directly from the code file provided.

BookController.cs

Now, the BookController is really the first place where we’ll actually benefit from the dependency injection system that comes with ASP.NET Core by default. We will need access to our repositories and data, that is, controlled via the repositories. So what I did was introduce a private field for both the book and the genre repository and used the interfaces for that. I created a private, readonly IBookRepository and called it _bookRepository. I did the same for the genre repository. I initialized the fields using the constructor. To that constructor, I passed an IBookRepository and an IGenreRepository. I set my local _bookRepository and _genreRepository to the one that is going to be injected. For handling the incoming request, I added an action method which is a public method and is returning a view. Since the result of this method will be a view, I used something called a ViewModel that I will define down below.

Module 4: Creating the View

Step 10: This is the section where I will try to keep it short. The main view which would display the page is called the List.cshtml. Create a new Folder called Views and add a subfolder called Book. I created the subfolder Book as this project will end up becoming a bigger application outside of this tutorial.
Now, in the Book Folder create a New Item and select Razor Page; name it List.cshtml

Create the List.cshtml

Step 11: Add the following code in the List.cshtml file. A .cshtml file is a Razor file that contains C# mixed with HTML code

Copy the code for List.cshtml file from the source code provided


I generally avoid using ViewBag in my views. A better approach is using something called a view model. A view model is a class that will contain all the data for a view, and the controller will build up that view model and pass it to the view. The next module explains creation of the view model.

Step 12: The next step is to create the supporting view files (like the ViewImports, ViewStart and Layout) and styling the view using css. I will skip explaining these files. You can directly take the files from the source code
Create a Shared folder under the Views folder and add _Layout.cshtml. Create the files _ViewImports.cshtml and _ViewStart.cshtml under the Views Folder. Take the code from the source code files.

This is how the View folder should look like

Step 13: Now copy the entire wwwroot folder from the source code file and place it to your project. This contains the css file and the picture files (logo and background) used in the website.

wwwroot folder

Module 5: Creating the ViewModel

Step 14: Lets go ahead and add a ViewModel class. Add a new folder in the project and name it ViewModels. Add a class file and name it BooksListViewModel.cs. Add the following code to it.

BooksListViewModel.cs

So I added a new view model that is just a plain class. In the BooksListViewModel.cs I just added a property for each type of data that we will need in our view. In our case, we need the IEnumerable of Books and the CurrentGenre. Now, take look back at the controller where we had already used the BooksListViewModel

Step 15: Go ahead and build the application. At this point there should not be any error and the application should get built successfully.

Module 6: Adding EF Core to the Application

Now that we have almost set up the application, the next step is to make the application EF Core enabled. In order to do that we have setup these 4 things –

Setting up EF Core in the Application

Step 16: Starting with .NET Core 3, it’s required that we add references to Entity Framework Core NuGet packages. When using EF Core 3 and ASP.NET Core 3, we need to add the correct NuGet packages. Right Click Dependencies, go to Manage NuGet Packages. And then we need to search for Microsoft.EntityFrameworkCore.SqlServer Install that. We also need to bring in the Microsoft.EntityFrameworkCore.Tools package

Add NuGet packages

Step 17: Next we will add the DbContext class. Since this is associated with models, so we’ll add it under the Models folder. Add a new class. Name it AppDbContext.cs. Add the code from the source code AppDbContext class file. Let me explain the code.

Copy the code from AppDbContext.cs file from the provided source code

The point is to make sure that it inherits from the DbContext class. By default, Visual Studio won’t find that, therefore I used using statement for Microsoft.EntityFrameworkCore. A DbContext must have an instance of DbContextOptions for it to execute. We can do that by using this constructor –
public AppDbContext(DbContextOptions options) : base(options)
Next, we will indicate which entities it is going to manage. Behind the scenes, this will also map to a database table in the actual database. Since it is going to manage Book and Genre, we created new DbSet in Book and Genre –
public DbSet Genres { get; set; }
public DbSet Books { get; set; }

Step 18: Modify the appsettings.json file to add the connection string –
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\mssqllocaldb;Database=SkBookClub001;Trusted_Connection=True;MultipleActiveResultSets=true"

In ASP.NET Core MVC, the connection strings are not written in a Web.config file which we’ve been doing for years with plain ASP.NET or plain ASP.NET MVC. Instead, we placed the connection string in the appsettings.json file. In the ConnectionStrings, we have the DefaultConnection, which points to a local database which we haven’t created yet. I placed a database on my LocalDB server. LocalDB is an option that you can install together with Visual Studio. It gets installed by default typically. I provided a database name, and I used a trusted connection, so I will not use SQL Server Authentication.

Step 19: Modify the Startup.cs file with the code from the source code file provided. I will explain the code below.

Copy the code snippet from the source code file

Basically I modified the statup.cs file for the application to know about Entity Framework Core. In the ConfigureServices method, I added the correct services so that our application knows about Entity Framework Core. On the services collection, I called the extension method AddDbContext, which by the way came with the NuGet packages that we added. I pass the type of our DbContext, that is the AppDbContext, and then I also specify in the options that it needs to use SQL Server. Don’t forget to add the using statements; Visual Studio will tell you what to add. Now the application knows it needs to use SQL Server. By default, the appsettings file gets read out, and it will arrive in an instance of IConfiguration, which gets passed into the application via constructor injection. Now in this IConfiguration object, I’ll have access to the properties, which are set in appsettings. Now using configuration, I can ask my configuration to get the connection string. When I call Configuration.GetConnectionString, it will automatically read out the connection string from the appsettings and it will search for the connection string named DefaultConnection.
At this point go ahead and do a build; there should be no errors.

Module 7: Working with Data using EF Core

We have almost completed setting up the application. In the next steps we will set up the data in the code and go through steps to create the database, tables and push the data into the tables, all through the .NET code and Visual Studio IDE.

Step 20: Lets go back to the model and create the actual repositories for Book and Genre. Go to Models folder. Create 2 class files – BookRepository.cs and GenreRepository.cs. Copy the code from the source code provided. I will provide the explanation of the code.

BookRepository.cs – take the code from source code provided
GenreRepository.cs – take the code from the source code provided

The BookRepository implements the IBookRepository created earlier. The BookRepository is going to work with the AppDbContext. And I introduced a private readonly field for the AppDbContext – private readonly AppDbContext _appDbContext;. Since we registered our DbContext using AddDbContext on our services collection (in Startup.cs), this is also managed through the dependency injection container. Therefore, in our repository, we can now simply create a constructor, and through constructor injection we will get access to the AppDbContext in our BookRepository.
public BookRepository(AppDbContext appDbContext)
{
_appDbContext = appDbContext;
}

Because of dependency injection, it’s now really simple to access the AppDbContext, which will be the intermediate between our code and the database. The BookRepository will use the DbContext for persisting and reading data from the database.
Next I implemented the interfaces – AllBooks, BooksOfTheWeek and GetBookById.
Take a look at the code and see what I am returning –
return _appDbContext.Books.Include(c => c.Genre).Where(p => p.IsBookOfTheWeek);
Here I used a LINQ query to get the books where the IsBookOfTheWeek is set to true. I used the where clause and I specified that I want to get the Books where the IsBookOfTheWeek property is actually true.

Step 21: Go back to the Startup.cs class and add the following lines of code. Also make sure the Configure() method is also same as the source code provided.

Add the lines of code in Startup.cs
Update the code from source code provided

In this line of code – services.AddScoped<IBookRepository, BookRepository>(); I’m registering the BookRepository in the container using services.AddScoped. I pass the interface and then the concrete implementation. The result of this call is that we can now, from anywhere, ask for an IBookRepository, and we will get back a fully instantiated BookRepository from the container

Step 22: There are different ways in adding data or “seeding” data into the database. One of the recommended way is to do it through the DbContext. So go to the AppDbContext.cs file and paste the code snippet shown below. Use the code provided in this tutorial.

Add the code to seed data in AppDbContext.cs

I’ve created an override of the OnModelCreating method. The OnModelCreating method is a method that we can also use to configure how the actual SQL Server database should be created, but it can also be used to seed data.

Step 23: At this point build the application once, if there are no errors, run the application using the IIS Express button in the Visual Studio IDE. The default page that opens up would have the url something like this – https://localhost:44379/ But our view file is inside the book folder and is called List.cshtml. Therefore we have to browse to that location. Modify the url to say – https://localhost:44379/book/list. This should give the following error. This is a good thing because now we are sure the application is doing what it is supposed to do. It is not able to find the database that’s why it is throwing the error.

Module 8: Creating Database and Seeding the Tables

Code-First Approach using EF Core

In the code first approach, we aren’t managing the actual database ourselves. Instead, EF Core is doing that for us. EF Core comes with something called “Migrations” to do this. A migration will be created by EF Core. Basically it is just code that it will execute to bring the database model in sync with the domain model. Initially, this migration will create the code to create all the tables we need to have in the database to map to our domain entities. Creating migrations can be done through the Package Manager Console in Visual Studio. There are two commands, which we’ll need to remember in this context. Add-migration will be the command that generates the migration code that can bring the database in sync with the model that we have created. Then we run the update-database command for the SQL script code to get executed against the database. We can also use EF Core to populate the database with some initial data. In our application code, in the AppDbContext class, we are checking if some data is already in the database, if not then we can insert data into the Book table in the database. The way that we initialize the database with data has changed since ASP.NET Core 2.1. We can now use the HasData method to seed data through a migration. Lets go ahead and create the database, seed some data and finally run the application.

Step 24: Navigate to the Package Manager Console by going to View -> Other Windows -> Package Manager Console. Type add-migration initialMigration and hit enter

The Package Manager Console
Run the add-migration command

Looks something like this when t completes –

add-migration command successfully completed

Step 25: Next type the command update-database and hit enter. The command should execute successfully

update-database command executed successfully

Now lets see what really happened. First go to the Solution Explorer and take a look at it. You will see that a new folder was added to the application called Migrations. And inside the folder you can see there is a new class for initialMigration. It inherits from Migration and it has two methods, Up and Down. Up is really going to contain a code to bring the application’s database in sync with the application’s domain. Down is basically going to revert that migration.

Up and Down methods in the migration class


One you take a look at the Up method, you’ll see that it creates two tables, one for the Genre and one for Books. For each of these two tables, the columns and constraints such as primary keys have also been created. Further down, you can also see that it contains the insert statements as well.

Code for the Up method contains code for table creation and insert data

Step 26: Go to the SQL Server Object Explorer under the View menu. You’ll find the LocalDB instance. Browse through to the Books table and right click and select View Data. You should be able to see the data within the Books table

Browse through the table to view the data in the Books table

Step 27: At this point we have everything perfectly done and are ready to run the application. Go ahead and click IIS Express and modify the url to include books/list – https://localhost:44379/book/list.
…..and there’s your application!

Summary

So we finally come to end to this really long post. I tried to provide explanation at relevant places but if you have any questions feel free to drop a note and I shall try to help you out. Do provide feedback about this post.
Until next time – good luck with building an ASP.NET MVC Core application using the code-first approach