ASP.NET MVC Tutorial

banner_asp

By Jonathan Danylko for Udemy

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

TABLE OF CONTENTS: CLICK TO JUMP TO A SPECIFIC SECTION

 Overview

What is ASP.NET MVC?
Why is it so popular?
Requirements and installation
Layout of an MVC project
General flow of an MVC application

Understanding the Essentials

Models
Controllers
Views
Routes

Moving Forward with Enhancements

Model Enhancements
Controller Enhancements
View Enhancements

Conclusion


Overview

In this introduction to Microsoft’s ASP.NET MVC, we will discuss the technology, terminology, and techniques for building your very first ASP.NET MVC application.

While this is considered an introductory course, this makes a few assumptions. You should have a good understanding of C#, object-oriented concepts, and the way the Internet works in general to fully understand the workings of an ASP.NET MVC application.

Let’s start with the basics of defining ASP.NET MVC.

What is ASP.NET MVC?

ASP.NET MVC is Microsoft’s framework for developing fast web applications using their .NET platform with either the C# or VB.NET language.

MVC is not a new concept and was introduced back in the 1970’s using a language called Smalltalk-76. It was also implemented in the 1980’s using Smalltalk-80.

MVC is an acronym that stands for:

  • (M)odel – Objects that hold your data.
  • (V)iew – Views that are presented to your users, usually HTML pages or pieces of HTML.
  • (C)ontroller – Controllers are what orchestrates the retrieving and saving of data, populating models, and receiving data from the users.

Microsoft has taken these concepts and integrated them into a flexible and easy web framework, calling it ASP.NET MVC.

For those unaware of ASP.NET, below is a list of terms to understand the technology we’ll be using in this tutorial.

  • .NET Framework – A technology introduced in 2002 which includes the ability to create executables, web applications, and services using C# (pronounced see-sharp), Visual Basic, and F#.
  • ASP.NET – An open-source server-side web application framework which is a subset of Microsoft’s .NET framework. Their first iteration of ASP.NET included a technology called Web Forms.
  • ASP.NET WebForms – (2002 – current) A proprietary technique developed by Microsoft to manage state and form data across multiple pages.

Why is it so popular?

Since ASP.NET MVC appeared eight years ago, it has been a breath of fresh air for Microsoft developers. Most developers stopped working with WebForms to move forward with MVC.

But why has it become so popular?

  • ASP.NET MVC has a separation of concerns.
    Separation of concerns means that your business logic is not contained in a View or controller. The business logic should be found in the models of your application. This makes web development even easier because it allows you to focus on integrating your business rules into reusable models.
  • ASP.NET MVC provides testability out of the box.
    Another selling point is that ASP.NET MVC allows you to test every single one of your components, thereby making your code almost bulletproof. The more unit tests you provide for your application, the more durable your application will become.
  • ASP.NET MVC has a smaller “View” footprint.
    With WebForms, there is a server variable called ViewState that tracks all of the controls on a page. If you have a ton of controls on your WebForm, the ViewState can grow to become an issue. ASP.NET MVC doesn’t have a ViewState, thus making the View lean and mean.
  • ASP.NET MVC has more control over HTML.
    Since server-side controls aren’t used, the View can be as small as you want it to be. It provides a better granularity and control over how you want your pages rendered in the browser.

There are a number of other reasons, but a lot of thought was put into ASP.NET MVC and over eight years, it has matured into an exceptional framework for web developers.

Requirements and installation

To start building ASP.NET MVC applications, it is recommended that you have the following:

  • A version of Visual Studio (preferably 2013, 2015, or Community Edition) installed on your machine. The Community Edition can be found at http://www.visualstudio.com/.
  • .NET Framework (4.0 or higher)

Once you’ve installed Visual Studio, we can create a sample project to find out what’s included with an MVC project.

Layout of an MVC project

I know you want to jump right into development, but you have to understand where everything is at before you start coding.

You need to know where the hammer and screwdriver are before building, right?

When you create a new MVC project, your solution should have the following structure in your Solution Explorer.

image01

App_Data – While I don’t use this folder often, it’s meant to hold data for your application (just as the name says). A couple of examples would include a portable database (like SQL Server Compact Edition) or any kind of data files (XML, JSON, etc.). I prefer to use SQL Server.

App_Start – The App_Start folder contains the initialization and configuration of different features of your application.

  • BundleConfig.cs – This contains all of the configuration for minifying and compressing your JavaScript and CSS files into one file.
  • FilterConfig.cs – Registers Global Filters.
  • RouteConfig.cs – Configuration of your routes.

There are other xxxxConfig.cs files that are added when you apply other MVC-related technologies (for example, WebAPI adds WebApiConfig.cs).

Content – This folder is meant for all of your static content like images and style sheets. It’s best to create folders for them like “images” or “styles” or “css”.

Controllers – The controllers folder is where we place the controllers.

