A Step-by-Step ASP.NET Tutorial for Beginners

bannerASP2

By Moshfegh Hamedani for Udemy

Interested in more than just a guide? Check out a full ASP.NET course. 

TABLE OF CONTENTS: CLICK TO JUMP TO A SPECIFIC SECTION

What We’re Going to Build

Setting Up the environment

Displaying the List of Videos

Step 1: Building the Model
Step 2: Generating the Database
Step 3: Populating the Table
Step 4: Creating a Page to Display Videos in the Database

Adding a New Video

Step 1: Creating a Page to Add a Video
Step 2: Saving the Video to the Database

Editing an Existing Video

Step 1: Creating a Page Populated with Video Details
Step 2: Updating a Video in the Database

Deleting a Video

Step 1: Creating a Page to Confirm Deletion
Step 2: Deleting a Video from the Database

Review


A Step-by-Step ASP.NET MVC Tutorial for Beginners

In this tutorial, I’m going to teach you the fundamentals of ASP.NET MVC 5 and Entity Framework 6.  

Before we get started, I’m assuming you already have some experience with C# and Visual Studio. At a minimum, you should be able to write code and have very basic understanding of databases. However, no prior knowledge of ASP.NET MVC or Entity Framework is required. So, let’s get started.

What We’re Going to Build

As part of this tutorial, we’ll be building a simple web application for a video rental store. We want the admins to have a page to see the list of all videos in the store, as well as the ability to add, edit and delete videos. I’m going to exclude advanced features such as dealing with the stock, renting a video or returning it, calculating cost, etc., so we can focus on the core concepts of ASP.NET MVC. I’ll be covering those advanced scenarios in my comprehensive ASP.NET MVC course that will be published on Udemy soon.

So, as part of building this app, you’re going to learn how to:

  • Create a data entry form to add, update and delete records in a database. In this tutorial, we’ll build a form for managing videos, but you can take what you learn from this tutorial and apply it in any real-world scenarios.
  • Display a list of records. Again, here we’ll display a list of videos, but you can apply what you’ll learn here to any real-world scenarios. You can use these techniques to display lists of tweets, photos, blog posts, and literally anything else.
  • Use Entity Framework to query or update your database. Entity Framework is an Object/Relational Mapper (ORM) that sits on top of a database. This frees you from having to work directly with database connections, writing SQL queries and commands, etc. You ask Entity Framework to load or save a set of objects, and Entity Framework will take care of all the dirty work for you.
  • Generate your database using code. This is what we call Code First workflow (more on this later).

By the end of this tutorial, you’ll have a good understanding of ASP.NET MVC and Entity Framework fundamentals. Not only will you be able to build simple applications, but you’ll also be able to follow other tutorials more easily. So, let’s get started.

Setting Up the environment

To build this application, you need Visual Studio 2013. Any edition would work. You can get a free community edition of Visual Studio here:

https://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx

Once you have Visual Studio ready, launch it. Then go to File > New > Project. In the New Project dialog, on the left side, under Templates, select Visual C# > Web. On the right side, select ASP.NET Web Application.

image15

In the Name field, type Beaver. This is the code name for our video rental store application. In the Location box, specify a location to create the files on the disk. Preferably, use a local drive and not a network drive. Otherwise, sometimes you may run into security or performance issues. Finally, click OK.

On the next page, select MVC from templates. On the bottom right, make sure Host in the cloud is not checked, as we’re not going to cover deployment in this tutorial.

image16

Next, wait a few seconds until Visual Studio creates your project template.

Now that our application is created, we can run it by pressing Ctrl+F5. Visual Studio will launch your browser and take you to an address like http://localhost:1234 where 1234 is the port number. The port number on your machine might be different from mine, but that doesn’t matter.

image10


Beginner’s Question: What is localhost? Every web application needs to be hosted by a web server. Localhost is a mini web server running on your machine. In the real world, you often publish an ASP.NET application to a full-fledged IIS server. Web hosting companies take care of installation of IIS for you. So you never have to worry about it. All you do is upload your files.


Now we have an application with some basic functionality. You can register a new account, log in, log out, change your password, etc. All this functionality comes with the ASP.NET MVC template. So, you never have to write code for these repetitive features that nearly every application needs.

Let’s test-drive our sample application. On the top right, click Register. Fill out the form with an email address and password, and click Register.

image14

Note that you’re automatically logged in with the email address you supplied.

image11

You can also log out.

All this functionality comes out of the box with a package called ASP.NET Identity. If the default registration form doesn’t work for you, you can always customize it. That is beyond the scope of this tutorial, and I’m going to cover it in my comprehensive ASP.NET MVC course.

Let’s recap: we built an ASP.NET MVC application using the template in Visual Studio. Now, it’s time to implement some functionality specific to our video rental store. Over the next few sections, in each section, we’ll add a new function to our application.

Displaying the List of Videos

The first feature I’d like to implement here is a page with a plain list of videos. It’s much easier to build this than a form to add or update a video. So, to build this page, first we need a database populated with some records.

The traditional workflow is to create a database, design the tables using table designers, and then generate domain classes based on these tables. This approach or workflow is called Database First. But in this tutorial, I’m going to teach you the modern way of working with a database. This approach is called Code First, which simply means code first, and let the tools create the database for you. Thus, we’re never going to use table designers to create our database.

At this point, you might ask, “What tooling do we need to auto-generate the database?” The answer is: Entity Framework, which comes automatically with our default ASP.NET MVC template.

Here is an overview of what we’re going to do in this section.

  1. We’re going to create a domain class that represents a video. This class is going to have properties such as Name, Description and Genre.
  2. We use Entity Framework to generate the database.
  3. We populate our table with some video records.
  4. We build a web page to display the list of videos in the database.

Step 1: Building the Model

Back to Visual Studio, go to Solution Explorer. If it’s not visible, open it from View > Solution Explorer. Right-click the Models folder in the project and select Add > Class… In the Add Class dialog, type Video in the Name field. Now, declare these properties in the Video class.

