Web Design that taps into the haromny and vision of your dreams.

Introduction to ASP.Net MVC

By on in Coding

3,779 words, estimated reading time 18 minutes.

Introduction to Programming with C# Series
  1. Introduction to Programming with C# 7
  2. C# Programming Fundamentals
  3. Introduction to Object-Oriented Programming
  4. C# Object-Oriented Programming Part 2
  5. Flow Control and Control Structures in C#
  6. C# Data Types, Variables and Casting
  7. C# Collection Types (Array, List, Dictionary, Hash Table)
  8. C# Operators
  9. Using Data in C# 7 with ADO.Net & Entity Framework
  10. LINQ: .NET Language Integrated Query
  11. Error and Exception Handling in C#
  12. Advanced C# Programming Topics
  13. Reflection in C#
  14. What Are ASP.Net Webforms
  15. Introduction to ASP.Net MVC
  16. Windows Application Development
  17. Assemblies in C#
  18. Working with Resources Files, Culture & Regions
  19. Regular Expressions in C#
  20. Introduction to XML with C#
  21. Complete Guide to File Handling in C#

Introduction to the Microsoft ASP.Net MVC framework showing you everything that you need to build an application using this tool.

What is MVC?

Before we dive into the Microsoft MVC.Net framework, let's first talk a little bit about why it exists. Traditional ASP.NET Web Forms was a way to make developing for the web similar to developing desktop applications using forms. When you click a button on an ASP.NET Web Form, an event is triggered in the code behind which performs an action. This is the same way in which Windows Forms work. Web Forms abstracted away from the technicalities of HTML requests, and even HTML markup. As time moved on, people didn't want this abstraction any more, and looking at other web development methodologies and frameworks, Microsoft decided to adopt the Model View Controller design pattern. Microsoft MVC.Net does not replace web forms, it is another way of doing something. There is still C# of VB.Net code behind, Sessions, Caching and Requests all work in the same way.

The MVC Design Pattern

The MVC Design Pattern has actually been around for decades and across many different platforms and technologies, everything from Smalltalk to C++ to Java.

The general idea with Microsoft MVC.Net is that you'll have a component called the View which is solely responsible for rendering the user interface. That view will talk to a Model, and that model contains all of the data that the view needs to display. Views generally don't have any logic inside of them, with the exception of some HTML and some expressions of where to take pieces of data from the model into the correct places in the HTML template. It's is the role of the controller to tie things together that orchestrates everything. The controller is responsible for building the model, performing any logic and selecting the view. It never interacts with the user interface. That's the job of the view. The controller never holds any data or state inside of it. That's the job of the model.

Microsoft MVC.Net Architecture
Microsoft MVC.Net Architecture

Web Forms versus Microsoft MVC.Net

If you've already been using ASP.NET Web Forms, you may be wondering how the MVC pattern changes the high-level view of how stuff works inside of ASP.NET. With Web Forms, you'll have an incoming HTTP request which will ask for a specific ASPX page. That request is directed to a specific file on the file system and ASP.NET is going to instantiate a class that represents that page and ask it to execute. Inside of here you can have things like a page load method, the page pre-renders method, the page unload method. You can perform all your processing inside of that page. The HTML view contained within that page is really bound to that page, there is little separation between the HTML view and the logic code behind. That makes code re-use and unit testing far more complicated.

In Microsoft MVC.Net, things work a little bit differently. The incoming HTTP request will be routed to the MVC framework, which is going to do is first route that requests to a controller. That controller is going to be a class that you write, and it isn't bound to any particular ASPX file. It is pure C# or VB.Net code (or whatever code you choose to write in). The controller class has regular public instance methods like any other class. There's no page load event handler that has to be invoked. These are simply methods that return results and they take parameters.

Hello World ASP.NET MVC application