Models – This folder contains your business models. It’s better when you have these models in another project, but for demo purposes, we’ll place them in here.

Scripts – This is where your JavaScript scripts reside.

Views – This parent folder contains all of your HTML “Views” with each controller name as a folder. Each folder will contain a number of cshtml files relating to the methods in that folder’s controller. If we had a URL that looked like this:

http://www.xyzcompany.com/Products/List

we would have a Products folder with a List.cshtml file. We would also know to look in the Controllers folder and open the ProductsController.cs and look for the List method.

Views/Shared – The Shared folder is meant for any shared cshtml files you need across the website.

Global.asax – The Global.asax is meant for the initialization of the web application. If you look inside the Global.asax, you’ll notice that this is where the RouteConfig.cs, BundleConfig.cs, and FilterConfig.cs are called when the application runs.

Web.Config – The web.config is where you place configuration settings for your application. For new MVC developers, it’s good to know that you can place settings inside the <appsettings> tag and place connection strings inside the <connectionstring> tag.

Now that you know where everything is located in your project, we can move forward with what is the process when an MVC application is initially called.

General flow of an MVC application

The flow of an MVC application can get confusing, but I want to visually show you how a simple request moves through the ASP.NET pipeline.

  1. A user requests a web page using a browser.
  2. The server receives the request.
  3. If this is the first time the web application is called, Route objects are added to the RouteTable object. Once the route table is created, we build additional routing objects and perform the routing using the RouteTable, which creates the RouteData, then the RequestContext.
  4. Now that we have our Request Context, the MvcRouteHandler creates an MvcHandler. The MvcHandler is what kicks off the start of an MVC Application. It also identifies which controller to use based on the HTTP request. The MvcHandler creates the controller and calls the execute method.
  5. Once we have our Controller identified and selected, we need to find the method to execute. This is done by using the ControllerActionInvoker. Once found, it executes that method.
  6. The action method is executed while passing in user parameters, orchestrates response data, and returns a resulting ActionResult. Usually, a ViewResult is returned by MVC.
  7. The data is passed through to either the default View or a specified different View through a ViewResult. The data is laid into the View (HTML) using Razor placeholders. Think of it as a template.
  8. Once the data is in the View, it now processes the View, performing replacements by executing code resulting in plain HTML.
  9. The final View is sent back to the user in their browser.

image00

If this seems like a lot to remember, it’s okay. You’ll see how easy the process is while we work through this tutorial.

Let’s start with the basics.

Understanding the essentials

Models

What are Models?

Models are probably the easiest section to address first. Models are the objects that define and store your data so you can use them throughout the application.

I would consider Models to be the equivalent of plain old CLR (Common Language Runtime) objects, or POCO’s. A POCO is a plain class that holds structured data. That’s it.

For example, if you had a business, one simple POCO (or model) would be similar to:


public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public IEnumerable<Order> Orders { get; set; }
}
​

Of course, you do have options when adding additional functionality to your POCO’s. For example, how long have they been with you as a customer?

Your business Model may look something like this:


public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Company { get; set; }
    public IEnumerable<Order> Orders { get; set; }
    public DateTime FirstMet { get; set; }
 
    public int CalculateAge(DateTime endTime)
    {
        var age = endTime.Year - FirstMet.Year;
        if (endTime < FirstMet.AddYears(age))
            age--;
        return age;
    }
}
​

While this is a very simple example of what a model is, this won’t be the last time we discuss models.

Controllers

Controllers are considered to be the coordinators or heavy lifters of your application.

When a request comes in for a web page (GET), it goes through a controller. If a user hits a submit button (POST), that data is sent back to a controller. You can even use controllers to return smaller portions of HTML.

A controller has the following structure:


public class ExampleController : Controller
{
    public ActionResult Index()
    { 
        return View();
    }
 
    [HttpPost]
    public ActionResult Index(ExampleViewModel model)
    {        
        return View();
    }
}
​

IMPORTANT: You may notice that the name of our class is called ExampleController. This is a convention in MVC. All controllers are required to have a suffix of “controller.”

It also makes it easy to spot when building your URL’s.

In the example above, our URL would be:

http://www.xyzcompany.com/Example/Index

or

http://www.xyzcompany.com/Example

In WebForm speak-ese, the Index method is the equivalent to the Default.aspx on each controller. The Index is assumed and automatically added to the end of the URL, so both URL’s end up going to the Index method.

ActionResults

At the end of each method, you’ll notice a “return View();”. What is this?

This View method is called an ActionResult. ActionResults are a way to tell the controller what to return to a View or what to return to the browser.

Essentially, ActionResults are what you want to return when you are done processing your Action method. We’ll talk about a number of ActionResults later in the tutorial.

In this case of the ExampleController above, no data is sent to the Index view. If you observe a method returning an ActionResult without any data (like View()), it’s safe to say that a model isn’t attached to the View.