public class Video
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public Genre Genre { get; set; }
}
public enum Genre
{
    Comedy = 1,
    Horror,
    SciFi,
    Romance,
    Documentary,
    Kids
}

Here, we use the Id property to uniquely identify each video. This Id will be generated by the database.

Next, open IdentityModels.cs from the Models folder. This code is automatically generated as part of the project template. Inside this file, we have two classes: ApplicationUser, which represents a user, and ApplicationDbContext. A DbContext is an abstraction over the database which hides all the complexity of working with a database, such as opening and closing connections, running commands, reading and writing data, etc. Here is the auto-generated code for ApplicationDbContext:

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

Note the constructor of this class. The constructor calls the base constructor and passes “DefaultConnection”.

    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

DefaultConnection is the name of the connection string for the database and is declared in Web.config, which is the configuration file for our application. Let’s have a quick look at the connection string. Going back to the Solution Explorer, open Web.config in the project root.

Under <connectionStrings>, note the element with the name DefaultConnection. Look at the value of the connectionString attribute. This is the actual connection string to the database:

<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-Beaver-20150822102023.mdf;Initial Catalog=aspnet-Beaver-20150822102023;Integrated Security=True"

Let me break this down for you:

  • Data Source: specifies the instance of your SQL Server. LocalDb is a lightweight version of SQL Server that is used for development, which is automatically installed with Visual Studio 2013. So you don’t need a full installation of SQL Server on your machine to do your development.
  • AttachDbFilename: this is the path to the database file. Here DataDirectory represents the App_Data folder in your project. So if you look inside this folder, you’re going to see a file named aspnet-Beaver-xxxx. The value of xxxx depends on the date/time you create this project.
  • Initial Catalog: is the name of the database. In this case, it is the same name as the database file itself.
  • Integrated Security = True means you can connect to the database using your current Windows credentials, so you don’t need a separate username/password to connect to SQL Server.

Let’s quickly recap what we’ve done up to this point. We created a Video class and had a quick look at the auto-generated DbContext as well as the connection string for the database.

The last part of this step is to make a slight modification to our DbContext. Go back to IdentityModels.cs, and modify ApplicationDbContext as follows:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<Video> Videos { get; set; }
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

Here I added a property of type DbSet<Video> called Videos. DbSet is a generic class that comes with Entity Framework. As the name implies, it represents a set (or a table) in a database. We work with this DbSet like a collection in memory. We add Video objects to it, we remove an object, or modify it and then when we ask Entity Framework to write changes to the database. Entity Framework keeps track of changes in this collection in memory, and based on those changes it will generate corresponding SQL commands and runs them on the database.

We built our model in this step. Next, we’re going to generate the database.

Step 2: Generating the Database

In this step, you’re going to learn how to use Entity Framework Code First workflow to generate a database. But before we get started, let me explain the process first, and then we’ll do it together. The Code First workflow includes three steps:

  • Enabling migrations: The very first time you need to use Code First workflow, you need to enable migrations. With this, you instruct Entity Framework to keep track of changes in your domain classes.
    • Adding a migration: Once migrations are enabled, every time you make a change to your domain classes (e.g., adding a new class, modifying an existing one, etc.), you create a new migration. A migration is a class with some auto-generated code that is used to upgrade or downgrade the database. Since Entity Framework is now aware of changes in your domain classes, it will automatically generate the code to migrate the database. For example, if you create a new class like Video and then add a migration, Entity Framework will generate code to create a new table called Videos.
  • Updating the database: With this step, you tell Entity Framework to run migrations you’ve created on the database. Entity Framework will compare the migrations you have in your project with the ones that are run on the database, and if there are any new migrations, it will run them sequentially to bring your database up to date.

So this is the process. Now, it’s time to do the steps. We do all these steps in Package Manager Console. Go to Tools > NuGet Package Manager > Package Manager Console.

First, we need to run the Enable-Migrations command.

PM> Enable-Migrations

When you run this command, a new folder called Migrations will be added to your project. Inside this folder, you’ll see a file like [DATETIME]_InitialCreate.cs. Here, the value of DATETIME depends on the date/time you run this command.

What is this file? Let’s open it and see. You see a migration class called InitialCreate which derives from DbMigration and has two methods: Up and Down, which are executed when upgrading or downgrading the database, respectively. So with Entity Framework Code First, you get full versioning of your database. At any time, you can upgrade it to the latest version, or downgrade it to an earlier version. This is extremely useful in the real world, where you may need to maintain multiple versions of an application.

Let’s take a look at the Up method in our migration class. Inside this method, you see a number of calls to CreateTable method. Each of these calls aims to create a table in the database. When you run migrations, Entity Framework will read all this code and generate corresponding SQL statements to execute on your database. This migration aims to create tables such as AspNetRoles, AspNetUserRoles, AspNetUsers, etc. These are the tables used internally by ASP.NET Identity to manage user registration, login, etc.

Now, back to our migration process. I mentioned that every time you make a change to your domain model, you need to add a new migration. Thus, we created the Video class and added a DbSet<Video> to our DbContext. By adding this DbSet to our DbContext, we tell Entity Framework that this Video class needs to be stored in the database. Now, at this point, we don’t have any tables in the database for our videos. So, we need to add a new migration.

Back to Package Manager Console, run this command:

PM> Add-Migration AddVideosTable

This command takes an argument, which is the name of your migration, in this case AddVideosTable. This name is arbitrary, and you can call it anything. There is no magic behind it. It’s just a way to organize your migrations so you know how each migration affects your database. I tend to name my migrations based on the changes that should happen in the database. In this case, because the Video class is a new class, I expect Entity Framework to generate a migration to add a new table called Videos. This is why I called this migration AddVideosTable.

When you run this command, Entity Framework will create a new migration file in the Migrations folder, called [DATETIME]_AddVideosTable. Let’s take a look at this file.