So how does MVC know what controller and what method to call? Well, that's all handled by routing. By default, the standard URL structure of an MVC site takes the form of http://domainname.com/home/index. In that example, Microsoft ASP.Net will instantiate an instance of the class for the home controller, and execute a method called index. There are some naming conventions that must be observed. The controller must be named HomeController (home, with Controller as a suffix). Controller classes must reside within a folder called Controllers.

Start off by clicking File > New then selecting New Project. From the screen that appears browse into Templates > Windows > Web and select ASP.NET Web Application. Give your project a name and set the location. In the next window, select MVC. Click ok to create the project. When the project is done creating you should have a solution similar to the one on the right.

You should notice some familiar folders from Web Forms, as well as the Controllers, Models and Views folders. If you expand the folders and look inside, you should see the HomeController.cs and the view for the Homepage.

MVC Application Solution
MVC Application Solution

If you run the application you can browse to the homepage, about and contact pages. The Index method of the HomeController class is the default view for each controller class. You can also see methods for About and Contact. The About method places some data in the ViewBag object. This is used to temporarily store some data which can be used in the View.

If you look in the Views/Home folder you can see the autogenerated views for Index, Contact and About. These are implicitly called when you call View(); from a controller method. You can also explicitly invoke a view by passing it as a parameter e.g. View("Contact");

Creating a Simple Model

A Model is just a class with a series of public properties. There is no naming convention for models, you can name them anything you want, although common suffixes include Model or ViewModel simply to identify them as such, such as CustomerProvileViewModel or SearchResultsModel.

public class DemoModel
{
  public string SampleText { get; set; }
}

Creating a Simple Controller

Controllers have the responsibility for processing data and performing logic. Although you can pass data to the view using the ViewBag, for more than a couple of items it's best to use a model.

A really simple controller would look something like this.

 
public class HomeController: Controller
{
  public ActionResult Index()
  {
    return View();
  }
}

In the example above we can see that the HomeController extends the Controller class, it has a method called Index which returns an ActionResult. Almost all controller actions will return an ActionResult, usually the View or a redirect.

We can create a controller method for the page load which creates an instance of our model, populates some data and returns the data to the view.

To pass a model from a controller to a view, simply pass it as a parameter to the View() method.

 
public class HomeController: Controller
{
  public ActionResult Index()
  {
    DemoModel model = new DemoModel();
    model.SampleText = "Hello World";
    return View(model);
  }
}

Creating a Simple Razor View

The controller must have a view. Views are contained within a folder called Views, and a subfolder with the same name as the controller. The file is named the same as the method name. In this example it would be ~/Views/Home/Index.cshtml.

View pages are equivalent to ASPX pages, although they use slightly different syntax and a different render engine called Razor.

Razor syntax begins with an @ symbol to prefix commands, for example @Html is the razor HTML helper. A simple view is shown below.

@{
    ViewBag.Title = "Home Page";
}
 
<div class="jumbotron">
    <h1>ASP.NET</h1>
    <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
    <p><a href="http://asp.net" class="btn btn-primary btn-lg">Learn more »</a></p>
</div>

To use a model in the view, make a model declaration in the header of the file. Start with @Model then the fully qualified name for the models class.

@Model DemoApplication.Models.DemoModel
@{
    ViewBag.Title = "Home Page";
}
 
<div class="jumbotron">
    <h1>ASP.NET</h1>
    <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
    <p><a href="http://asp.net" class="btn btn-primary btn-lg">Learn more »</a></p>
</div>

Now you can access the strongly typed properties of the model using the @Model helper.

@Model DemoApplication.Models.DemoModel
@{
    ViewBag.Title = "Home Page";
}
 
<div class="jumbotron">
    <h1>@Model.SampleText</h1>
    <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
    <p><a href="http://asp.net" class="btn btn-primary btn-lg">Learn more »</a></p>
</div>

Passing Data Between Controllers and Views

Data is passed between the controller and the view by using the model. The model is a class which contains all the information the view needs to display the page.

When your controller method finishes processing the data and is ready to hand over to the view, it should be calling the View method with the model as a parameter.