When you see the View() returned, what is actually happening behind the scenes is that the controller creates a new ViewResult and returns that as the result. The View method is just a way to camouflage the underpinnings of what makes a ViewResult function properly.

You could very easily do something like this:

public ActionResult Index()
{
 
    return new ViewResult
    {
        ViewName = "Index"
    };
}
​

But the developers of the ASP.NET MVC framework have made this extremely easy to use by creating a View() method at the controller level. The returning of the View() with the default method simplifies the process.

Most developers new to MVC have asked the question, “What’s the difference between a ViewResult and an ActionResult?”

The answer is that a ViewResult is a type of ActionResult. ViewResult is inherited from an ActionResult. There are a number of additional ActionResults that we’ll visit later, but for our purposes right now, the default behavior to an Action Method should be a ViewResult (which is an ActionResult).

ActionFilter

If you are familiar with attributes in .NET, you’ll get a fair amount of them in ASP.NET MVC.

An ActionFilter is merely an attribute that is attached to a controller or action method to perform a certain task.

One specific ActionFilter that is used a lot is the Authorize filter. Using our example above, the ExampleController doesn’t have an ActionFilter attached to the Index page.

When we attach an Authorize ActionFilter to the method, it automatically requires authorization to access the page. Your authorization could be forms authentication, Windows, cookie, or whatever type of authentication you have on your site.

[Authorize]
public ActionResult Index()
{
    return View();
}

This means that if someone tries to go to /Example/Index and they haven’t been authorized to use that page, they won’t be able to go to the Index page. If you want people to access that web page, remove the [Authorize] off the method.

ActionFilters are very powerful. There are a number of ActionFilters that can compress pages before sending them to the server, remove white space from a page, and even log data after execution.

TryUpdateModel

When we post data back to our POST action method, we need to update our model with the contents of our ViewModel.

Instead of performing the “left=right” syntax, there is a method in the controller called TryUpdateModel. There is also an UpdateModel method as well, but I consider the TryUpdateModel to be more versatile.

While we haven’t talked about Views yet, our HTML View can have a form that looks like this:

@using (Html.BeginForm("Index", "User", FormMethod.Post))
{
    @Html.TextBox("FirstName", String.Empty)
    <span class="input-group-btn">
        <button class="btn btn-default" type="submit">Save</button>
    </span>
}

When the Save button is pressed, the User Controller and Index Action method are called. This is sent back to the POST Index page, not the GET index page. You can specify in the View form which Postback method you want to use (either FormMethod.Post or FormMethod.Get).

[HttpPost]
public ActionResult Index(UserViewModel model)
{
    var user = new User();
    if (TryUpdateModel(user))
    {
        // Save new “user” variable to the database.
        return Redirect("/User/List");
    }
 
    return View(model);
}
​

This is a loaded section to discuss. There is a lot happening in this Action method.

First, we have an HttpPost ActionFilter on our method so we can tell MVC explicitly that this is our POST Index Action method.

The ViewModel is sent to the controller, and we create a new instance of a user.

Next, the TryUpdateModel takes our new instance of a user and tries to map the properties in the model with properties in the user object.

Keep in mind that it also takes into account Validation Attributes while the update is occurring on each field. If a field is required and there’s nothing there, the TryUpdateModel will fail and mark that property with an error message.

If it succeeds, then it will “save to the database” and return to the User Listing page.

If it doesn’t succeed, the model will return to the current View (which contains errors in the model) and display the errors on the page.

Views

Since we just discussed controllers, this is a nice segue into the discussion about Views. A View is the missing piece for a complete MVC cycle and how everything connects.

Views are your HTML pages. They are merely templates with placeholders.

Out of the box, ASP.NET MVC includes two types of ViewEngines: WebForm and Razor. For this tutorial, we’ll be using the Razor syntax.

Let’s get a little ambitious. What if we wanted to send data from a controller to a View?

There are a number of ways we can accomplish this. They are ViewData, ViewBag, TempData, and ViewModels.

ViewData

Defined as a dictionary object in the controller class, the ViewData assigns a key/value pair to pass the data over to the View.

Since this is part of the controller class, we do not need to explicitly pass it to the View. It will automatically send it over.

For example, in our controller above, we can create a variable called “message” and a variable called “customers.”

public ActionResult Index()
{
    // in our controller code.
    var customer = "Jose";
    var account = 1;
    ViewData["Message"] = string.Format("Customer: {0} ({1})", customer, account);
    var customers = new List { "John", "Bob", "Fred" };
    ViewData["Customers"] = customers;
    return View();
}
​

In our View, we can have the following:

<!DOCTYPE html>
<html>
<head>
    <title>Index</title>
</head>
<body>
    @ViewData["Message"]
    <hr />
    <ul>
        @foreach (var customer in (ViewData["Customers"] as List<string>))
        {
            <li>@customer</li>
        }
    </ul>
</body>
</html>
​