So, you see another migration class that derives from DbMigration. Look at the Up method. Note the call to CreateTable, which tries to create a table called Videos.

public override void Up()
{
    CreateTable(
        "dbo.Videos",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                Title = c.String(),
                Description = c.String(),
                Genre = c.Int(nullable: false),
            })
        .PrimaryKey(t => t.Id);        
}

I’ve highlighted the key areas here that you need to understand. Note the name of this table: Videos. Entity Framework uses convention over configuration. Thus, there are certain conventions built into it that work in most cases. In this case, because we have a class called Video, it assumes the table should be called Videos.

Similarly, because we have four properties in our Video class, it will create four columns with the same name and type in the database: Id, Title, Description and Genre.

Also, look at the last line in this method:

.PrimaryKey(t => t.Id);        

Again, based on the convention, it assumes that the Id property or column represents a unique key for a video. Hence, it marks this column as the primary key.

As you see, the convention is useful and works in most cases. But if it doesn’t work for you, you can always override it. For example, some developers prefer singular names for their database tables. You can always supply additional configuration to override the default conventions. This is beyond the scope of this tutorial, but it’s something I’ve covered in my Entity Framework course that will be published on Udemy soon.

Back to our migration process. We enabled the migrations, and added a new migration. Entity Framework detected that we have a new class, called Videos, and generated the corresponding code to create a new table in the database. The third step of the process is to run the migrations.

Open up Package Manager Console again and run:

PM> Update-Database

At this point, Entity Framework runs any pending migrations on your database. By pending, I mean any migrations that have not been run on the database before. So, let’s take a look at the database.

In Solution Explorer, expand App_Data folder. You should see your database file with MDF extension. If you don’t see it, it’s because it’s not part of the project, and by default, Visual Studio hides files on the disk that are not in your project. To see all files, click the Show All Files button in the toolbar on Solution Explorer.

image13

You should see your database file in App_Data folder. Double-click it. A new panel called Server Explorer pops out of the left side. Expand the Tables.

image07

The _MigrationHistory table is used by Entity Framework to keep track of migrations that have been run on the database. Tables starting with AspNet are used by ASP.NET Identity to manage authentication. And finally, we have our Videos table.

As you saw in this step, with the Code First workflow, we never wasted our time with table designers. Instead, we focused on our code, which is what we programmers do anyway. We modify our domain model, then add a migration and update the database. Entity Framework will take care of bringing the database up to date. With this, not only can we get things done faster, but we also get full versioning of our database. We can upgrade or downgrade our database to any version. When it comes to deploying our application to production, we can ask Entity Framework to generate a SQL script based on all migrations in our project. Then we can take this script and run it on the production database.

In this step you learned about Code First migrations. Now that we have our domain class and the corresponding table, it’s time to populate this table with some data so we can display it to the user.

Step 3: Populating the Table

In Server Explorer, right-click the Videos table and go to Show Table Data. Then add a few records to this table. Note that the Id column is an IDENTITY column, so you don’t need to supply any values for it. Again, by convention, Entity Framework marks the primary key of a table as an identity column.

image08

Step 4: Creating a Page to Display Videos in the Database

In this step, you’re going to learn how to create new web pages with ASP.NET MVC. We’re going to create a simple page to display all videos in the database.

Again, before getting into the mechanics, let me give you some background on the process and how everything fits together.

ASP.NET MVC is based on the Model View Controller (MVC) pattern. MVC is one of the architectural patterns that aims to provide better separation of concerns in your application, which results in better maintainability.

To understand MVC, think of a restaurant. When you go to a restaurant, there is a waiter/waitress, a chef, one or more kitchen hands, a manager, etc. Every person in the restaurant is responsible for only one thing. Imagine what the restaurant would be like if all these people did everything! What would it be like if the chef came to you, took the order, then went shopping, and asked the cashier to cook your food? You’d probably run away! The same concept applies in software. Clean software is like a well-managed restaurant, where everyone has one and only role. Architectural patterns like MVC help us to achieve this by promoting separation of tasks. Therefore, different parts of your application will be responsible for only one thing. In MVC terms, we have:

  • Views: which are purely responsible for presenting data. This is where we write our HTML markup. Views should only have logic related to viewing data, not for processing inputs. For example, you can use a foreach block to render a list of objects in a view. But you’re not supposed to use any other kind of logic for processing user input or controlling application flow.
  • Controllers: responsible for processing user input, application flow, etc.
  • Models: classes that represent the state of the application. In practical terms, this often means the domain model of an application. In our application, the Video class we created is part of the application domain. When we load data from the database, we create one or more Video objects that represent the state of the application.

As you see, with this structure, we get a clean separation. Every component is responsible for one thing.

Earlier, we created our domain model. In this step, we’re going to create a Controller and a View.

Right-click the Controllers folder and go to Add > Controller…. In the dialog box, select the first item (MVC 5 Controller – Empty).

image03

There are other templates here that automatically generate some code for us, but in this tutorial I want to teach you how to write all this code by hand so you have a good understanding of how everything works. Click Add. Name this controller VideosController and click Add again. Visual Studio will create a basic empty controller like this:

public class VideosController : Controller
{
    // GET: Videos
    public ActionResult Index()
    {
        return View();
    }
}

Our VideosController derives from the Controller class. Controller is part of ASP.NET MVC and encapsulates the basic functionality that every controller in the application might need.

Here, we have a method called Index which returns an ActionResult. In ASP.NET MVC, Methods in a controller are referred to as Actions. The job of an action is to handle a request. So, when an HTTP request comes into the ASP.NET runtime, it will be routed to an action for processing. This routing is based on convention, but you can always override it. The convention determines the name of a controller and an action from the URL of the request. So, as an example, if the URL of a request equals /videos/index, it should be handled by a controller called VideosController with the Index method (or action). I’ll explain routing in a bit more detail later on.