public ActionResult ViewEmployee()
{
  Employee employee = new Employee();
  employee.FirstName = "Marta";
  employee.LastName="Jensen";
  employee.Salary = 20000;
 
  return View("ViewEmployee", employee);
}

You can also use two system global properties which can be set in the controller and accessed in the view. These are ViewData and ViewBag.

ViewData is a dictionary, which will contain the data to be passed between the controller and views.

ViewData["Employee"] = employee;
return View("ViewEmployee");

You would then use this in the view by accessing the ViewData collection.

<div>
  @{
      WebApplication1.Models.Employee emp=(WebApplication1.Models.Employee)ViewData["Employee"];
  }
 
  <h1>Employee Details<h1>
  <ul>
    <li>Employee Name : @emp.FirstName@emp.LastName </li>
    <li>Employee Salary: @emp.Salary.ToString("C")</li>
  </ul>
</div>

ViewBag is very similar except that instead of accessing as an array, you access values as a property.

ViewBag.Employee = employee;
return View("ViewEmployee");
<div>
  @{
      WebApplication1.Models.Employee emp=(WebApplication1.Models.Employee)ViewBag.Employee;
  }
 
  <h1>Employee Details<h1>
  <ul>
    <li>Employee Name : @emp.FirstName@emp.LastName </li>
    <li>Employee Salary: @emp.Salary.ToString("C")</li>
  </ul>
</div>

Partial Views

If you want to reuse a view in your web application, you can use what's known as partial views. Partial view is like a regular view, with a file extension .cshtml. We can use partial views anywhere you need to reuse a block of code, for example, a sales order grid which may be shown on customer details page, product pages and sales order details pages. Partial views are analogous to the user control concept in ASP.NET.

When you create a new view, in the popup window you can tick the box which says "Create as partial view". This will automatically give the view the correct file extension and setup the page header tag.

If your view will be shared between multiple areas you can add them to the Views/Shared folder. If your view will only be used on one area you can add it to the area folder.

Including a partial view in your master page is as easy as writing a short tag, much in the same way you would add a control to an ASP.Net page.

@Html.Partial("~/Views/Shared/_SalesOrderGrid.cshtml");

An example master page could include multiple partial views to build the entire page.

<body>
    @{ Html.RenderPartial("_Header"); }
    @Html.Partial("_Sidebar")
    <div class="container body-content">
       @RenderBody()
    </div>
    @{ Html.RenderPartial("_Footer"); }
</body>

In this example we also see calls to RenderPartial and RenderBody. The choice of which to use depends on your requirements. If you need to further manipulate the string being injected in the response stream, you should use Partial; otherwise, go with RenderPartial which faster as it goes straight to the response stream.

Passing data to Partial Views

By default, the view engine passes each partial view a reference to the same view model object it received from the controller. You can also pass in a custom object or better yet a property from the page model.

You can pass data to the partial view by adding it as a parameter when calling Partial or RenderPartial.

@Html.Partial("~/Views/Shared/_SalesOrderGrid.cshtml", Model.Orders);

Render Action Methods

Every time you render a view, the associated controller method is responsible for obtaining the data that is specific to the run action and the subsequent views. Unless working over an Ajax request, the controller is always responsible for serving a full view. To avoid the logic of each controller action method getting spoiled by layout concerns and data retrieval we can use render action methods.

A render action is a regular controller method that you invoke from the view by using Action or RenderAction.

@Html.Action("action")
@{ Html.RenderAction("action"); }

The difference between Action and RenderAction is the same as between Partial and RenderPartial. The Action method returns the markup as a string, whereas RenderAction writes directly to the output stream. RenderAction will always be faster so it's best to use it unless you need to work on the markup as a string before writing it to the output stream.

Validation

ASP.NET MVC uses DataAnnotations attributes to implement validations. DataAnnotations includes built-in validation attributes for different validation rules, which can be applied to the properties of the model class. ASP.NET MVC framework will automatically enforce these validation rules and display validation messages in the view.