In the Razor syntax, you need to prefix your code with an at (@) symbol to display any data from your models.

Quick Tip: If you want to display an at symbol in your View, use two at symbols (@@).

As you can see, this muddies your Views by casting your ViewData as types (List<string>). However, this simple technique to access a dictionary string is not strongly-typed, meaning we don’t have a way to suggest the type of item we want to display in the View.

While this is a good way to pass data, it’s not ideal.

ViewBag

ViewBag is a little bit better when it comes to passing data. It wraps the ViewData and makes the object type dynamic so we can immediately find it in our View.

Here is an example of our controller:

public ActionResult Index()
{
    var customer = "Jose";
    var account = 1;
    ViewBag.Message = string.Format("Customer: {0} ({1})", customer, account);
    var customers = new List { "John", "Bob", "Fred" };          
    ViewBag.Customers = customers;
    return View();
}
​

And our View would look like this:

<!DOCTYPE html>
<html>
<head>
    <title>Index</title>
</head>
<body>
    @ViewBag.Message
    <hr />
    <ul>
        @foreach (var customer in ViewBag.Customers)
        {
            <li>@customer</li>
        }
    </ul>
</body>
</html>
​

ViewBag is much the same as ViewData: set it and forget it. It will automatically be sent over to the View for immediate use.

In our example using ViewBag, we were able to remove our casting of our object types to make the View cleaner, but we can do better than ViewBag and ViewData.

TempData

As a side note, there is another type of dictionary in the controller called TempData. TempData is set once and when the request and response are complete, it is removed and never used again.

A good use of this would be when a user posts data back to the HttpPost action method. If everything went well and we didn’t have any problems with saving our data, we would create a TempData[“Message”] saying “Everything was saved.” and redirect to the HttpGet Index Action Method.

In the HttpGet Action Method, we would check to see if there was a message in the TempData dictionary. If there was, set the ViewBag.Message to the TempData[“Message”].

Here is an example of a controller:

public ActionResult Index()
{
   var customer = "Jose";
   var account = 1;
   if (TempData["Message"] != null)
   {
      ViewBag.Message = TempData["Message"].ToString();
   }
   else
   {
      ViewBag.Message = string.Format("Customer: {0} ({1})", customer, account);
   }
            
   return View();
}
[HttpPost]
public ActionResult Index(FormCollection forms)
{
   if (forms["name"] != "John")
   {
      TempData["Message"] = "This data is only for John. Access Denied.";
   }            
   return RedirectToAction("Index");
}
​

When a post occurs, a message is set in the TempData dictionary. Did you notice the RedirectToAction(“Index”)? This is a type of ActionResult and will redirect the page over to the HttpGet version of Index.

In the HttpGet Index Action Method, we check to see if there is a TempData message. If there is, we set the ViewBag.Message to the TempData “message”. If there isn’t a TempData message, we default the Message to the customer name and customer number.

We show the message in the View using @ViewBag.Message where you want the message to appear.

ViewModels

ViewBag, ViewData, and TempData are great for passing simple data to a View, but what if you have complex data? How do you pass multiple classes, or “models”, over to the View?

This last method is my preferred way of passing data from a controller to a View, and it’s called ViewModels. ViewModels are nothing more than a collection of models in one class.

If we were building a car, we would need parts for this car. So we would have a car frame object, a steering wheel object, and options for the car.

public class CarFrame
{
    public string Manufacturer { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
    public int Year { get; set; }
}
 
public class SteeringWheel
{
    public string Color { get; set; }
    public string Type { get; set; }
}
 
public class CarOptions
{
    public bool AirConditioning { get; set; }
    public bool CdPlayer { get; set; }
    public bool DvdPlayer { get; set; }
    public bool PowerSeats { get; set; }
}
​

If the user wants to see all of the components on one screen, you need to pass all of those objects over.

Let’s create our CarViewModel.

public class CarViewModel
{
    public CarFrame CarFrame { get; set; }
    public SteeringWheel SteeringWheel { get; set; }
    public CarOptions Options { get; set; }
}
​

As you can see, it’s a very simple object. Remember that a ViewModel is strictly a container to hold Models for the View. It’s just a container to transport the data.

That’s all it is.

When you are using ViewModels, there are a couple of things you need to remember.