Here in this method: we need to write code to handle a request for the URL /videos/index. This means that we need to get the list of videos from the database and display them in a view. Change the code as follows, and then I’ll explain how everything works:

using System.Linq;
using System.Web.Mvc;
using Beaver.Models;

public class VideosController : Controller
{
    private ApplicationDbContext _dbContext;

    public VideosController()
    {
        _dbContext = new ApplicationDbContext();
    }

    // GET: Videos
    public ActionResult Index()
    {
        var videos = _dbContext.Videos.ToList();

        return View(videos);
    }
}

What’s going on here? First, I added two using statements on the top to import the required namespaces.

Next, I declared a private field of type ApplicationDbContext in the controller and initialized it in the constructor.

In the Index action, we use _dbContext to get the videos from the database. Remember how earlier we added a DbSet<Video> to our AppicationDbContext? I told you that this DbSet represented a set (or a table) in the database. So, here _dbContext.Videos represents the set of videos. The ToList method is an extension method provided by LINQ. When we call this method, Entity Framework runs a query on the database and pulls out all videos from the database. If you need to better understand LINQ and extension methods, check out my C# Advanced course on Udemy.

As you see, with Entity Framework, getting data from the database can be as simple as one line of code. We never have to worry about working with plain ADO.NET objects such as SQL connections, commands, etc. Our DbContext takes care of all this complexity.

Finally, in the last line of our Index action, we call the View method and pass the videos object to it. This method is a helper method that is defined in the base Controller. It returns an instance of the ViewResult class. By returning an instance of a ViewResult, we tell ASP.NET MVC runtime to return a view upon processing this request. In a more complex application, we don’t always return a view from an action. Sometimes we may want to redirect the user to a new URL, or return a JSON object. This is the reason the return type of our Index action is ActionResult. This is an abstract class that specific action results inherit from. For example, ViewResult, RedirectResult and JsonResult all inherit from ActionResult. By using the base class as the return type, this method can return any of its derivatives. It’s common convention to return an ActionResult from controller actions.

Let’s recap: we built a controller with one action that returned a view populated by the list of videos from the database. But where is the actual view? We’re going to create it now.

Back in the Solution Explorer, expand the Views folder, right-click the Videos and go to Add > View… By convention, since we have a controller called Videos, we should have a folder here called Videos, which includes all the views this controller is going to use.

In the Add View dialog, set the view name to Index. Again, here by convention, since our action is called Index, we can create a view with the same name. We don’t have to follow this convention. We can always create a view with a different name, but following the convention helps us write less code to achieve the same thing.

Make sure Use a layout page is ticked and click ….

image00

In the new dialog, in the Project folders pane on the left, navigate to Views > Shared. On the right, select the first item: _Layout.cshtml and click OK. Click Add to finish adding a new view.

image04

So, what is a layout? It’s a template or a master page for all our views. By using a layout, we can ensure that all views have the same look and feel. The default ASP.NET MVC project template already has a layout that you saw when previewing the site. We can always change this layout to customize it for our own needs.

Let’s take a look at the newly generated view:


@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>

In ASP.NET MVC, our views are files with the cshtml extension. Inside these files we can write both HTML and C# code. To write C# code, you need to prefix it with @ or @{ } if your code is more than one line. This syntax is based on what we call Razor Views. So, in ASP.NET MVC we have a view engine that knows how to parse these views with this special syntax, and generate raw HTML from our C# code.
Look at the top of this file:

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Here we have a code block indicated by @{ }. The first line specifies the title of this view. This title is what we see in the browser title bar when we access this page. The second line specifies the layout file that you selected in the Add View dialog. So you can always come back here and change the layout if you want.

Next, we need to display the list of videos in this view. First, we need to add this line on the very top of the view:

@model IEnumerable<Beaver.Models.Video>

With this line, we tell the view engine that the model behind this view is an instance of IEnumerable<Video>. What is IEnumerable? It’s an interface used for enumerating a list of objects. Earlier in the controller, we used the ToList method to get the list of videos from the database:

var videos = _dbContext.Videos.ToList();

Here, this videos object is a List<Video>. A list in C# implements the IEnumerable interface, which allows us to iterate the list using the foreach block. Alternatively, in the view, we could set the model to List<Video> instead of IEnumerable<Video>. Is there a difference? Yes, a tiny one. When you use a concrete class like List<Video>, your model has to be of that type. But if you use an interface, your model can be of any type that implements that interface. In this example, if we use IEnumerable and later we decide to pass an object of a different type to this view (e.g., a SortedList or Dictionary), everything will continue to work, because those types implement the IEnumerable interface as well. Hence, with interfaces, your application will be more loosely coupled and breaks less as a result of internal changes.

Back to the view: we specified the model passed to the view. Next, change the heading of the view from:

<h2>Index</h2>

to:

<h2>Videos</h2>

Now, write the following piece of code after the heading:

<ul>
    @foreach (var video in Model)
    {
        <li>@video.Title (@video.Genre)</li>
    }
</ul>

Here, we’re using a UL (unordered list) to display the list of videos.

As you see, the code includes a mix of HTML and C# code, thanks to the Razor view engine! Note that our C# code is prefixed with @. This tells the view engine that this is C# code and needs to be executed.

We use a LI (list item) to render each video. Again, in this line, we have a mix of HTML and C# code. Here we simply display the Title and Genre of each video. In a more complex application, you can have a complex UL/LI structure with lots of child elements and display lots of attributes to the user. But the process is exactly the same as what we’ve done here. Thus, you can take this knowledge and apply it to a difference scenario.

Note that as you were typing:

@video.Title

IntelliSense showed you the properties of the video object when you used the dot notation. This is because we set the model of this view at the top of the view. If you didn’t do that, IntelliSense wouldn’t work, and in some cases you would even get a runtime exception.

That’s all you had to do to get the list of videos from the database and show them to the user. We created a controller and wrote a couple of lines of code in the Index action, then created a view and used a foreach block to display videos.