AttributeDescription
RequiredIndicates that the property is a required field
StringLengthDefines a maximum length for the string field
RangeDefines a maximum and minimum value for a numeric field
RegularExpressionSpecifies that the field value must match with specified Regular Expression
EmailAddressValidates with email address format
MaxLengthSpecifies maximum length for a string field
MinLengthSpecifies minimum length for a string field

DataAnnotations can be combined you can use as many as you need. You can also provide a validation error message which will be shown on the front end when a validation error occurs. This is done by specifying a message in the ErrorMessage property.

You can apply these data annotations to your model like this.

public class Employee
{
  public int EmplyeeId { get; set; }
 
  [Required]
  public string FirstName { get; set; }
 
  [Required]
  public string LastName { get; set; }
 
  [Required]
  [Range(18,65)]
  public int Age { get; set; }
 
  [Required(ErrorMessage = "The email address is required")]
  [EmailAddress(ErrorMessage = "Invalid Email Address")]
  public string Email { get; set; }
}

When data is submitted to the server you need to check that the data is valid. This is done via a property on the ModelState.

[HttpPost]
public ActionResult Edit(Employee employee)
{
  if (ModelState.IsValid) 
  { 
    // your update code here
    return RedirectToAction("Index");
  }
 
  return View(employee);
}

Using HTML Helper to Create Views Faster

HtmlHelper class generates HTML elements using the model class object in razor view. It binds the model object to HTML elements to display the value of model properties into HTML elements and also assigns the value of the HTML elements to the model properties while submitting a web form. So always use HtmlHelper class in razor view instead of writing HTML tags manually.

Html Helpers are accessed by using the @Html shortcut.

@Html.ActionLink("Register Account", "Register")

This will create an HTML anchor tag with the text "Register Account" which will take you to the register page (calling the Register action method on the controller).

Forms Helpers

Unless you are creating a very limited application, you will want to capture some kind of user input in a form of some kind. MVC makes this very easy using a model and the HTML helpers.

Firstly, create a simple form in the view using the HTML helper methods.

@using (Html.BeginForm())
{
  @Html.AntiForgeryToken()
  @Html.ValidationSummary(true, "", new { @class = "text-danger" })
  @Html.TextBox("Name")
  @Html.Password("Password")
  <input type="submit" value="Sign In">
}

The first line creates a form, it automatically handles the open and close tags and the attributes of the form. The default is to post back to the controller method. The anti-forgery token is used to help protect against cross-site scripting. The process is automatic. The validation summary should be familiar from web forms, it simply shows errors from the form submit. Next, there is a text box field and a password field and a submit button.

Routing

We can use a variety of method attributes on controller methods to control which method is called. One of the most basic attributes is the [HttpGet] and [HttpPost] attributes. These determine which method gets called depending on the URL and the HTTP method.

We can, for example, define two Index methods. One will be called via HTTP Get (initial page load) and the other during HTTP Post requests (form submit).

The controller action to handle this and capture the results will look like the method below.

[HttpGet]
public ActionResult Index()
{
  DemoModel model = new DemoModel();
  model.SampleText = "Hello World";
  return View(model);
}
 
[HttpPost]
public ActionResult Index(string Name, string Password)
{
  DoSomeAction(Name, Password);
  return View();
}

The HttpPost attribute on the method indicates that this method can only be accessed when an HTTP POST is sent to it. The default is GET. The Index method accepts parameters for the two text boxes, Name and Password. MVC automatically extracts the data from the form submit and places them in the properties for you.

You can also show a form for a model for more advanced data capture. In this case instead of @Html.TextBox, use @Html.TextBoxFor and pass in the model property you wish to use.

@using (Html.BeginForm())
{
  @Html.AntiForgeryToken()
  @Html.ValidationSummary(true, "", new { @class = "text-danger" })
  @Html.TextBoxFor(x => x.SampleText)
  <input type="submit" value="Submit">
}