  • ViewModels are different. When you pass a ViewModel from a controller to a View, you have to pass it through the View() method at the end of your Action method (i.e., return View(myViewModel); )
  • In your View, you need to include the model type at the very top. This explains to the Razor ViewEngine what objects this view will use. For example, our CarViewModel would look like this in the View using the Razor syntax:
    @model <namespace>.CarViewModel
    This step alone provides us with IntelliSense in our Views.

Our controller would look like this:

public ActionResult Index()
{
    var carFrame = new CarFrame
    {
        Year = 2015,
        Manufacturer = "Dodge",
        Make = "Charger",
        Model = "RT"
    };
 
    var wheel = new SteeringWheel();
 
    var options = new CarOptions
    {
        AirConditioning = true,
        DvdPlayer = true,
        CdPlayer = true,
        PowerSeats = false
    };
 
    var viewModel = new CarViewModel
    {
        CarFrame = carFrame,
        Options = options,
        SteeringWheel = wheel
    };
 
    return View(viewModel);
}
​

The ViewModel is like a package that places everything necessary to display an entire “View” of data to the user. Once the ViewModel is built, we pass it over to the View.

Our View will look like the following:

@model  CarViewModel
<!DOCTYPE html>
<html>
<head>
    <title>Car Parts</title>
</head>
<body>
   <p>Car: @Model.CarFrame.Year @Model.CarFrame.Manufacturer @Model.CarFrame.Make @Model.CarFrame.Model</p>
</body>
</html>
​

The ViewModel method of passing data provides a solid way to build your Views using strong-typed objects instead of “magic-strings” or dynamic objects.

As mentioned before, you even receive a bonus of IntelliSense for assisting you in creating your Views.

Routes

Routing is extremely important in ASP.NET MVC. It’s a way to direct each URL to its proper controller and action.

The routes are stored in the App_Start\RouteConfig.cs file. The Default route looks like this:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
​

Most developers keep this standard and don’t modify the routes because of the complexity it could incur on the application.

If you are satisfied with the way your application routes the URL’s with this basic route, then by all means, you can leave it just the way it is and move on with building your application.

However, if you need to make new routes, it’s essential that you understand how it breaks the URL into segments to know which controller is used.

If we have the following URL:

http://localhost/Products/List

and we broke these pieces down to their basic routing components, it would look like this:

  • Domain (http://localhost/) is not used
  • Products is the controller name
  • List is the action name
  • Id would not be used in this case because we didn’t provide it.

If we changed our URL to something like this:

http://localhost/Products/Edit/5

The route would be broken down like this:

  • Again, domain is not used in the routing.
  • Products, again, is the name of the controller.
  • Edit is the name of the Action in the controller.
  • Id would contain the value 5 and be a parameter passed into the Edit Action in the controller.

So your controller would look like this:

public class ProductsController : Controller
{
    public ActionResult Edit(string id)
    {
       // id would equal 5
       return View();
    }
}
​

Now that you’ve seen a couple of examples, let’s break down the MapRoute method to understand what it expects.

The name of the route (“Default” in this case) can be anything you want (preferably something descriptive so you know what route it is). You could even have a route called “BlueberryPie”, but it has to be unique. If you define another route in your RouteConfig, you can’t have another “BlueberryPie” route.

The url parameter is the pattern that your URL will accept to direct you to the proper controller. However, you can easily mess up the route and it could go to a completely different controller.

A simple example would be the http://localhost/Products/List. When this URL is requested, the routing engine analyzes the “Products/List.” It doesn’t look at the domain (http://localhost/) at all.

It takes the first segment of the URL and says, “Since Products is the first parameter and my route url template says the controller is the first segment, Products is the name of the controller.” It processes the List segment the same way and identifies that the List action is in the Products controller.

The id is the last piece of the URL segment. As you can see by the “defaults” parameter, the Id is UrlParameter.Optional. This means we may not have an id to pass into the action method (which is standard for most routes).

The defaults parameter is equally important. Any one of these segments could be missing from the URL. If they are missing, then we define that default controller and default action in the MapRoute.

To crystallize this point a little further, this table is based off of the MapRoute defined above for various URL’s coming into the application.

If the Url is: Controller Action Id
http://localhost/Products/Edit/5 Products Edit 5
http://localhost/Products/Edit Products Edit (empty)
http://localhost/Products Products Index (empty)
http://localhost/ Home Index (empty)

As you can see, routing can get very elaborate, but here are some tips when defining your routes in your application.

  • Keep your routes as simple as possible
    If you have a large number of routes in your RouteConfig.cs, you are doing it wrong. Remember, it’s a template for how your site is structured. It should be a simple scheme on how to get to each controller and action effectively and quickly.
  • Keep a “Route Table” handy in your RouteConfig.cs
    It’s usually a good idea to have some sample URL’s as comments in your RouteConfig.cs to visually confirm that a specific URL is pointing to the proper route.
  • Map out a sample URL
    By all means, copy and paste the format from the table above into your RouteConfig.cs as a comment, use a sample URL from your application, and map out each component to confirm that they are heading to the right controller through the right route.

“Google-Friendly” URL’s

To take routing one step further, let’s create user-friendly and “Google-friendly” URL’s.

How would you create a route for this URL?

http://www.danylkoweb.com/Blog/aspnet-mvc-routing-play-traffic-cop-with-your-routes-90

We know that we are going to a BlogController (because of the Blog directly after the domain). But I don’t think we have an “aspnet-mvc-routing-play-traffic-cop-with-your-routes-90” Action Method in our controller.

So how do you map this route?

routes.MapRoute(
    name: "BlogDetail",
    url: "Blog/{title}-{id}",
    defaults: new { controller = "Blog", action = "Detail", title = String.Empty, id = UrlParameter.Optional }
);
​

Anytime we have a Blog name, it automatically goes to the BlogController class.

Notice the {title}? It’s a way to name the route parameter. You can decide whether you want to use it or not. It doesn’t even need to be a parameter in the Action method.

We don’t have an action in the URL template, but in the defaults, we tell the routing engine to always use Detail action method in the Blog controller.

The only wild card here is the id. It’s the key to loading the proper blog post. We tack the Id onto the end of the URL to know exactly which post to load. Our Detail action method would look like this:

public ActionResult Detail(string id)
{
    // Load the post based on the Id passed in (id=90)
    var model = GetPostById(id);
    return View(model);
}
​

I know routing was a large section, but as I mentioned before, it is definitely an important part of ASP.NET MVC.

Essentially, the routing engine is sophisticated enough to take complex URL’s and break them down into simpler components for proper routing, thus making your application easier to maintain.

Moving forward with enhancements

Now that we have the essentials under our belt, we can move towards some additional features that not only assist you with your development, but actually enhance your application and speed up your development efforts.

Model Enhancements

Model Binders

In WebForms, when you submitted a form, a postback occurred and you would assign all of the user control data from Form into your model’s properties and fields.

In ASP.NET MVC, this process has been abstracted out to a separate process called ModelBinding. Behind the scenes, when you submit a form through a submit button, a default ModelBinder is available to map all of the form data from the View into the current ViewModel and pass that into your controller.

Most of the time, you don’t need to worry about ModelBinders because MVC out-of-the-box takes care of those pesky details for you.

Since we have a default modelbinder, we will create a new one just to show you how easy it is to build a ModelBinder for your needs in case you need one.

Let’s say we wanted to create a Search capability in our web application. Our search model would look like this:

public class SearchViewModel
{
    public string SearchTerm { get; set; }
    public IEnumerable Posts { get; set; }
}
​

To attach a ModelBinder to a ViewModel, we need a ModelBinder attribute on the class.

[ModelBinder(typeof(SearchViewModelBinder))]
public class SearchViewModel
{
    public string SearchTerm { get; set; }
    public IEnumerable Posts { get; set; }
}​

Our new SearchViewModelBinder would look like this:

public class SearchViewModelBinder: DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext)
    {
        var request = controllerContext.HttpContext.Request;
        