Let’s run the application and see the result. Press Ctrl+F5 to run the application. Your browser will launch and navigate to /Videos/Index. This is because you pressed Ctrl+F5 when you were viewing the Index view in the Videos folder.

image05

Look at the content of the page. You see the list of videos. So we successfully built the first feature of our application. In the next section, we’ll implement the ability to add a new video to the database.

Adding a New Video

In this section, you’re going to learn how to create a data entry form and save data to the database using Entity Framework. We will be building a form for adding a new video to the database.

I’m going to break this section into two steps:

  • Creating a page to add a video
  • Saving the video to the database

Step 1: Creating a Page to Add a Video

Before we get started, let’s take a closer look at routing.

Earlier I told you that the routing engine determines the name of the controller and the action from the URL of the request. The default rule (or the default convention) targets a URL with the pattern /controller/action/id. Here both action and id are optional. If action is not specified, Index is assumed as the action name. Take a look at the following table for a few examples:

URLControllerAction
/videosVideosControllerIndex()
/videos/indexVideosControllerIndex()
/videos/newVideosControllerNew()
/videos/edit/1VideosControllerEdit(int id)

For the purpose of this section, we need a new page for the user to add a new video. To do this, we’re going to create a new action that responds to a URL like /videos/new. Inside this action, we’ll return a view which will include a data entry form for adding a video.

First, go to VideosController and create a new action like this:

public ActionResult New()
{
    return View();
}

All we do here is simply return a view. Let’s create the corresponding view. In Solution Explorer, expand the Views folder, right-click the Videos folder, and go to Add > View…. Set the name of the view to New and make sure _Layout.cshtml is selected as the layout (similar to the last section).

image09

Next, set the model behind this view on the top:

@model Beaver.Models.Video

We set the model to the Video because we’re going to capture a Video object in this form.

Now, write the following code in the view to create an HTML form element:

@using (Html.BeginForm("Add", "Videos", FormMethod.Post, new { @class = "form" }))
{

}

Here we are using Razor syntax (note the @) to write C# code. Html.BeginForm is a helper method, which we use to render an HTML form element. It returns an instance of MvcForm, which is a disposable object. By wrapping it inside a using block, we can ensure that it will be properly disposed.

The first and second arguments specify the name of the action and controller that will be called when we post this form. In this case, we expect an action named Add in our VideosController to be called. We haven’t created this action yet, but we’ll do so soon.

The third argument specifies the form method. In HTML forms, we have two methods: GET and POST. When sending data for modification to the server, we should always use the POST method.

The last argument is an anonymous object ( new {} ) that specifies any additional attributes to add to the HTML markup. So, when this code is executed, the view engine will render something like this:

<form action=”/videos/add” method=”post” class=”form”>
</form>

We use the form CSS class to give a nice, modern look to our forms. This CSS class is defined in Bootstrap, which is a CSS framework for building modern and responsive (mobile- and tablet-friendly) web applications. When you create an ASP.NET MVC project in Visual Studio, Bootstrap is automatically added for you.

We added the form. Now, we need to add three input fields in this form: Title, Description and Genre. Write this code inside the using block:

    <div class="form-group">
        @Html.LabelFor(m => m.Title)
        @Html.TextBoxFor(m => m.Title, new { @class = "form-control" })
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.Description)
        @Html.TextAreaFor(m => m.Description, new { @class = "form-control", rows = 4 })
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.Genre)
        @Html.EnumDropDownListFor(m => m.Genre, new { @class = "form-control" })
    </div>

Here we have three sections, each wrapped with a div with a form-group class. Again, this is one of the classes that is defined in Bootstrap. If you follow Botostrap’s markup, you always get a nice, clean form that renders well both on the desktop and on mobile devices.

Inside each form-group, we have a label and an input field. Look at the first form-group.

<div class="form-group">
    @Html.LabelFor(m => m.Title)
    @Html.TextBoxFor(m => m.Title, new { @class = "form-control" })
</div>

We’re using Html.LabelFor to render a label for the Title property of the Video class.

@Html.LabelFor(m => m.Title)

The expression m => m.Title is a lambda expression that we use to access a property in the model of this view. If you’re not familiar with lambda expressions, check out my C# Advanced course on Udemy. When this line is executed by the view engine, we’ll get an HTML markup like this:

<label for=”Title”>Title</label>

Next, we use Html.TextBoxFor helper method to render a text box.

@Html.TextBoxFor(m => m.Title, new { @class = "form-control" })

Again, we use a lambda expression to specify the target property. Also, note that the second argument to this method is an anonymous object that specifies any additional attributes to add to the markup, in this case form-control CSS class. This is another Bootstrap class that gives our text boxes a bit of padding, round corners and a nice effect when the input is in focus. The result will be HTML markup like this:

<input type=”text” id=”Title” name=”Title” class=”form-control”></input>

Now you read the second form-group.

<div class="form-group">
        @Html.LabelFor(m => m.Description)
        @Html.TextAreaFor(m => m.Description, new { @class = "form-control", rows = 4 })
    </div>

It’s very similar to the first one, except that here we use the Html.TextAreaFor helper method to render a textarea input element instead of a text box. This allows the user to write a description that is more than one line.

And finally, in the third form-group, we use a different helper method (Html.EnumDropDownListFor) to render a drop-down list for the Genre property, which is an enum:

<div class="form-group">
        @Html.LabelFor(m => m.Genre)
        @Html.EnumDropDownListFor(m => m.Genre, new { @class = "form-control" })
    </div>

For the last step, we need a button to submit the form. Add this markup inside the using block, after all form groups:

<input type="submit" class="btn btn-primary" value="Save" />

Here, btn and btn-primary are both Bootstrap classes that make our buttons look cool and modern.

Your entire using block should look like this:

@using (Html.BeginForm("Add", "Videos", FormMethod.Post, new { @class = "form" }))
{
    <div class="form-group">
        @Html.LabelFor(m => m.Title)
        @Html.TextBoxFor(m => m.Title, new { @class = "form-control" })
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.Description)
        @Html.TextAreaFor(m => m.Description, new { @class = "form-control", rows = 4 })
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.Genre)
        @Html.EnumDropDownListFor(m => m.Genre, new { @class = "form-control" })
    </div>

    <input type="submit" class="btn btn-primary" value="Save" />
}

Now it’s time to review what we have done. Run the application with Ctrl+F5 and look at the form we’ve built:

image01

Note how the input fields and the button look. This is all because of the beautiful styles defined in Bootstrap.

In this step, we added a new action to our controller that returned a view. We created a view with a form to add a video. In the next step, we’re going to save this video to the database.

Step 2: Saving the Video to the Database

Earlier in the last step, we defined a form with the following code:

using (Html.BeginForm("Add", "Videos", FormMethod.Post, new { @class = "form" }))
{
}

As I explained before, when this form is posted, the Add action in the Videos controller will be executed. So in this step, we’re going to implement this action.

Open up VideosController and create a new action as follows:

public ActionResult Add(Video video)
{
    _dbContext.Videos.Add(video);
    _dbContext.SaveChanges();
    return RedirectToAction("Index");
}

This action takes a Video object populated with the values that the user enters into the form.

The first line adds the Video object to our DbSet. Remember DbSet? It’s a collection of objects in memory that is tracked by Entity Framework. When we add an object to this collection, nothing is saved to the database yet. Everything is in memory. When we call _dbContext.SaveChanges(), Entity Framework will look at all the changed objects in memory and will automatically run the right SQL statements to update the database.

In the last line, we are using the RedirectToAction helper method to redirect the user to the Index action. This means that once the video is saved, the user will be redirected to /videos/index where they will see the list of all videos in the database. The RedirectToAction method returns a RedirectToRouteResult which derives from ActionResult. So, by using ActionResult as the return type of our actions, we can return an instance of any classes that derive from ActionResult. So far, you’ve seen RedirectToRouteResult and ViewResult. There are a few other ActionResults which are beyond the scope of this tutorial.

It’s time to test our application. Run the application with Ctrl+F5 and in the browser, change the URL to go to /videos/new.

Fill out the form, and click the Save button. The new video should appear in the list.

Before we finish this step, it would be nice to add a link to the Add Video page in the list of videos. Open up Views > Videos > Index and type the highlighted code:

<h2>Videos</h2>
<p>
    @Html.ActionLink("Add Video", "New")
</p>
<ul>
    @foreach (var video in Model)
    {
        <li>@video.Title (@video.Genre)</li>
    }
</ul>

Here, Html.ActionLink is yet another helper method that we use to generate hyperlinks. The first argument is the text for the link, and the second argument is the name of the target action. We could optionally supply a third argument that would be the name of the controller, but in this case because we’re in a view for the Videos controller, it’s not necessary. It’ll be assumed by convention.

Now, you might ask, “Why do we use these helper methods to generate HTML markup? Why don’t we just use raw HTML elements?” We can use raw HTML, but the benefit of using these helper methods is that they are aware of routing configuration. In this case, when we tell this method to render a link for the New action, it will generate a link that points to /videos/new. If you override the default routing and map your New action to another route (eg /videos/create), this code will continue to work. It will generate a link to /videos/create. However, if we used a raw HTML anchor element (e.g., <a href=”/videos/new”>), the link will break because we no longer have an action that responds to /videos/new. So, we prefer to use helper methods to generate HTML markup.

Run the application again, and you should see the link.

image02

Next, let’s add the ability to edit existing videos.

Editing an Existing Video

In this section, you’re going to learn how to use partial views in ASP.NET MVC (for promoting re-usability) and how to update data using the Entity Framework.

Similar to the last section, we’re going to implement this feature in two steps. First, we’re going to add a link in front of each video that would take us to a page populated with the video details. Next, we’ll implement updating the video in the database.

Step 1: Creating a Page Populated with Video Details

In this step, we’re going to add an edit link in front of each video. The link should take us to a URL like /videos/edit/{id} where {id} is the ID of the video.

Open up Index view inside Views > Videos and change the <li> as follows:

<li>@video.Title (@video.Genre) @Html.ActionLink("Edit", "Edit", new { id = video.Id })</li>

Again, here we’re using the ActionLink helper method you saw in the last step. The first argument is the label for the link, the second argument is the target action, and the third argument is an anonymous object used to supply additional parameters to the route. In this case, we’re passing the ID of each video. With this, ActionLink will return markup like:

<a href=”/videos/edit/1”>Edit</a>

When the user clicks on this link, we need to take them to a page with a form populated with the video details. We need an action to handle this request. Inside this action, we’re going to fetch the video with the given ID from the database, and put it on the view. Create a new action in the VideosController as follows:

public ActionResult Edit(int id)
{
    var video = _dbContext.Videos.SingleOrDefault(v => v.Id == id);

    if (video == null)
        return HttpNotFound();

    return View(video);
}

In the first line, we’re using our DbSet (_dbContext.Videos) but this time, instead of using the ToList method (to get all videos), we use SingleOrDefault. Both of these methods are LINQ extension methods. If you’re not familiar with LINQ, checkout my C# Advanced course. With this method, we get a single object from the database. Default means that if no object matching the criteria is found, null is returned. Note that the argument to this method is a lambda expression that specifies the criteria.

If the video is not found, we call the HttpNotFound method and return its value.

if (video == null)
    return HttpNotFound();

This method returns HttpNotFoundResult which is yet another ActionResult. With this line, the user will automatically be redirected to a standard “Page Not Found” page in your application.

Finally, if the video is found, we return a view and populate it with the video object:

return View(video);

Now, let’s go ahead and create this view. Inside the Views folder, right-click Videos and go to Add > View… Set the name of this view to Edit and ensure that the layout is selected.