The controller action method can now accept the model as a parameter.

[HttpPost]
public ActionResult Index(DemoModel data)
{
  DoSomeAction(data.SampleText);
  return View();
}

Other attributes you can use are HttpPut, HttpPatch and HttpDelete.

URL Routing and RESTful API's

RESTful API services use a specific URL structure which doesn't natively fit with control action names. We can, however, use custom routing to direct requests to a specific action. The attribute is simply Route and we can use this for all our custom routing needs.

If we don't want to have Index as a controller action and instead insist on it being called Homepage, we can use a route to direct all requests to Homepage instead of Index.

[Route("/")]
public ActionResult Homepage()
{
}

We can add subpages to this controller as well, for example, the URL https://mywebsite.com/about/ can point and serve content from the Homepage controller by routing about to an action method.

[Route("about")]
public ActionResult AboutPage()
{
}

We can even add parameters to the URL which are automatically extracted and passed into a function. Consider a search results page which is paginated and has a URL of https://mywebsite.com/search/3/.

This can be routed to a search method which takes in the page number.

[Route("search/{pageNumber:int}")]
public ActionResult Search(int pageNumber)
{
}

Finally, we can post data to an action and capture the data in a model.

[HttpPost]
[Route("product")]
public ActionResult AddProduct([FromBody]Product newProduct)
{
}

Notice the FromBody attribute. This simply forces the Web API to read the type from the request body which is sent as part of the POST form data.

Bundling and Minification

Bundling and minification are two techniques you can use to improve request load time. Bundling and minification improve load time by reducing the number of requests to the server and reducing the size of requested assets such as CSS and JavaScript.

To enable bundling and minification, set the debug value to "false". You can override the Web.config setting with the EnableOptimizations property on the BundleTable class. The following code enables bundling and minification and overrides any setting in the Web.config file.

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                 "~/Scripts/jquery-{version}.js"));
 
    // Code removed for clarity.
    BundleTable.EnableOptimizations = true;
}

The Bundle class Include method takes an array of strings, where each string is a virtual path to the resource. The following code from the RegisterBundles method shows how multiple files are added to a bundle.

bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
    "~/Content/themes/base/jquery.ui.core.css",
    "~/Content/themes/base/jquery.ui.resizable.css",
    "~/Content/themes/base/jquery.ui.selectable.css",
    "~/Content/themes/base/jquery.ui.accordion.css",
    "~/Content/themes/base/jquery.ui.autocomplete.css",
    "~/Content/themes/base/jquery.ui.button.css",
    "~/Content/themes/base/jquery.ui.dialog.css",
    "~/Content/themes/base/jquery.ui.slider.css",
    "~/Content/themes/base/jquery.ui.tabs.css",
    "~/Content/themes/base/jquery.ui.datepicker.css",
    "~/Content/themes/base/jquery.ui.progressbar.css",
    "~/Content/themes/base/jquery.ui.theme.css"));

Bundles are referenced in views using the Render method, (Styles.Render for CSS and Scripts.Render for JavaScript). The following markup shows how the default ASP.NET internet project views reference CSS and JavaScript bundles.

<!DOCTYPE html>
<html lang="en">
<head>
    @Styles.Render("~/Content/themes/base/css", "~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body>  
   @Scripts.Render("~/bundles/jquery")
   @RenderSection("scripts", required: false)
</body>
</html>
 

Minification performs a variety of different code optimizations to scripts or CSS, such as removing unnecessary white space and comments and shortening variable names to one character. This further reduces the size of the bundled code.

Last updated on: Thursday 11th October 2018

 

Comments

Have a question or suggestion? Please leave a comment to start the discussion.

 

Leave a Reply

Please keep in mind that all comments are moderated according to our privacy policy, and all links are nofollow. Do NOT use keywords in the name field. Let's have a personal and meaningful conversation.

Your email address will not be published.