        // Can use:
        //    request.QueryString for binding Url Data
        //    request.Cookies for browser cookie information
        //    request.Form for form data posted back.
        var searchTerm = request.Form["q"]; // Access the form variable "q" (for query).
 
        return new SearchViewModel
        {
            SearchTerm = searchTerm
        };
    }
}
​

When the postback occurs, it checks to see if there is a ModelBinder available for this ViewModel in the current View. If not, it uses the DefaultModelBinder. Since we have a custom ModelBinder and we have the attribute attached to the top of our ViewModel, our custom ViewModeBinder will get called.

After the model is created and returned, it’s passed on to the corresponding controller as a parameter to the Action method and your SearchController would look similar to this:

public class SearchController : Controller
{
    public ActionResult Search(SearchViewModel model)
    {
        // model.SearchTerm would have the “q” value from the Form (View).
        // Make a database call to populate your post records.
        // model.Posts = LoadPostsFromDatabase(model.SearchTerm);
        return View(model);
    }
}
​

ModelBinders are great for retrieving data from a postback, and you want to populate a ViewModel so you don’t have to “muddy up” your controllers.

Validation Attributes

Your models are very secluded and keep to themselves.

We need a way to tell the View how to display them, tell the Controller how to validate them, which fields are required, and what labels to show in the form.

Validation Attributes are attributes meant for your Views to find out more about your models. One specific Validation Attribute is the RequiredAttribute.

The Required attribute tells the Controller (and View) that this field cannot be blank and it needs to be filled in.

There are a number of additional validation attributes you can use on your model properties. For example, there is a CreditCardAttribute you could use for validating the entry of a credit card.

Each one is explained at the MSDN site under the DataAnnotations web page.

In our previous example, we had our SearchViewModel. The SearchTerm can have a Required attribute attached to it as shown below:

public class SearchViewModel
{
    [Required]
    [Display(Name = "Search Term:")]
    public string SearchTerm { get; set; }
    public IEnumerable Posts { get; set; }
}
​

We also included a DisplayAttribute for a label next to the search text box.

Now that the Required and Display attribute is on the SearchTerm property, our View will know how to display a label for the SearchTerm and Controller will know how to validate and show an error message if it’s empty.

If we had an HtmlHelper wanting to display a label:

@Html.LabelFor(e=> e.SearchTerm)

the View would look at the SearchTerm property on the Model, examine it, and notice that we have a Display attribute attached to the property. The LabelFor would display “Search Term:” as the label in the View.