We want to display a form to edit a video. This form looks identical to the form we created earlier for adding a video. Following the DRY principle (Don’t Repeat Yourself) of software engineering, let’s refactor our existing code and prevent code duplication.

Right-click the Videos folder again, and go to Add > View… Set the name of this view to _VideoForm (note the underscore) and make sure to tick Create as a partial view.

image12

When you tick this option, the layout checkbox becomes disabled. A partial view is like a small view that we can reuse in many views. It doesn’t have a layout, so it’s not a full view. In this case, we’re going to extract our video form and put it in this partial view so we can reuse it in both the add and edit views.  

Open up New.cshtml. Select all the markup inside the using block (excluding the using block), and then cut and paste it into _VideoForm.cshtml. This is the markup you need to move to the partial view:

<div class="form-group">
    @Html.LabelFor(m => m.Title)
    @Html.TextBoxFor(m => m.Title, new { @class = "form-control" })
</div>
<div class="form-group">
    @Html.LabelFor(m => m.Description)
    @Html.TextAreaFor(m => m.Description, new { @class = "form-control", rows = 4 })
</div>
<div class="form-group">
    @Html.LabelFor(m => m.Genre)
    @Html.EnumDropDownListFor(m => m.Genre, new { @class = "form-control" })
</div>
<input type="submit" class="btn btn-primary" value="Save" />

Make sure to set the model for this partial view at the top of the view:

@model Beaver.Models.Video

Back to New.cshtml, change the using block as follows:

@using (Html.BeginForm("Add", "Videos", FormMethod.Post, new { @class = "form" }))
{
    Html.RenderPartial("_VideoForm");
}

Here we’re using RenderPartial helper method to include the markup in another view, in this case _VideoForm. Note that by convention, partials are prefixed with an underscore.

Also, note that the call to RenderPartial is terminated by a semicolon because unlike the other helper methods you’ve seen so far (e.g., Html.LabelFor, Html.TextBoxFor), this method directly writes markup to the response, whereas the other helper methods return an MvcHtmlString which is then converted to a string by the view engine.

Now we’re going to reuse this partial view in our Edit Video page. Copy the entire using block in New.cshtml and paste it into Edit.cshtml. Then change the action name from Add to Update. Your Edit.cshtml should look like this:

using (Html.BeginForm("Update", "Videos", FormMethod.Post, new { @class = "form" }))
{
    Html.RenderPartial("_VideoForm");
}

Run the application with Ctrl+F5. You’ll see a runtime error because Visual Studio redirects you to /videos/edit without specifying the ID of the video to edit. Change the address in the browser and navigate to /videos to see the list of videos. Click the edit link in front of one of the videos. You’ll be redirected to the edit form populated with the video you selected.

In the next step, we’re going to save the changes to the database.

Step 2: Updating a Video in the Database

In the last step, when we created our Edit view, we set the target action to Update. In this step, we need to implement this action to update the video. Add a new action to VideosController as follows:

[HttpPost]
public ActionResult Update(Video video)
{
    var videoInDb = _dbContext.Videos.SingleOrDefault(v => v.Id == video.Id);

    if (videoInDb == null)
        return HttpNotFound();

    videoInDb.Title = video.Title;
    videoInDb.Description = video.Description;
    videoInDb.Genre = video.Genre;
    _dbContext.SaveChanges();

    return RedirectToAction("Index");
}

The code should be very familiar, except for a few minor differences.

First, I’ve decorated this action with the [HttpPost] attribute. This tells the MVC runtime that this action can only be called when there is an HTTP POST request.


Beginner’s question: What is HTTP POST, and why/when should we use it? HTTP requests have different verbs, and each verb has a different meaning. We have GET (for reading data), POST and PUT (for inserting/updating data), and DELETE for deleting data. As a best practice, whenever you’re changing data in ASP.NET MVC, you need to mark your actions as HttpPost. If you don’t do this, it is possible that when a search engine spider (like Google) is crawling your website, it modifies or deletes your data without you being aware of that. Because these spiders use HTTP GET to navigate to different parts of your website, when you use HTTP POST, you’re preventing a simple HTTP GET from modifying/deleting data in your database.


Back to our action: in the first line, we get the video with the given ID from the database.

var videoInDb = _dbContext.Videos.SingleOrDefault(v => v.Id == video.Id);

Note that I named this variable videoInDb to distinguish it from the video object passed as a result of posting the form.

Next, we check to see if the video was found or not, just like before.

if (videoInDb == null)
    return HttpNotFound();

Then we update the Title, Description and Genre properties of videoInDb and call _dbContext.SaveChanges() to update the database.

videoInDb.Title = video.Title;
videoInDb.Description = video.Description;
videoInDb.Genre = video.Genre;
_dbContext.SaveChanges();

DbContext will issue an UPDATE SQL statement based on the properties we have updated. Finally, we redirect the user to the list of videos.

return RedirectToAction("Index");

Let’s run the application and see if everything is working. Navigate to /videos, and click the Edit in front of the first video. Make some changes, and click the Save button. You’ll be redirected to the 404 Not Found page. Why is that? This is one of those issues that you may encounter when you forget to add a hidden field in your form. Let’s go back to our action and see why exactly this happened:

var videoInDb = _dbContext.Videos.SingleOrDefault(v => v.Id == video.Id);

If you run the application in the debug mode and put a breakpoint here, you’ll see that the value of video.Id is 0. Thus, the request that is sent to the server does not have a value for the ID of the video. It only includes values for Title, Description and Genre, which come from the input fields on the form. To send the value of Video.ID, we need to add a hidden field.

Open up _VideoForm.cshtml and add a hidden field before the Save button:

@Html.HiddenFor(m => m.Id)
<input type="submit" class="btn btn-primary" value="Save" />

You can add this hidden field anywhere here, but my personal convention is to add them before the submit button. This way, I always know where to look when I’m looking for hidden fields.

Run the application again, try to edit a video, make a few changes, and save. Everything should work.

Next, we’ll add the ability to delete a video.

