This is a simple introduction tutorial that can help ASP.NET MVC3 beginners to create a first MVC application. Following the instructions and using code attached to this article, you will be able to create a simple MVC web application and extend it.
Table of Contents
Introduction
In this article, you will find the simplest way to create your first ASP.NET MVC application. This is a tutorial for absolute beginners to ASP.NET MVC. The only prerequisite for following this tutorial is that you know how to use Visual Studio, and understand HTML and C# syntax. Also, I will show you briefly how you can use some jQuery plug-ins so it would be helpful if you know some jQuery syntax. If you are not familiar with jQuery, it is not a problem, you can just skip those parts because they are optional enhancements.
Background
What is MVC (Model-View-Controller)? MVC is a simple architecture where all components are separated into three classes:
Model
- Classes that contain data that will be shown to the user View
- Components that will display the model to the user Controller
- Components that will handle any interaction with the user
In the web framework, the user will enter some URL to the ASP.NET MVC application, and the controller, model, and view will handle this request and return the HTML back to the user. The interaction between the browser and the server that has model, view, and controller components is shown in the following figure:
This simple scenario of processing an MVC request is described in the following steps:
- The user enters in the browser some URL that is sent to the server, e.g., http://localhost/Product/List.
- The user request is analyzed by the framework in order to determine what controller should be called.
- The Controller takes the parameters that the user has sent, calls the model to fetch some data, and loads the model object that should be displayed.
- The Controller passes the model object to the view.
- The View gets data from the model, puts it into the HTML template, and sends the response back to the user browser.
- The browser shows the HTML that is received from the server.
In this example, I will show how you can create a simple application that allows you to list and manage user details using ASP.NET MVC using the Razor syntax.
First, what is Razor? When you create a view component that translates C# data objects to HTML view, you can use several template syntax. Razor is one nice and clean syntax for combining C# and HTML code. In the following listing, you can see a simple example of the Razor syntax:
@{
string name = "Jovan";
var dateOfBirth = new { Day = 8, Month = 12, Year = 1980 };
string[] skills = new string[] { "MVC", "C#", "JQuery", "ASP.NET" };
}
<h2>@name</h2>
<p>Born in year: @dateOfBirth.Year</p>
<ul>
@foreach(skill in skills){
<li>skill</li>
}
</ul>
In the first part, I have defined a few C# variables, and then I have injected them into the HTML code. The resulting HTML output is shown in the following listing:
<h2>Jovan</h2>
<p>Born in year: 1980</p>
<ul>
<li>MVC</li>
<li>C#</li>
<li>JQuery</li>
<li>ASP.NET</li>
</ul>
As you can see, C# code will be discarded and only values from that code will be injected in the HTML template. Putting C# data into HTML with Razor syntax is easy - just put the name of the C# variable with the @
prefix. This works both with simple types and object fields. Even if you have more complex processing such as outputting the list of elements with some loop, the syntax is very clean.
If you are not familiar with Razor, you can see a quick reference here or a full reference on the ASP.NET MVC site.
Note that in this example, C# data is defined directly in the view. However, in the real code, C# data will come from the model that is provided by the controller (see figure above).
Using the Code
To start with this code, you will need to have Visual Studio or at least Web Developer. If you do not have it, you can install it from the ASP.NET MVC site. There you can find all the necessary prerequisites for installing the MVC framework.
Once you install Web Developer, creating an MVC application is easy. Just go to File/New Project, select ASP.NET MVC Web Application, and the wizard will walk you through the setup process.
Here, you should put the name of your project and determine where it will be placed. You can use the default settings if you want. The following sections will explain the structure and elements of the created MVC project.
MVC Project Structure
When you create your MVC web application, it will be organized in the following folders:
- Model containing your model classes.
- Controller where classes named as <CONTROLLER-NAME>Controller are placed. These classes contain the action method that will be called when an HTTP request is sent.
- Views - In this folder, template files that will be used to generate HTML as a response are placed. Views are partitioned into subfolders. Each controller has its own subfolder named the same way as the controller where the controller's views are placed.
- CSS files and images will be placed in the Content folder.
- JavaScript files will be placed in the Scripts folders.
An example of that kind of structure is shown in the following figure:
In this figure, you can see all the components described above. We have two controllers User and School and their views in the /Views/School and /Views/User folders. Views that are placed in the /Views/Shared folder are shared among all controllers and views. Note that views have a .cshtml file extension. This means that they are using Razor syntax for view templates (this syntax is used in this tutorial).
Model
Model can be any class that defines a data structure that will be shown to the user. It can be a plain C# class, an Entity Framework model generated from a database, even a DataSet
(although it is not recommended to use it in MVC). In this example, I will use a plain list of objects as a simulation of the data repository. The examples in this article will display a table of users from the list, show/edit details of a user object from the list, and enable you to add/delete users from the list. The Model
class used in the application is shown in the following listing:
public partial class User
{
public int UserID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Town { get; set; }
public string County { get; set; }
public string Country { get; set; }
public string Email { get; set; }
public DateTime DoB { get; set; }
public bool IsActive { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public int Rating { get; set; }
}
This example will not use persistent data storage (e.g., database). I will put the User
object in a plain list and the application will use it to show user data. An example of that kind of "repository" is shown in the following example:
public class UserRepository
{
public static List<User> Users = new List<User>();
}
Although I will not explain any advanced data access techniques, I will use some simple LINQ queries to find user data from the list. The following listing shows LINQ queries that find users:
var user = userList.First(x => x.UserID == id);
var bestUsers = userList.Where(x => x.Rating > 8);
The first line of code finds the first object in the user list that has property UserID
equal to the ID variable (i.e., finds a user by ID). The second line finds all the users with rating greater than 8.
The form parameter => expression is an inline function (lambda expression) that is used to define the criterion for finding users from the list. It is just a shorter version for the inline function that would look like:
function(parameter){ return expression; }
You can find more information about LINQ queries in the Using LINQ Queries article.
View
View is a plain file that defines a template that will be used to show Model data. In the simplest scenario, you can imagine View as a plain HTML code where are placed positions where you will inject Model
properties. An example of that kind of View is shown in the following listing:
<fieldset>
<legend>User</legend>
<div class="display-label">Name</div>
<div class="display-field">@Model.Name</div>
<div class="display-label">Address</div>
<div class="display-field">@Model.Address</div>
</fieldset>
In this View, an HTML structure that will be shown to the user is defined, and the places where the Model data will be placed. The example will inject the Model Name
and Address
properties into the HTML code. The syntax @Model.<<PropertyName>>
defines a place where the Model
property will be placed in the View
. If you have values "Jane Smith
" for name and "Regent street 12, London
" for address, the following HTML output will be generated:
<fieldset>
<legend>User</legend>
<div class="display-label">Name</div>
<div class="display-field">Jane Smith</div>
<div class="display-label">Address</div>
<div class="display-field">Regent street 12, London</div>
</fieldset>
When you generate complex form elements such as INPUT
, TEXTAREA
, etc., you can use the same approach as the one in the previous example. You can put HTML code for INPUT
and inject some property of the Model directly in the value
attribute. An example is shown in the following listing:
<input name="address" id="address" value="@Model.Address" class="medium-size" />
However, instead of plain HTML, you can use a number of built-in Extension Methods of the HTML class.
@Html.TextBox( "address", Model.Address)
@Html.TextBoxFor( model => model.Address )
The first parameter is the name/ID for the textbox, and the second parameter specifies the value it should have. This helper method will render an INPUT
tag and the type="text"
attribute. In the second example, the TextBoxFor
method is used where a lambda expression that specifies the Address
property is passed. In this case, we do not need to explicitly specify name/id of the input field - the helper method will take it from the property name. There are other helper methods that can be used to generate other form elements:
Html.DropDownListFor()
Html.CheckboxFor()
Html.RadioButtonFor()
Html.ListBoxFor()
Html.PasswordFor()
Html.HiddenFor()
Html.LabelFor()
You can also add your own methods that render some of your custom HTML such as Html.Table()
, Html.Calendar()
, etc. You can see more details in Creating custom helpers on the MVC site. You can also generate HTML without specifying the type using the Html.DisplayFor
and Html.EditorFor
methods. An example is shown in the following listing:
@Html.DisplayFor( model => model.Address )
@Html.EditorFor( model => model.Address )
In these methods, we have not specified the type of input at all, because it will be determined based on the type of the property that should be shown. As an example, if the type of the property is string
, EditorFor
will generate text input. A more interesting example is when you pass some object to EditorFor
. By default, the EditorFor
method will generate an INPUT
element for each property in the object based on the type (e.g., text input for string, checkbox for boolean, etc.). DisplayFor
will do the same except that it will render non-editable markup. You can find more details about the display templates here. However, the true power of these methods can be seen when you create custom templates for object types. This is a more advanced topic but if you are interested in this, you can see this article for more details.
Now back to basics - how do we add a new View
? In the folder structure above, you can see the Views folder and the subfolders called User, School, Shared, etc. Just right-click on the folder where you want to put the View, go to Add New View, and the following dialog will be shown to you:
Here, you can enter the name of the View (usually, it is the same as the name of the controller action) and the type of the Model
object that will be shown. Also, you can add an empty View and start coding it, or you can select some of the predefined templates for list, details, edit, create, or delete.
You can imagine Views as separate pages that will be shown to the user. However, there are a few other types of Views (described below).
Layout Page
When you are creating a set of pages, probably you will need to use the same elements on many pages. As an example, all pages will have the same menu, the same CSS/JavaScript files included, etc. In ASP.NET MVC, you do not need to copy the same elements on each page. You can use the so-called layout pages where a general layout of the entire MVC application will be defined and used on each View page. An example of a layout page that will be used in this project is shown in the following listing:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>This is a title of the page</title>
<link href="/Content/Site.css" rel="stylesheet" type="text/css" />
<script src="/Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
@RenderSection("PageScripts",false)
</head>
<body>
@RenderBody()
</body>
</html>
As you can see, in the layout page, I have included all the necessary CSS/JavaScript files that will be used across all pages. Also, I have defined two custom placeholders where each View will put specific content. These two placeholders are:
- Section
PageScripts
- where each page will be able to put some JavaScript or CSS files that will be required only on that page. RenderBody
statement that defines where the content of a particular View will be injected in the general layout.
Partial Views
Another way to organize and reuse your View
code is to put elements that are used on several Views into separate files. These are not standalone Views that are shown to the user - these are only partial views that are included on other main View pages.
Partial Views are HTML templates as regular Views. An example of a partial view that shows the current date is shown in the following listing:
_CurrentDateView.cshtml
<div class="now">Current date is @DateTime.Now.ToString()</div>
Whenever you need to include this partial view, you can just call it by name as shown in the following example:
@Html.Partial("_CurrentDateView")
In the place of the call, the entire content of the View
will be included. You can put this statement in standard views, layout pages, and even in other partial views.
Controller
Controller is the heart of the processing logic in MVC model. When a URL is sent to an internet application in the format /<<Controller>>/<<Action>>/<<Parameter>> (e.g., /User/Details/1), it will be parsed and the class called <<Controller>>Controller
(e.g., UserController
) will be found, the method <<Action>>
in that controller will be called (e.g., method Details
in the above URL), and the parameter will be passed to that method. The Controller will perform all the necessary processing - it will find a Model and pass it to the View.
The Controller can have any public
method with arbitrary parameters that will be passed. As an example, the following listing shows the Controller
called ExampleController
with a method ControllerAction
that receives three parameters - id
, name
, and flag
.
public ExampleController
{
public ActionResult ControllerAction(int id, string name, bool flag)
{
var model = GetModel(id, name, flag);
return View(model);
}
}
You can call this Controller
's action using the following URL:
/Example/ControllerAction?id=17&name=test&flag=true
This is the default mapping between URL routes and controller/actions where the first word in the URL represents a controller name, and the second one is the action method name. However, you can modify it and add your own routing mapping rules. You can see more details about the custom routing in the Creating custom routes article.
The Controller
will automatically map parameters from the request to the method arguments by name. This is useful if you have a form with many parameters that can be automatically read from the request and the user in the action method body.
How you can add a new Controller
? It is similar to adding new Views - go to the Controller folder, right-click, and add a new Controller
. The following dialog will be shown:
Here, you can enter the name of the Controller
- note that it must be in the format <<Name>>Controller
. Also, you can choose one of the predefined templates - empty controller, controller with list, details, edit, create, and delete actions, and controller that is already connected to the database via Entity Framework. In this example, I have started with an empty controller. Once you create an empty controller, you can add action methods in the following format:
public MyController{
[Get]
public ActionResult MyAction()
{
return View();
}
}
The action method should return a view that will display the HTML in the browser (ActionResult
type in the example above). By default, if you add the MyAction
method in the MyController
class, it will be called when the /My/MyAction URL is sent. You can change this behavior, but it will not be described in this beginner level article. Also, you might notice the [Get]
attribute that is placed before the method. This attribute tells the action that it should react only to a GET
HTTP protocol. As an alternative, I could set [Post]
instead of [Get]
or I could leave it blank so the action would be opened on both GET
and POST
protocols.
Also, you must have noticed that the last statement in the action is return View()
. If an action MyAction
is placed in MyController
, this statement will find the MyAction.cshtml View in the My folder in the Views section. This is the default rule for returning Views in action methods. If you do not want to use this default view, you can choose what View
should be returned by specifying the View name
, e.g.,
return View(name);
Note that you have an easy way to go to the View
, or to add a View
for a particular action. Just right click on the action and you will see a context menu that will enable you to add a View for this action. Add View action will open the "Add View" dialog as in the previous section. If a View with the same name as an action already exists, "Go to view" will open the view page.
jQuery
Although it is not a direct part of MVC, jQuery is a very useful JavaScript library that can enable you to enhance your user interface. The first useful thing you will be able to do is easily find HTML elements in the HTML. Some of the simplest queries are shown in the following table:
jQuery selector | Description |
$("table") | Find all table nodes in the HTML |
$("#Name") | Find elements in the HTML with ID Name |
$(".required") | Find all elements in the HTML that have CSS class "required " |
$("table a.delete") | In any table, find all A tags that have CSS class "delete " |
$("table tr:odd") | Find all odd rows in the table |
Once you find elements with jQuery selectors, you can hide them, change their color, attributes (classes, values, inner text), add some event handlers to them (click, double click), etc. An example of the code that attaches a click handler to the link is shown in the following listing:
$('a').click(function (event) {
event.preventDefault()
});
Also, jQuery contains a set of useful plug-ins that enable you to enhance your UI elements. Some examples are shown in the following table:
Plug-in | Description |
$("input.calendar").datepicker() | Add date picker (calendar) dialog on each input element that has CSS class "calendar " |
$("form").validate() | Add JavaScript validation on the form |
$("table").dataTable() | Add JavaScript sorting, pagination, and filtering in the table |
You can find more details and tutorials about jQuery on the jQuery documentation site. There is also an interesting article "jQuery for beginners" where you can find some interesting examples. This is optional, but very easy and useful to add in the MVC application. Note that when you create an MVC application, jQuery will be automatically included in the project. However, plug-ins are not part of core jQuery that is included in the MVC project so you will need to find them and put them in your project manually.
How can you use this JavaScript code? First, you will need to include the jQuery library from the jQuery download page. In your MVC project, you will probably find this library included in the scripts folder so you can just add a reference to this script in the layout page. Then you will be able to use this library - an example is shown in the following listing:
<script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("table").fadeOut("slow");
}
</script>
In this example, I have included jQuery version 1.7.1. and added a fade out effect on the table
element. Note that this statement is placed in the document ready wrapper. Using this wrapper, any JavaScript code within it will be called when an entire document is loaded and ready to be processed. This is a common practice in jQuery programming. Here, I have added jQuery code as an inline script, but you can put it into a separate file.
Creating Your First MVC Application
In this section, I will show how you can create a simple MVC application that lists, edits, creates, and deletes users.
List/Index Page
On the list page, a table with a list of users in the repository will be displayed. The page will be opened when the /User/Index URL is called. Therefore, we would need to create an Index
method and place it in the UserController
class. An example of the Index
method is shown in the following listing:
public ActionResult Index()
{
var model = UserRepository.Users;
return View(model);
}
This method is fairly simple. It takes a list of users from the repository and passes it to the View. The list view takes this list and displays a table as shown in the following listing:
<table class="display">
<thead>
<tr>
<th>
Name
</th>
<th>
Address
</th>
<th>
Town
</th>
<th>
County
</th>
<th>
Rating
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@item.Name
</td>
<td>
@item.Address
</td>
<td>
@item.Town
</td>
<td>
@item.County
</td>
<td>
@item.Rating
</td>
<td>
<a href="/User/Details/@item.UserID">Details</a> |
<a href="/User/Edit/@item.UserID">Edit</a> |
<a href="/User/Delete/@item.UserID" class="delete">Delete</a>
</td>
</tr>
}
</tbody>
</table>
As you can see, this list view has taken a collection of user objects and outputs them as an HTML table in the foreach
loop. Note that you do not need to create an HTML wrapper with head
and body
tags. These are defined in the layout page, and this part of the HTML code is just injected in the middle of the page (the RenderBody
statement in the layout page above). An example of the list page is shown in the following figure:
Applying the jQuery DataTables Plug-in
The table you saw is just a plain table without any functionality. However, you can easily enhance this table with the jQuery JavaScript library to add some advanced features such as sorting, pagination, filtering, etc. In the layout page, you saw that I have put a PageScripts
placeholder that allows each view to put some custom JavaScript or CSS. In this example, only on the list page, I will add some JavaScript that will enhance this table. An example of this additional script is shown in the following listing:
@section PageScripts{
<link href="/Content/dataTable/demo_table.css" rel="stylesheet" type="text/css" />
<script src="/Scripts/jquery.dataTables.1.8.2.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("table").dataTable();
}
</script>
}
This script has included jQuery DataTables CSS and JavaScript files, and applied DataTables function on the HTML table. As a result, you will convert this plain table to a feature-rich table shown on the following figure:
I will not explain how this jQuery plug-in can be used in more detail, but if you are interested, you can take a look at the Enhancing HTML tables using the jQuery DataTables plug-in article.
Details Page
On the details page, information of a particular user by ID will be shown. The request that is sent to the server-side is in the following format:
/User/Details/123
In this request, you can see that UserController
will be called, and that the Details
method with parameter 123 will be executed. 123 is the ID of the record that will be shown. The Details
method will take the ID of the user, find this user in the model repository, and pass it to the view:
public ActionResult Details(int id)
{
var model = UserRepository.Users.First(user => user.UserID == id);
return View(model);
}
The View is also simple - it receives the user
model object and injects user properties into the view. Part of view is shown in the following listing:
@model JQueryMVC.Models.User
<h2>User Details</h2>
<fieldset>
<legend>User</legend>
<div class="display-label">Name</div>
<div class="display-field">
@Model.Name
</div>
<div class="display-label">Address</div>
<div class="display-field">
@Model.Address
</div>
<div class="display-label">Town</div>
<div class="display-field">
@Model.Town
</div>
<div class="display-label">County</div>
<div class="display-field">
@Model.County
</div>
</fieldset>
You can notice that most of the page is plain HTML - we have only placed model properties in some parts of the HTML code. As a result, the following user details page will be shown:
Note that in the listing above, I have placed just a part of the view. You can find the complete listing in the attached source code.
Edit Page
The edit page is very similar to the details page. The Controller
will receive the same parameter (ID
), find an object with that ID
, and pass it to the view.
public ActionResult Edit(int id)
{
var model = UserRepository.Users.First(user => user.UserID == id);
return View(model);
}
The view is similar to the details view except that instead of the DIV
element for displaying plain labels, here we are using an HTML input element. In the following listing, part of the edit view is shown:
<form method="post" action="/User/Edit/@Model.UserID">
@Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<input type="hidden" name="UserID" id="UserID" value="@Model.UserID" />
<div class="editor-label">
<label for="Name">Name</label>
</div>
<div class="editor-field">
<input type="text" name="Name" id="Name" value="@Model.Name" />
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
<label for="Email">Email</label>
</div>
<div class="editor-field">
<input type="text" name="Email"
id="Email" value="@Model.Email" />
@Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
<label for="DoB">Date of birth</label>
</div>
<div class="editor-field">
<input type="text" name="DoB" id="DoB"
value="@Model.DoB" class="calendar"/>
@Html.ValidationMessageFor(model => model.DoB)
</div>
<div class="editor-label">
<label for="IsActive">Is Active</label>
</div>
<div class="editor-field">
<input type="checkbox" name="IsActive"
id="IsActive" value="@Model.IsActive" />
@Html.ValidationMessageFor(model => model.IsActive)
</div>
<div class="editor-label">
<label for="UserName">User name</label>
</div>
<div class="editor-field">
<input type="text" name="UserName"
id="UserName" value="@Model.UserName" />
@Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
<label for="Password">Password</label>
</div>
<div class="editor-field">
<input type="password" name="Password"
id="Password" value="@Model.Password" />
@Html.ValidationMessageFor(model => model.Password)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
There are also a few validation elements placed after inputs - these will be described later. The edit page is shown in the following figure:
We have seen the action that reads a user from the list and passes it to the view, but we would also need an action that will handle update requests that are sent when someone updates user data. The Action
that handles POST
requests is shown in the following listing:
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
var model = UserRepository.Users.First(user => user.UserID == id);
try
{
UpdateModel(model);
return RedirectToAction("Index");
}
catch
{
return View(model);
}
}
This action takes the ID of the user that is currently being edited and user parameters that are entered in the HTML form via the form collection. Then, it finds the user by ID
and updates it. If everything is fine, the Index view will be shown, otherwise if an error occurs, the same view will be shown again.
Adding the jQuery DatePicker
In this example, the date of birth (DoB
property) is entered as plain text. Instead of plain text input, I will attach a jQuery DatePicker
to this field so the user can select a date from the calendar popup. In order to integrate the jQuery DatePicker
, I will put the following custom script in the edit view:
@section PageScripts{
<link href="/Content/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css" />
<script src="/Scripts/jquery-ui-1.8.11.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("input#DoB").datepicker();
});
</script>
}
This custom script will include all necessary JavaScript and CSS files (jQuery UI) and put DatePicker
on the input element with an ID DoB
. As a result, the following calendar will be opened each time the date of birth is edited:
This is another example of how you can, with a few lines of code, enhance your user interface.
Create Functionality
When new users should be created, a blank form similar to the edit form should be shown. The URL of the create form will be:
/User/Create
As this form does not contain any data, the Create
action of the controller is very simple:
public ActionResult Create()
{
return View();
}
This action does nothing useful - when the /User/Create page is called, it just returns an empty view. Part of the view of the Create
page is shown in the following listing:
<form action="/User/Create" method="post">
@Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.IsActive)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.IsActive)
@Html.ValidationMessageFor(model => model.IsActive)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Password)
@Html.ValidationMessageFor(model => model.Password)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</form>
This is a simple form that contains INPUT
fields where can be entered user information. Note that in this case, we might use plain HTML input elements as in the edit example; however, in this case, I have used the MVC LabelFor
and EditorFor
functions. As a result, the following form will be shown:
There is no difference between plain HTML and MVC helper functions - both ways will generate standard HTML input. If you use plain HTML, it would be easier to modify HTML code, but if you use an editor, it will automatically generate text inputs or check boxes, depending on the type of the property (string
, bool
, etc). Also, one advantage of the EditorFor
function is that it can handle situations where the model is null
(in plain HTML mode, you will need to add some conditions to check if there is any data that can be displayed). However in practice, I believe that you will use both ways depending on your particular need. As in the edit example, we would need another action that handles requests that will be sent when information in the form is posted to the server. This action is shown in the following listing:
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
var user = new User();
UpdateModel(user);
UserRepository.Users.Add(user);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
This action is similar to the action that updates user data in the previous section. However, in this case, instead of finding a user by ID, a new user object will be created, updated with posted form parameters, and added to the list. If everything is fine, the index will be shown, otherwise create view will be shown again.
Delete Functionality
A standard delete page can be created the same way as other pages. You can create a Delete view that will show a confirmation page to the user, deletes user from the model, and then returns back to the list. However, in this case, I will show how you can create AJAXified functionality that deletes user data.
I will not create a separate delete view - I will modify the list view that is already created where we have already placed a delete link in each table row. In the list view, I will attach a jQuery AJAX call that deletes data on the server-side and removes the row from the table. The request that is sent to the server-side is in the following format:
/User/Delete/123
In this request, you can see that UserController
will be called, and that Delete
method with parameter 123 will be executed. 123 is the ID of the record that will be deleted.
First, I would need to attach a jQuery event handler to the delete link that is placed in the table. This code will not be just a few lines, therefore it is not convenient to put it directly in the view. Therefore, this script should be placed in a separate JavaScript file (e.g., delete-user.js). In the PageScripts
section of the index.cshtml view should be placed a reference to this file:
@section PageScripts{
<script src="/Scripts/delete-users.js" type="text/javascript"></script>
}
Why are we placing it in a separate file? First, it is not good practice to mix HTML and JavaScript in the same view. If your JavaScript code is just a few lines of code, it is fine, but if you have a significant amount of code it would be better to move it into a separate file. Also, if JavaScript functionality is placed in a separate file, it can be cached in the browser because the content of this file will not be changed. This way view that is always changed will be significantly smaller so it will be loaded faster, and the JavaScript file will probably be already available in the browser cache when the page is loaded the second time.
The actual implementation of the delete user functionality in the delete-user.js file is shown in the following listing:
$(document).ready(function () {
$("table a.delete").click(function (event) {
event.preventDefault();
var link = this;
if (confirm("Are you sure that you want to delete this user?")) {
$.ajax({
type: "POST",
url: link.href,
success: function (data) {
$(link).parents("tr").remove();
},
error: function (data) {
alert("This user cannot be deleted");
}
});
}
}
);
});
In this code sample, I have attached a function on the link that is placed in the table, which has the "delete
" class. This function will be called when the delete link is clicked. The first thing you will need to do is to prevent the default event action because you will replace it with a custom AJAX call. Then, the event handler asks the user to confirm that he wants to delete the current row. If he confirms it, this function takes the href
attribute of the link and creates the AJAX call to the server side page. If the delete request succeeds, the row will be removed from the table, otherwise an error message will be shown. On the server-side, we would need a Delete
action that will be called when the AJAX request is sent in the error handler.
Also, note the first line in the JavaScript file that references the jQuery library. This line is just a plain comment and it does not do anything in the browser. However, if you are using Visual Studio/Web Developer, and if you have the jquery-1.7.1.vsdoc file, using this line, you will have Intellisense support for JavaScript. When you type $.
, you will see a list of all the JavaScript methods that are available in the jQuery library with their descriptions (it is almost identical to the Intellisense support for regular C# code). See more details about JavaScript intellisense here.
The Controller action that handles the delete request is shown in the following listing:
public void Delete(int id)
{
var model = UserRepository.Users.First(user => user.UserID == id);
UserRepository.Users.Remove(model);
}
This action takes the ID from the request, finds an object from the repository by ID, and removes it from the list. In the real code, you would create some DELETE
SQL code, or delete the object from the Entity Framework model.
Search
The last functionality that will be shown here is user search. This will not be a separate page - I will create a partial view that can be placed on any page. The partial view is shown in the following listing:
_SearchUsers.cshtml
<form method="post" action="/User/Search">
<fieldset>
<legend>Search for users</legend>
<div class="editor-label">
<label for="active">Is Active</label>
</div>
<div class="editor-field">
Yes<input type="radio" name="active"
id="active" value="true" />
No<input type="radio" name="active"
id="active" value="false" checked="checked" />
</div>
<div class="editor-label">
<label for="rating">Minimal Rating</label>
</div>
<div class="editor-field">
<input type="text" name="rating"
id="rating" value="0" />
</div>
<input type="submit" value="Search" />
</fieldset>
</form>
As you can see, I have just created a form with an active radio button and a minimal rating text field. You can put it on any view using the @Html.Partial("_SearchUsers")
statement. Whenever you put this statement, MVC will inject the following form in the view:
When the Search button is pressed, parameters in the form are sent to the /User/Search URL, therefore we would need a controller that will accept form data and perform search for users. The search action is shown in the following listing:
public ActionResult Search(bool? active, int? rating)
{
var model = UserRepository.Users.Where
(user => user.IsActive == active && user.Rating > rating);
return View("Index", model);
}
First, you can see in the method signature, method arguments that match the form elements by name. When the form is sent, form parameters will be placed in these arguments. This action finds all users where the IsActive
flag is equal to the value selected in the form, and Rating is greater than a value entered in the form input.
Note that in this case, I have not created a view for showing search results. In standard case, I would need to create a Search view that will receive users that match the search condition and displays them in some kind of table. However, as I already have that kind of view (Index), I will use this one.
The result of this query (model) is passed to the view called Index
. The Index view does not care what controller has called it - it will just show the Model that is provided. As a result, you will see users filtered by the search criterion on the index page. You can see that I have used a View("Index", model)
call instead of View(model)
, in order to prevent the Controller
action to match view by action name.
Validation
One of the most important things that should be added in the application is validation. As an example, you need to put some validation rules that check if the user name was entered, is the date of birth a valid date, is rating in the range from 0 to 10, etc. If some validation rules are not satisfied, error messages similar to the ones on the following figure will be shown:
In the view page, you already saw that I have placed ValidationFor
elements. An example of the validation placeholder that will show an error message when an error occurs in the DoB
property is shown in the following listing:
<div class="editor-label">
<label for="DoB">Date of birth</label>
</div>
<div class="editor-field">
<input type="text" name="DoB" id="DoB" value="@Model.DoB"/>
@Html.ValidationMessageFor(model => model.DoB)
</div>
This code is used to show a validation message, but you will need to implement some rules that will check if the validation requirements are satisfied. In this article, I will show you three ways to implement validation rules:
- Using Data Annotations in the model
- Using Annotations in the model metadata class
- Using explicit rules
You can find more details about validation in the ASP.NET MVC3 Validation Basics article.
Using Data Annotations
The simplest way to implement validation is to put annotation attributes in the model class. As an example, I will put the [Required]
attribute in the Name
property of the user.
public partial class User
{
public int UserID { get; set; }
[Required]
public string Name { get; set; }
public string Address { get; set; }
public string Town { get; set; }
public string County { get; set; }
public string Country { get; set; }
public string Email { get; set; }
public DateTime DoB { get; set; }
public bool IsActive { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public int Rating { get; set; }
}
If the user does not populate the name of the user, UpdateModel
will throw an exception, and the required field message will be shown in the view.
Using a MetaData Class
Sometimes you are not able to modify a model class, especially if it is automatically generated. In that case, you can create a MetaData
class for the model class, where you will place validation rules. An example is shown in the following listing:
[MetadataType(typeof(UserMetadata))]
public partial class User
{
public class UserMetadata
{
[StringLength(50), Required]
public object Name { get; set; }
[StringLength(5)]
public object Email { get; set; }
[Range(0, 10)]
public object Rating { get; set; }
}
}
In this case, in the model class is defined that UserMetaData
will be the meta data class of the User
class where validation rules will be placed. In the metadata class, you can put properties named the same way as properties of the model and put annotations there. This is a useful way to implement validation even if you can modify your original model classes but you do not want to mix validation rules and properties. The only prerequisite is that the model class is defined as partial so we can put the second part of the class in a separate file.
Custom Validation
The third option is to put custom validation rules directly in the controller code. An example of explicit setting of error messages in the controller is shown in the following listing:
ModelState.AddModelError("Country", "This is useless message attached to the 'Country' input");
The method AddModelError
takes the ID of the input element where the error label should be shown and the text of the error message. This code is placed in the action method of the controller and it puts a new error that will be associated to the Country
input.
Advanced Topics
In this section, you can find some advanced topics in the MVC framework. These are not really beginner level items, but I believe that it might be a good guidance for further investigation.
Routing
As you already saw, the MVC framework maps URLs to controller and actions. As an example, if you have a URL such as http://localhost/User/Details/1, it will be mapped to the UserController
and the Details
method. This is not a hardcoded rule for mapping. If you open the Global.asax.cs file, you might see the following part of code:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
In this code, the default route that will be used to map a URL pattern to the Controller/Action is defined. The first token {controller}
will determine what controller will be called, second one {action}
will be mapped to the method, and the last one that is optional will be sent as an ID. Also, here are specified default values. If you type just http://localhost/User/, the Index
method will be called although the action is not specified. If you type in just http://localhost/, the UserController
will be called with the default Index
method. If you want to use different routes, you can add your custom rules. As an example, I will add this rule for user search:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Search",
"Search/{keyword}",
new { controller = "User", action = "SearchByKeyword",
keyword = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
The "Search
" rule will take the URL that starts with /Search and call the Search
method in the UserController
. The first token after search will be passed as a keyword to the SearchKeyword
method. As an example, if you put http://localhost/Search/Andersson in the browser, UserController
will be called and in the method Search
will be passed the string "Andersson"
. The only thing you need to do is add the action that will perform the search - something like in the following listing:
public ActionResult SearchByKeyword(string keyword)
{
var model = UserRepository.Users.Where(user => user.Name.Contains(keyword));
return View("Index", model);
}
You can define any route you want here. Note that this controller can be called with a default route too. As an example, if you type in http://localhost/User/SearchByKeyword?keyword=Andersson, the same action will be called because it is mapped with the second rule.
Areas
In the standard application, you have one set of controllers/views placed in root folders. However, you can create different sets of controllers and views that will be placed in separate areas. If you right-click on the project, go to Add > New Area, you will be able to create new sub areas of your application. New areas will be placed in the Areas folder with separate Model, View, and Controllers, as shown in the following picture:
Here, you can see two areas in the application called Admin and Site. Also, you will have different URLs for each area with a separate routing mechanism. By default, controllers in the area are called via the <Area>/<Controller>/<Action> format (e.g., Admin/User/Index or Site/User/Search). New routes are defined in the AreaRegistration.cs file that is placed in each area. As an example, if you create an Admin area, the following code will be added in the AdminAreaRegistration.cs file:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
This code adds a new mapping rule that maps requests sent in the area to the area controllers. You can also add your own mapping for the areas here.
View Bag
In the standard way of usage, your controller will pass a model to the view (or a collection of objects). However, sometimes, you might want to pass several different objects that are not part of the Model. As an example, you might want to pass information that will be placed as meta-tags in the heading (title of the page, meta-keywords, and meta-description). If this information is not already calculated from the Model, it might be difficult to pass different sets of objects from the Controller to the View.
If you need to pass additional objects besides the Model, you can use the ViewBag
collection. ViewBag
is a set of dynamic properties that can be sent to the View. An example of adding additional properties in the bag is shown in the following listing:
public ActionResult Index()
{
ViewBag.Title = "Index page";
ViewBag.SeoDescription = "Description of the page";
ViewBag.SeoKeywords = "MVC, ASP.NET, CodeProject";
var model = UserRepository.Users;
return View(model);
}
In the View
, you can use properties from the view bag the same way as in standard Model
objects. An example is shown in the following listing:
<html>
<head>
<title>@ViewBag.Title</title>
<meta name="description" content="@ViewBag.SeoDescription">
<meta name="keyword" content="@ViewBag.SeoKeywords">
</head>
<body>
</body>
</html>
If you need to display some information from the configuration/resource files, read them from the database, or from properties/methods of another class, it is better to load them in the controller and then pass them to the view via ViewBag
.
Custom View Templates
In the examples above, I have described how you can use HTML helper methods for generating HTML instead of writing plain HTML directly in code, and injecting values of the Model. As an example, you can generate inputs and checkboxes for the Name
, IsActive
, and Password
properties using the following code:
@Html.EditorFor(model => model.Name)
@Html.EditorFor(model => model.IsActive)
@Html.EditorFor(model => model.Password)
When you call the Html.EditorFor
method, it will check what is the type of the property and then use a template for editing that type. By default, inputs with type text use the editor for string
s and DateTime
, checkbox
for bool
, etc.
However, you can define your own custom display and editor templates that will be applied depending on the type. You just need to create partial views in the format <TypeName>.cshtml and put them into the /DisplayTemplates and /EditorTemplates subfolders. When the Html.DisplayFor
helper method is used, the MVC framework will try to find what template should be used based on the type of the property that will be displayed. If you have a matching <TypeName>.cshtml file in the /DisplayTemplates folder, the framework will use that template for displaying the object instead of the default one. The same logic applies to the editor templates. As an example, imagine that you want to render DateTime
properties in the INPUT
textbox where is added class "calendar
". Instead of putting class "calendar
" in every occurrence of input
, you can define a type-specific editor template that will be used. In this case, you can create the DateTime.cshtml file in the /EditorTemplates subfolder and this template will be used to render the editor for each DateTime
property. An example of the DateTime.cshtml file is shown in the following listing:
@inherits System.Web.Mvc.WebViewPage<System.DateTime>
@Html.TextBox("", (Model.ToShortDateString()), new { @class = "calendar" })
You can put the EditorTemplates folder in the /Views/Shared folder, in the /Views/User folder, or in both as shown in the following figure:
If you put it in the /Shared folder, it can be applied in any View in the application. However, if you put it in a specific folder (e.g., /User) it will be applied only in the Views in this folder. Use custom view templates if you want to change the default way in which certain types of data should be shown.
Extension Methods
I mentioned above, you have a lot of helper methods in the HtmlHelper
class that can be used to generate text boxes, check boxes, password fields, etc. Some examples are shown in the following listing:
@Html.TextBox("Name", Model.Name)
@Html.TextArea("Address", Model.Address)
@Html.CheckBox("IsActive", Model.IsActive)
However, if you need more types, you can add them by extending the HtmlHelper
class. Imagine that you want to have a method that generates a calendar as in the example above (input with class calendar
). You can add the following DateTime
helper extension:
namespace System.Web.Mvc
{
public static class HtmlDateTimeExtension
{
public static MvcHtmlString DateTime
(this HtmlHelper helper, string name, string label, DateTime val)
{
return MvcHtmlString.Create( String.Format(@"<label for='{0}'>{1}</label>
<input type='text' name='{0}' id='{0}' value='{2}' class='calendar'/>",
name,
label,
val.ToShortDateString()) );
}
}
}
The only thing you need to do is to add a new static
method that has as the first argument this HtmlHelper
helper, and this method will be added to other HtmlHelper
static
methods. Other arguments will be used as parameters of the method. This method should return an HTML string
that will be placed in the output HTML. Now you can generate DateTime
input directly using the HTML class, as shown in the following listing:
@Html.DateTime("DoB", "Date of birth", Model.DoB);
The effect is the same as in a custom view except that you need to explicitly call this method. This approach is useful if you need to add some additional code in the method such as choosing different templates depending on a condition, checking in the database should this element be shown, etc.
If you need to choose between a custom view template and an Extension Method, the choice is simple. If you have a lot of C# code that should generate output, use an Extension Method; otherwise, if you have a lot of HTML code and just a few places where you place data, use custom views.
Helper Methods
Another way to organize your code in a View
is to create inline helper methods. Inline helper methods are plain functions that are defined directly in the View
and can be called as any standard function. An example of a helper function is shown in the following listing:
@helper DateTime(string name, string label, DateTime val){
@String.Format(@"<label for='{0}'>{1}</label>
<input type='text' name='{0}' id='{0}' value='{2}' class='calendar'/>",
name,
label,
val.ToShortDateString())
}
Once you create the helper function, you can use it in the view as any function. An example is shown in the following listing:
@DateTime("DoB", "DoB", Model.DoB);
Helper functions are good when you want to refactor some code that repeats in the View; however, if you will use it on several View
s, I believe that it is better to use some HTML extension helper method or a custom view. You can see more details about the helper methods in ScottGu's post.
Conclusion
In this article, I have shown you the basics of ASP.NET MVC3 with Razor syntax. Following these instructions and using the attached code, you will be able to create a simple MVC web application and extend it.
Note that MVC is much more - you can find a lot of additional functionalities and customizations such as integration with Entity Framework, using areas, defining custom routing, applying filters, etc. You might take a look at the ASP.NET MVC site for more details about these features. Also, here I have used Razor syntax for Views, however you might want to explore other alternative View syntaxes such as standard ASP.NET, Spark, or NHaml. There are a lot of possibilities you can explore and I hope that this will be a good starting point for you.
History
- 13th March, 2012: Initial version
Graduated from Faculty of Electrical Engineering, Department of Computer Techniques and Informatics, University of Belgrade, Serbia.
Currently working in Microsoft as Program Manager on SQL Server product.
Member of JQuery community - created few popular plugins (four popular JQuery DataTables add-ins and loadJSON template engine).
Interests: Web and databases, Software engineering process(estimation and standardization), mobile and business intelligence platforms.