Controller Enhancements

Additional ActionResults

We mentioned earlier that we have a number of ActionResults we can use in a controller, and we focused on one called the ViewResult to return our HTML Views.

There are times when we don’t want to return just a ViewResult. We would rather return content, a file, or even JSON (JavaScript Object Notation).

You may have noticed in the Controller section above, in the TryViewModel section, that we checked if the TryUpdateModel was successful, and if it was, we called the Redirect(“/Users/List”) ActionResult. The Redirect ActionResult does just that. It redirects the user to a new page.

While you can create your own ActionResult, you already have a library of them at your disposal.

ActionResultDescriptionHow It’s Used
ViewResultReturns an specific HTML View with optional data.public ActionResult List()
{
// processing done here.
return View "List");
}
RedirectResultPerforms a Redirect to send a user to another View (or page).public ActionResult List()
{
// processing done here.
return RedirectToAction("Create");
}

-OR-

public ActionResult List()
{
// processing done here.
return
Redirect "http://www.cnn.com/”);
}
JsonResultReturns a JSON (JavaScript Object Notation) formatted object. Best used in JavaScript code to return data to the browser.public ActionResult GetJson()
{
var user = new User();
user.FirstName = "JD";
return Json(user, JsonRequestBehavior.AllowGet);
}
FileResultReturns a file to the browser.public ActionResult GetFile()
{
var stream = new StreamReader("yourFileToReturn.txt");
return File(stream.ReadToEnd(), "text/plain");
}
ContentResultReturns raw, unformatted data to the browser.public ActionResult SayHello()
{
var greeting = "Hello World.";
return Content(greeting);
}

There are other ActionResults out there to assist you in your development efforts, and they are extremely easy to use. You make a call to an action method in a controller, process the data, and return an ActionResult.

There are even ExcelActionResults some users have created to return dynamic Excel spreadsheet data.

View Enhancements

UrlHelpers

Action UrlHelper

Links make the Internet world go around. And MVC applications are no exception to the rule.

How can you properly manage an entire list of links for an application?

In your Views, you may have a link that points to a controller/action for viewing products.

<a href="/Products/List" title="Go to a list of products">Products</a>

While this is the hard way of writing your application’s URL’s, UrlHelpers are a better way to build links. They help you with the rendering of your links in your application. They are merely extension methods.

One specific UrlHelper is the Action UrlHelper. The Action UrlHelper can replace the HTML link above with:

<a href="@Url.Action("List", "Products")" title="Go to a list of products">Products</a>

While it looks like it may be a little bit bigger and include more code, it definitely simplifies a link in your MVC application.

When you first start working with MVC, you can run into an ugly issue with links in your Views relatively quickly. Let me set up a scenario for you.

Let’s say you have a 1,000-page website and your boss comes in and says we are renaming the ProductsController to ClearanceController. What happens to all of your links in your 1,000 pages on your site?

It’s a 404 party and you’re invited – broken links all over the place.

You have 1,000 pages where you need to open each one, change the “Products” controller name to “Clearance”, and save the changes 1,000 times (or do a major find/replace in your Views)….

The best solution when you are using UrlHelpers is to centralize all of your links.

For our solution, create a new folder off the root directory called Helpers and a new folder under that called Url. Create a new extension method class called ApplicationUrlHelpers.cs and it will look like this:

public static class ApplicationUrls
{
    public static string ProductListUrl(this UrlHelper helper)
    {
        return helper.Action("List", "Products");
    }
}
​

Note how we abstracted the Action method out of the View and into its own link class. With this in place, your View will look a little different now.

<a href="@Url.ProductListUrl()" title="Go to a list of products">Products</a>

What did we achieve by doing this? A lot:

  1. We have centralized all of the links in our application to one unit (ApplicationUrlHelpers.cs).
  2. This allows IntelliSense to provide a pick list of which URL we want to use in our Views.
  3. You don’t need to change all 1,000 pages of content. In your ProductListUrl extension method, you change “Products” to “Clearance” and you’re done.

UrlHelpers make managing your links a little easier to work with in your application.

RouteUrl UrlHelper

One last note about UrlHelper:. There is another method on the UrlHelper class called RouteUrl.

The UrlHelper.RouteUrl is a faster option for building links. Why?

Remember the Routing section above and when I mentioned that too many routes can slow down your application?

While the UrlHelper.Action method uses “magic strings” to create the URL, the RouteUrl uses the RouteTable (created using the MapRoute method) as a reference to create the URL.

If you have a smaller list of routes for your application, how fast is it to look through a list of one? RouteUrl is definitely a faster approach to link creation in your MVC applications.

If you decided to use RouteUrl, Your ApplicationUrlHelpers.cs would have these changes.

public static string ProductListUrl(this UrlHelper helper)
{
    return helper.RouteUrl("Default", new { @controller = "Products", @action = "List" });
}
​