Deleting a Video

In this section, you’ll learn how to delete data in the database using the Entity Framework.

Again, we’re going to implement this feature in two steps: first, we’re going to add a Delete link in front of each video in the video list. When the user clicks this link, they’ll see a page with the details of the video to delete. This is the delete confirmation page. Next, we’ll be focusing on actually deleting the video from the database.

Step 1: Creating a Page to Confirm Deletion

This step is very similar to what we’ve done before. Add a Delete link in front of each video in the list. When this link is clicked, display a view with the details of the video to delete. Use a UL/LI to display different attributes of a video. Don’t worry about deleting the video from the database yet. After trying this, take a look at my solution:

First, we need to add the Delete link in front of each video. So open up Index.cshtml in Views > Videos, and change the LI as follows:

<li>
    @video.Title (@video.Genre)
    @Html.ActionLink("Edit", "Edit", new {id = video.Id}) |
    @Html.ActionLink("Delete", "Delete", new {id = video.Id})
</li>

Note that I added a vertical separator between Edit and Delete to separate them.

Next, we should create a new action in the VideosController as follows:

public ActionResult Delete(int id)
{
    var video = _dbContext.Videos.SingleOrDefault(v => v.Id == id);

    if (video == null)
        return HttpNotFound();

    return View(video);
}

Nothing should be new to you at this point. We’re just pulling out the video to show to the user before deleting it.

Now, let’s create the corresponding view. Add a new view called Delete inside Views > Videos. Make sure it’s not a partial view and has a layout. Write the following code inside the view.

@model Beaver.Models.Video

@{
    ViewBag.Title = "Delete";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Delete</h2>

<p>
    Are you sure you would like to delete this video?
</p>
<ul>
    <li>Title: @Model.Title</li>
    <li>Description: @Model.Description</li>
</ul>

Here I am using a simple UL/LI to display the attributes of the video. You can use anything to lay out the details of a video. It doesn’t really matter from the perspective of learning ASP.NET MVC.

Next, write this code in the view:

@using (Html.BeginForm("DoDelete", "Videos", FormMethod.Post))
{

    @Html.HiddenFor(m => m.Id)
    <input type="submit" class="btn btn-danger" value="Yes, Delete it!" />
    @Html.ActionLink("No, back to videos", "Index")
}

You might wonder why I’m using Html.BeginForm when we don’t really have a data entry form here. The reason is that we need to call the Delete action using HTTP POST method. Again, anytime we need to modify data in ASP.NET MVC, we should use HTTP POST to prevent accidental data modification. In ASP.NET MVC, the only way to use HTTP POST is by creating a form. In this example, our form only has a submit button and no input fields.

Note that in this form, we also have a hidden field to render the ID of the video in our markup.

@Html.HiddenFor(m => m.Id)

This way, when we post to the server, we’ll have the ID of the video to delete.

I’ve used the btn-danger Bootstrap class to make our delete button red.

<input type="submit" class="btn btn-danger" value="Yes, Delete it!" />

Now, run the application. You’ll see a delete link in front of each video. Click one of them. Look at the new page we just built.

image06

Click No, back to the videos. So, we have a nice navigation between these two pages. The only thing remaining is to actually delete a video from the database. That’s what we’re going to do in the next step.

Step 2: Deleting a Video from the Database

The form we created in the last step posts to an action named DoDelete.

@using (Html.BeginForm("DoDelete", "Videos", FormMethod.Post))

Let’s go to VideosController and create this action:

[HttpPost]
public ActionResult DoDelete(int id)
{
    var video = _dbContext.Videos.SingleOrDefault(v => v.Id == id);
    if (video == null)
        return HttpNotFound();
    _dbContext.Videos.Remove(video);
    _dbContext.SaveChanges();
    return RedirectToAction("Index");
}

Again, the code should look very familiar to you. I’ll just highlight the important aspects.

I’ve decorated this action with [HttpPost] to make sure an HTTP GET caused by a web crawler will not delete our records.

Inside the method, first we need to read the video from the database and then call the Remove method of our DbSet. This is how you ask Entity Framework to delete records in the database. You cannot directly delete a record in the database. You should always read that record first, remove it from the memory and then call SaveChanges. This way, Entity Framework’s change tracker will realize that an object is deleted and will issue a DELETE FROM SQL statement to the database.

Let’s run the application and test the delete functionality. Delete one of the videos.

Review

If you made it this far, well done. I hope you’ve enjoyed this tutorial and learned the basics of ASP.NET MVC.

Let’s quickly review what you’ve learned and what the next step is. In this tutorial,

  • You learned and used the core building blocks of ASP.NET MVC (Models, Views and Controllers).
  • You created a model using the Entity Framework Code First workflow.
  • You used Code First migrations to generate your database.
  • You built a controller with different actions for viewing lists of videos, adding a new video, and editing and deleting an existing one.
  • You learned about the routing engine in ASP.NET MVC and how URLs get mapped to controllers and actions.
  • You used Razor syntax to mix HTML and C# code in your views.
  • You refactored your code by extracting the reusable view code into a partial view.
  • You learned about the difference between HTTP GET and HTTP POST, and now you’re able to build more reliable applications.
  • You used many HTML helper methods in views such as ActionLink, LabelFor, TextBoxFor, TextAreaFor and BeginForm.
  • You used many helper methods in actions such as View, RedirectToAction and HttpNotFound.

What’s next? ASP.NET MVC is more than what you’ve read, and that’s why I’m planning to create a comprehensive course to teach you lots of things you can do with ASP.NET MVC. In particular, I’ll be teaching you:

  • Authentication and authorization
  • Prevention of common security attacks
  • Data validation
  • Caching
  • Real-time connections
  • Working with Javascript libraries
  • Ajax
  • Creating RESTful services with ASP.NET Web API
  • And more

If you enjoyed my teaching style and would like to learn more from me, subscribe to my newsletter. I’ll send out an announcement once my course is ready.