What we’re doing is forcing a link to be created based on an existing route in the RouteTable.

The first parameter is the name of the route in the RouteTable (remember “BlueberryPie”?).

The second parameter are the values we want for the controller, action, and the optional id if we want to use it.

The best part about this is that you can choose which one is better for your application and your links won’t change in your Views. It still creates the correct link and points to the proper controller and action.

HtmlHelpers

If you’ve used WebForms before and you are using ASP.NET MVC now, you may be missing your server-side controls.

In MVC, the HtmlHelpers are what I would consider the equivalent of the server-side controls.

HtmlHelpers are similar to UrlHelpers, but instead of returning a link, HtmlHelpers return generated HTML or Views.

Of course, there are already a number of HtmlHelpers included with your ASP.NET MVC framework.

You have already been exposed to the TextBox HtmlHelper and the Html.BeginForm() in the TryUpdateModel section above.

@Html.TextBox("FirstName")

All this does is render out a simple textbox with an id and name of “FirstName.”

<input type="text" id="FirstName" name="FirstName" />

These two lines are exactly the same.

Some of the other HtmlHelpers are listed below.

HtmlHelperDescription
@Html.TextBoxFor(e=> e.FirstName)Renders a strongly-typed TextBox based on the View’s Model.
@Html.ActionLink("Product Link", "List", "Products")Creates and renders an HTML link using a controller, action, and link text to place inside the anchor.
@using (Html.BeginForm("Index", "Search", FormMethod.Post, new {@id = "menuAdd", @role = "form"}))Renders the start of a form tag with settings on which controller and action to send the data to and which method to use when posting the data (FormMethod.Post/FormMethod.Get).
@Html.CheckBox("MyCheckbox", true)Create a Checkbox named “MyCheckbox”.
@Html.CheckBoxFor(e=> e.IsAvailable)Renders a strongly-typed Checkbox based on a property in the View’s Model.
@Html.HiddenFor(e=> e.SearchTerm)Renders a strongly-typed Hidden field based on a property in the View’s Model.
@Html.Hidden("SearchTerm", Model.SearchTerm)Creates a Hidden field named SearchTerm with a value from the Model.
@Html.TextArea("BigTextArea")Creates a TextArea called “BigTextArea”.
@Html.TextAreaFor(e=> e.BigText)Renders a strongly-typed TextAreaFor field based on a property in the View’s Model.

If you wanted to create your own HtmlHelper, it’s just as easy as creating a UrlHelper.

Create a directory under your Helpers directory called HTML, and create a ApplicationHtmlHelpers.cs file.

As an example, let’s create an HtmlHelper that displays a message if there aren’t any posts.

public static class EmptyRecordsExtensions
{
    public static MvcHtmlString NoPostsMsg(this HtmlHelper helper, IEnumerable list)
    {
        if (list.Any()) return MvcHtmlString.Empty;
 
        var container = new TagBuilder("div");
        container.AddCssClass("well text-center");
 
        container.InnerHtml = "No posts are available right now.";
 
        return MvcHtmlString.Create(container.ToString(TagRenderMode.Normal));
    } 
}
​

For an extension method to work properly, the class and the method have to be static and you need the this statement in the signature of the method.

We are receiving a list of posts and deciding whether or not any are in there. If it’s a full list, we just return nothing.

If we don’t have a list of posts, we create a DIV tag and add some CSS to the div element. We then set out text inside the div to let the user know that “No posts are available right now.”

Finally, we return the HTML back to the View.

To use our new HtmlHelper, we include the namespace at the top of the View and add it to our View where we want the message to appear.

@Html.NoPostsMsg(Model.Posts)

If no posts are available, the message will appear. If we do have posts, it won’t display anything and we can display all of our posts.

PartialViews

As you continue to write more Views, you’ll start to notice patterns where you are reusing your HTML over and over again.

PartialViews are shared, smaller pieces of HTML reused across your entire site. It allows your site to remain consistent in its design.

For example, if you had a menu on every single page, you can take that HTML and place it into the Views/Shared folder and call it CommonMenu.cshtml.

To call that menu from your View, you would have the following:

@Html.Partial("CommonMenu")

ASP.NET MVC would search through the Views folder and finally find the CommonMenu.cshtml in the Views/Shared folder and load the HTML to display the menu.

If your ViewModel has a list of menus, you can pass the list of menus into your partial view.

@Html.Partial("CommonMenu", Model.Menus)

It’s a quick and easy way to make HTML modules out of your web application.

Conclusion

With these firm fundamentals of ASP.NET MVC, you can now start building your own basic websites using all of the best practices addressed in this tutorial.

As with any subject, there is always more to learn.

Yet, with everything that ASP.NET MVC has to offer, it is constantly evolving and is always exciting to see it turn into something better.

I hope you have enjoyed this tutorial and will post any feedback letting me know if it was helpful.